// $Id: imageitem.cpp,v 1.4 2008/03/06 21:18:58 hvengel Exp $
//  
//  Lttle cms Profiler
//  Copyright (C) 1998-2001 Marti Maria
// Copyright (C) 2005 - 2007 Hal Engel
//
// THIS SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
//
// IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
// OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
// LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
// OF THIS SOFTWARE.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// Version 1.11

#include "lprofmain-priv.h"
#include "lprofmain.h"

#include <qpainter.h>
#include <qmessagebox.h>
#include <qfile.h>
//Added by qt3to4:
#include <QTranslator>
 
// A ICC profile transform on whole image


void ImageItem::TransformImage(const QString OutputProfile,
                               const QString InputProfile,
                               vigra::DRGBImage& p,
                               QImage& pout)
{
    QFile in(InputProfile), out(OutputProfile);
    
    qDebug("ImageItem::TransformImage InputProfile = " + InputProfile.toLocal8Bit());
    
    if (in.exists() && out.exists())
    {
        struct dblColor
        {
            double r, g, b;
        };
    
        struct uint8Color
        {
            char r, g, b;
        };
    
        dblColor *RGB;
        uint8Color *rgb;
        double divisor;
    
        RGB = (dblColor*) malloc(sizeof(dblColor));
        rgb = (uint8Color*) malloc(sizeof(uint8Color));
        // qDebug("ImageItem::TransformImage");
        cmsHTRANSFORM xform;
        cmsHPROFILE hIn, hOut;
        qDebug("about to call lcms");
        hIn  = cmsOpenProfileFromFile(InputProfile.local8Bit(), "r");
        hOut = cmsOpenProfileFromFile(OutputProfile.local8Bit(), "r");
        qDebug("back from lcms");
    
        xform = cmsCreateTransform(hIn, TYPE_RGB_DBL, hOut, TYPE_RGB_8,
                            /*INTENT_PERCEPTUAL*/ intent, cmsFLAGS_WHITEBLACKCOMPENSATION);
    
        vigra::DRGBImage::Iterator point=p.upperLeft();
    
        if (uint8lprof) divisor = 255.0;
        else if (int16lprof) divisor = 65536.0;
        else if (int32lprof) divisor = 4294967296.0;
    
        for (int i=0; i < p.height(); i++)
            for (int j=0; j < p.width(); j++)
        {
            if (uint8lprof | int16lprof | int32lprof)
            {
                    // scale RGB values to max = 1.0
                    // since this is what is expected for
                    // floating point images
                RGB->r = point(j, i).red()/divisor;
                RGB->g = point(j, i).green()/divisor;
                RGB->b = point(j, i).blue()/divisor;
            }
            else // Floating point image
                    // no rescaling of RGB values needed
            {
                RGB->r = point(j, i).red();
                RGB->g = point(j, i).green();
                RGB->b = point(j, i).blue();
            }
            cmsDoTransform(xform, RGB, rgb, 1);
            pout.setPixel(j,i, qRgba ( rgb->r, rgb->g, rgb->b, 0xff));
        }
    
        cmsDeleteTransform(xform);
        cmsCloseProfile(hIn);
        cmsCloseProfile(hOut);
        free(RGB);
    free(rgb);
    }
}



ImageItem::ImageItem(QString ImageFile, const QString Monitor, const QString Scanner, Q3Canvas *canvas )
    : Q3CanvasRectangle( canvas ), image()
{

    // qDebug("ImageItem::ImageItem");
    lProof = FALSE;
    Reload(ImageFile, Monitor, Scanner, canvas);
}


void ImageItem::Reload(QString ImageFile, const QString Monitor, const QString Scanner, Q3Canvas *canvas )
{

     // qDebug("ImageItem::Reload");

    char file[256];
    uint  rvi = 0;
    uint  gvi = 0;
    uint  bvi = 0;
    double r, g, b;

    if (ImageFile == QString::null) return;  // make sure there is a file name
    if (!QFile::exists(ImageFile)) return;
    strcpy(file,  ImageFile.local8Bit());

    // check to see if the file name point to a valid image file
    if (!vigra::isImage(file))
    {
        QMessageBox mb( QTranslator::tr("Load image failure"),
                        QTranslator::tr("This image format is unsupported by LPROF on your system. Sorry. Supported ones are BMP, GIF, JPEG, PNG, PBM, PGM, PNM, PPM, SUN, TIFF and VIFF."),
                                QMessageBox::Critical,
                                QMessageBox::Ok | QMessageBox::Default,
                                Qt::NoButton,  Qt::NoButton);

        mb.exec();
        return;
    }
    
    image_data = new vigra::ImageImportInfo(file);

     // make sure it is a color image
    if (!(image_data->isColor()))
    {
        QMessageBox mb( QTranslator::tr("Load image failure"),
                        QTranslator::tr("This image is not a color RGB image.  Only color images are supported at this time."),
                                QMessageBox::Critical,
                                QMessageBox::Ok | QMessageBox::Default,
                                Qt::NoButton,  Qt::NoButton);

        mb.exec();
        return;
    }

    image_file_name = ImageFile;
    QString pixtype = QString::fromLocal8Bit(image_data->getPixelType());
    int16lprof = (pixtype.contains(QString::fromLocal8Bit("INT16")) > 0);
    int32lprof = (pixtype.contains(QString::fromLocal8Bit("INT32")) > 0);
    uint8lprof = (pixtype.contains(QString::fromLocal8Bit("UINT8")) > 0);
    fltpixlprof = (pixtype.contains(QString::fromLocal8Bit("FLOAT")) > 0);
    dblpixlprof = (pixtype.contains(QString::fromLocal8Bit("DOUBLE")) > 0);

    // try again
    vigra::DRGBImage in(image_data->width(), image_data->height());
    vigra::importImage(*image_data, destImage(in)); // windows blow up here?
    vigra::DRGBImage::Iterator point=in.upperLeft();

    if (! image.create (image_data->width(),
          image_data->height(), 32, 0,
                             QImage::IgnoreEndian))
        qDebug( "image create failed");  // should never happen

    for (int i=0; i < image_data->height(); i++)
        for (int j=0; j < image_data->width(); j++)
    {
        r = point(j, i).red();
        g = point(j, i).green();
        b = point(j, i).blue();

        if (uint8lprof)
        {
            rvi=(uint)r;
            gvi=(uint)g;
            bvi=(uint)b;
        }
        else if (int16lprof)
        {
                    // This code is a work around for a bug in VIGRA
            if (r < 0.0)
            {
                r = r + 65536.0;
                point(j, i).setRed(r);
            }
            if (g < 0.0)
            {
                g = g + 65536.0;
                point(j, i).setGreen(g);
            }
            if (b < 0.0)
            {
                b = b + 65536.0;
                point(j, i).setBlue(b);
            }

                    // Normalize to 8 bits/channel for display
            rvi=(uint)(r/257.0);
            gvi=(uint)(g/257.0);
            bvi=(uint)(b/257.0);
        }
        else if (int32lprof)
        {
                    // This code is a work around for a bug in VIGRA
            if ( r < 0.0)
            {
                r = r + 4294967296.0;
                point(j, i).setRed(r);
            }
            if (g < 0.0)
            {
                g = g + 4294967296.0;
                point(j, i).setGreen(g);
            }
            if (b < 0.0)
            {
                b = b + 4294967296.0;
                point(j, i).setBlue(b);
            }
                    // Normalize to 8 bits/channel for display
            rvi=(uint)(r/16843009.0);
            gvi=(uint)(g/16843009.0);
            bvi=(uint)(b/16843009.0);
        }
        else if (fltpixlprof || dblpixlprof )
        {   // float or double encoding
                    // this may be wrong fix me
                    // normalize the range
                    // max of 255
            rvi = (uint) (r * 255.0);
            gvi = (uint) (g * 255.0);
            bvi = (uint) (b * 255.0);
        }

        image.setPixel(j,i, qRgba ( rvi, gvi, bvi, 0xff));
    }


    QImage scaled = image.smoothScale(canvas->width(), canvas->height());

    setSize( scaled.width(), scaled.height() );

    sx = (double) image.width() / scaled.width();
    sy = (double) image.height() / scaled.height();

    pixmap.convertFromImage(scaled);

    if (lProof)
    {
        if (Monitor != QString::null && Scanner != QString::null)
        {
            QFile scn(Scanner);
            QFile mon(Monitor);
            if (scn.exists() && mon.exists())
            {
               TransformImage(Monitor, Scanner,  in, image);
            }
        }
    }
    

    QImage pscaled = image.smoothScale(canvas->width(), canvas->height());
    proof.convertFromImage(pscaled);

    move(0, 0);
    setZ(5);
    show();
    // qDebug("ImageItem::Reload Done");
}


void ImageItem::drawShape( QPainter &p )
{
    // qDebug("ImageItem::drawShape");
    p.drawPixmap( int(x()), int(y()), lProof? proof : pixmap );
}

