diff options
Diffstat (limited to 'src/utilities/imageeditor/canvas/dimginterface.cpp')
| -rw-r--r-- | src/utilities/imageeditor/canvas/dimginterface.cpp | 1270 | 
1 files changed, 1270 insertions, 0 deletions
| diff --git a/src/utilities/imageeditor/canvas/dimginterface.cpp b/src/utilities/imageeditor/canvas/dimginterface.cpp new file mode 100644 index 00000000..8ce1c114 --- /dev/null +++ b/src/utilities/imageeditor/canvas/dimginterface.cpp @@ -0,0 +1,1270 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date        : 2003-01-15 + * Description : DImg interface for image editor + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2004-2009 by Gilles Caulier <caulier dot gilles at gmail dot com>  + * + * 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 2, 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. + * + * ============================================================ */ + +#define OPACITY  0.7 +#define RCOL     0xAA +#define GCOL     0xAA +#define BCOL     0xAA + +// C++ includes. + +#include <cmath> +#include <cstdio> +#include <cstdlib> +#include <iostream> + +// TQt includes. + +#include <tqwidget.h> +#include <tqimage.h> +#include <tqpixmap.h> +#include <tqbitmap.h> +#include <tqcolor.h> +#include <tqfile.h> +#include <tqvariant.h> + +// KDE includes. + +#include <kcursor.h> +#include <tdemessagebox.h> + +// Local includes. + +#include "ddebug.h" +#include "bcgmodifier.h" +#include "colorcorrectiondlg.h" +#include "undomanager.h" +#include "undoaction.h" +#include "iccsettingscontainer.h" +#include "icctransform.h" +#include "exposurecontainer.h" +#include "iofilesettingscontainer.h" +#include "rawimport.h" +#include "editortooliface.h" +#include "sharedloadsavethread.h" +#include "dmetadata.h" +#include "dimginterface.h" +#include "dimginterface.moc" + +namespace Digikam +{ + +class UndoManager; + +class DImgInterfacePrivate +{ + +public: + +    DImgInterfacePrivate() +    { +        parent           = 0; +        undoMan          = 0; +        cmSettings       = 0; +        expoSettings     = 0; +        iofileSettings   = 0; +        thread           = 0; +        width            = 0; +        height           = 0; +        origWidth        = 0; +        origHeight       = 0; +        selX             = 0; +        selY             = 0; +        selW             = 0; +        selH             = 0; +        zoom             = 1.0; +        exifOrient       = false; +        valid            = false; +        rotatedOrFlipped = false; +    } + +    bool                       valid; +    bool                       rotatedOrFlipped; +    bool                       exifOrient; +    bool                       changedBCG; + +    int                        width; +    int                        height; +    int                        origWidth; +    int                        origHeight; +    int                        selX; +    int                        selY; +    int                        selW; +    int                        selH; + +    float                      gamma; +    float                      brightness; +    float                      contrast; + +    double                     zoom; + +    // Used by ICC color profile dialog. +    TQWidget                   *parent; + +    TQString                    filename; +    TQString                    savingFilename; + +    DImg                       image; + +    UndoManager               *undoMan; + +    BCGModifier                cmod; + +    ICCSettingsContainer      *cmSettings; + +    ExposureSettingsContainer *expoSettings; + +    IOFileSettingsContainer   *iofileSettings; + +    SharedLoadSaveThread      *thread; + +    IccTransform               monitorICCtrans; +}; + +DImgInterface* DImgInterface::m_defaultInterface = 0; + +DImgInterface* DImgInterface::defaultInterface() +{ +    return m_defaultInterface; +} + +void DImgInterface::setDefaultInterface(DImgInterface *defaultInterface) +{ +    m_defaultInterface = defaultInterface; +} + +DImgInterface::DImgInterface() +             : TQObject() +{ +    d = new DImgInterfacePrivate; + +    d->undoMan = new UndoManager(this); +    d->thread  = new SharedLoadSaveThread; + +    connect( d->thread, TQ_SIGNAL(signalImageLoaded(const LoadingDescription &, const DImg&)), +             this, TQ_SLOT(slotImageLoaded(const LoadingDescription &, const DImg&)) ); + +    connect( d->thread, TQ_SIGNAL(signalImageSaved(const TQString&, bool)), +             this, TQ_SLOT(slotImageSaved(const TQString&, bool)) ); + +    connect( d->thread, TQ_SIGNAL(signalLoadingProgress(const LoadingDescription &, float)), +             this, TQ_SLOT(slotLoadingProgress(const LoadingDescription &, float)) ); + +    connect( d->thread, TQ_SIGNAL(signalSavingProgress(const TQString&, float)), +             this, TQ_SLOT(slotSavingProgress(const TQString&, float)) ); +} + +DImgInterface::~DImgInterface() +{ +    delete d->undoMan; +    delete d->thread; +    delete d; +    if (m_defaultInterface == this) +        m_defaultInterface = 0; +} + +void DImgInterface::load(const TQString& filename, IOFileSettingsContainer *iofileSettings, +                         TQWidget *parent) +{ +    // store here in case filename == d->fileName, and is then reset by resetValues +    TQString newFileName = filename; + +    resetValues(); + +    d->filename       = newFileName; +    d->iofileSettings = iofileSettings; +    d->parent         = parent; + +    if (d->iofileSettings->useRAWImport && DImg::fileFormat(d->filename) == DImg::RAW) +    { +        RawImport *rawImport = new RawImport(KURL(d->filename), this); +        EditorToolIface::editorToolIface()->loadTool(rawImport); + +        connect(rawImport, TQ_SIGNAL(okClicked()), +                this, TQ_SLOT(slotUseRawImportSettings())); + +        connect(rawImport, TQ_SIGNAL(cancelClicked()), +                this, TQ_SLOT(slotUseDefaultSettings())); +    } +    else +    { +        slotUseDefaultSettings(); +    } +} + +void DImgInterface::slotUseRawImportSettings() +{ +    RawImport *rawImport = dynamic_cast<RawImport*>(EditorToolIface::editorToolIface()->currentTool()); + +    d->thread->load(LoadingDescription(d->filename, +                    rawImport->rawDecodingSettings()), +                    SharedLoadSaveThread::AccessModeReadWrite, +                    SharedLoadSaveThread::LoadingPolicyFirstRemovePrevious); +    emit signalLoadingStarted(d->filename); + +    EditorToolIface::editorToolIface()->unLoadTool(); +} + +void DImgInterface::slotUseDefaultSettings() +{ +    d->thread->load(LoadingDescription(d->filename, +                    d->iofileSettings->rawDecodingSettings), +                    SharedLoadSaveThread::AccessModeReadWrite, +                    SharedLoadSaveThread::LoadingPolicyFirstRemovePrevious); +    emit signalLoadingStarted(d->filename); + +    EditorToolIface::editorToolIface()->unLoadTool(); +} + +void DImgInterface::resetImage() +{ +    EditorToolIface::editorToolIface()->unLoadTool(); +    resetValues(); +    d->image.reset(); +} + +void DImgInterface::resetValues() +{ +    d->valid          = false; +    d->filename       = TQString(); +    d->width          = 0; +    d->height         = 0; +    d->origWidth      = 0; +    d->origHeight     = 0; +    d->selX           = 0; +    d->selY           = 0; +    d->selW           = 0; +    d->selH           = 0; +    d->gamma          = 1.0; +    d->contrast       = 1.0; +    d->brightness     = 0.0; +    d->changedBCG     = false; +    d->iofileSettings = 0; +    d->parent         = 0; + +    d->cmod.reset(); +    d->undoMan->clear(); +} + +void DImgInterface::setICCSettings(ICCSettingsContainer *cmSettings) +{ +    d->cmSettings = cmSettings; +    d->monitorICCtrans.setProfiles(d->cmSettings->workspaceSetting, d->cmSettings->monitorSetting); +} + +void DImgInterface::setExposureSettings(ExposureSettingsContainer *expoSettings) +{ +    d->expoSettings = expoSettings; +} + +void DImgInterface::slotImageLoaded(const LoadingDescription &loadingDescription, const DImg& img) +{ +    const TQString &fileName = loadingDescription.filePath; + +    if (fileName != d->filename) +        return; + +    bool valRet = false; +    d->image    = img; + +    if (!d->image.isNull()) +    { +        d->origWidth  = d->image.width(); +        d->origHeight = d->image.height(); +        d->valid      = true; +        d->width      = d->origWidth; +        d->height     = d->origHeight; +        valRet        = true; + +        // Raw files are already rotated properlly by dcraw. Only perform auto-rotation with JPEG/PNG/TIFF file. +        // We don't have a feedback from dcraw about auto-rotated RAW file during decoding. Well set transformed  +        // flag as well. + +        if (d->image.attribute("format").toString() == TQString("RAW")) +            d->rotatedOrFlipped = true; + +        if (d->exifOrient &&  +            (d->image.attribute("format").toString() == TQString("JPEG") || +             d->image.attribute("format").toString() == TQString("PNG")  || +             d->image.attribute("format").toString() == TQString("TIFF"))) +            exifRotate(d->filename); + +        if (d->cmSettings->enableCMSetting) +        { +            if (TQFile::exists(d->cmSettings->workspaceSetting)) +            { +                IccTransform trans; +                TQByteArray fakeProfile; + +                // First possibility: image has no embedded profile +                if(d->image.getICCProfil().isNull()) +                { +                    // Ask or apply? +                    if (d->cmSettings->askOrApplySetting) +                    { +                        if (d->parent) d->parent->setCursor( KCursor::waitCursor() ); +                        trans.setProfiles(TQFile::encodeName(d->cmSettings->inputSetting), +                                          TQFile::encodeName(d->cmSettings->workspaceSetting)); + +                        // NOTE: If Input color profile do not exist, using built-in sRGB intead. +                        trans.apply(d->image, fakeProfile, d->cmSettings->renderingSetting, +                                    d->cmSettings->BPCSetting, false,  +                                    TQFile::exists(d->cmSettings->inputSetting));  + +                        d->image.getICCProfilFromFile(TQFile::encodeName(d->cmSettings->workspaceSetting)); +                        if (d->parent) d->parent->unsetCursor(); +                    } +                    else +                    { +                        // To repaint image in canvas before to ask about to apply ICC profile. +                        emit signalImageLoaded(d->filename, valRet); + +                        DImg preview = d->image.smoothScale(240, 180, TQSize::ScaleMin); +                        trans.setProfiles(TQFile::encodeName(d->cmSettings->inputSetting), +                                          TQFile::encodeName(d->cmSettings->workspaceSetting)); +                        ColorCorrectionDlg dlg(d->parent, &preview, &trans, fileName); + +                        switch (dlg.exec()) +                        { +                            case TQDialog::Accepted: +                                if (d->parent) d->parent->setCursor( KCursor::waitCursor() ); + +                                // NOTE: If Input color profile do not exist, using built-in sRGB intead. +                                trans.apply(d->image, fakeProfile, d->cmSettings->renderingSetting, +                                            d->cmSettings->BPCSetting, false,  +                                            TQFile::exists(d->cmSettings->inputSetting));  + +                                d->image.getICCProfilFromFile(TQFile::encodeName(d->cmSettings->workspaceSetting)); +                                if (d->parent) d->parent->unsetCursor(); +                            break; +                            case -1: +                                if (d->parent) d->parent->setCursor( KCursor::waitCursor() ); +                                d->image.getICCProfilFromFile(TQFile::encodeName(d->cmSettings->workspaceSetting)); +                                if (d->parent) d->parent->unsetCursor(); +                                DDebug() << "dimginterface.cpp: Apply pressed" << endl; +                            break; +                        } +                    } +                } +                // Second possibility: image has an embedded profile +                else +                { +                    trans.getEmbeddedProfile( d->image ); + +                    // Ask or apply? +                    if (d->cmSettings->askOrApplySetting) +                    { +                        if (d->parent) d->parent->setCursor( KCursor::waitCursor() ); +                        trans.setProfiles(TQFile::encodeName(d->cmSettings->workspaceSetting)); +                        trans.apply(d->image, fakeProfile, d->cmSettings->renderingSetting, +                                    d->cmSettings->BPCSetting, false, false);  +                        if (d->parent) d->parent->unsetCursor(); +                    } +                    else +                    { +                        if (trans.getEmbeddedProfileDescriptor() +                            != trans.getProfileDescription( d->cmSettings->workspaceSetting )) +                        { +                            // Embedded profile and default workspace profile are different: ask to user! + +                            DDebug() << "Embedded profile: " << trans.getEmbeddedProfileDescriptor() << endl; + +                            // To repaint image in canvas before to ask about to apply ICC profile. +                            emit signalImageLoaded(d->filename, valRet); + +                            DImg preview = d->image.smoothScale(240, 180, TQSize::ScaleMin); +                            trans.setProfiles(TQFile::encodeName(d->cmSettings->workspaceSetting)); +                            ColorCorrectionDlg dlg(d->parent, &preview, &trans, fileName); + +                            switch (dlg.exec()) +                            { +                                case TQDialog::Accepted: +                                    if (d->parent) d->parent->setCursor( KCursor::waitCursor() ); +                                    trans.apply(d->image, fakeProfile, d->cmSettings->renderingSetting, +                                                d->cmSettings->BPCSetting, false, false);  +                                    d->image.getICCProfilFromFile(TQFile::encodeName(d->cmSettings->workspaceSetting)); +                                    if (d->parent) d->parent->unsetCursor(); +                                break; +                                case -1: +                                    if (d->parent) d->parent->setCursor( KCursor::waitCursor() ); +                                    d->image.getICCProfilFromFile(TQFile::encodeName(d->cmSettings->workspaceSetting)); +                                    if (d->parent) d->parent->unsetCursor(); +                                    DDebug() << "dimginterface.cpp: Apply pressed" << endl; +                                break; +                            } +                        } +                    } +                } +            } +            else +            { +                TQString message = i18n("Cannot find the ICC color-space profile file. " +                                       "The ICC profiles path seems to be invalid. " +                                       "No color transform will be applied. " +                                       "Please check the \"Color Management\" " +                                       "configuration in digiKam's setup to verify the ICC path."); +                KMessageBox::information(d->parent, message); +            } +        } +    } +    else +    { +        valRet = false; +    } + +    emit signalImageLoaded(d->filename, valRet); +    setModified(); +} + +void DImgInterface::slotLoadingProgress(const LoadingDescription &loadingDescription, float progress) +{ +    if (loadingDescription.filePath == d->filename) +        emit signalLoadingProgress(loadingDescription.filePath, progress); +} + +bool DImgInterface::exifRotated() +{ +    return d->rotatedOrFlipped; +} + +void DImgInterface::exifRotate(const TQString& filename) +{ +    // Rotate image based on EXIF rotate tag + +    DMetadata metadata(filename); +    DMetadata::ImageOrientation orientation = metadata.getImageOrientation(); + +    if(orientation != DMetadata::ORIENTATION_NORMAL)  +    { +        switch (orientation)  +        { +            case DMetadata::ORIENTATION_NORMAL: +            case DMetadata::ORIENTATION_UNSPECIFIED: +                break; + +            case DMetadata::ORIENTATION_HFLIP: +                flipHoriz(false); +                break; + +            case DMetadata::ORIENTATION_ROT_180: +                rotate180(false); +                break; + +            case DMetadata::ORIENTATION_VFLIP: +                flipVert(false); +                break; + +            case DMetadata::ORIENTATION_ROT_90_HFLIP: +                rotate90(false); +                flipHoriz(false); +                break; + +            case DMetadata::ORIENTATION_ROT_90: +                rotate90(false); +                break; + +            case DMetadata::ORIENTATION_ROT_90_VFLIP: +                rotate90(false); +                flipVert(false); +                break; + +            case DMetadata::ORIENTATION_ROT_270: +                rotate270(false); +                break; +        } + +        d->rotatedOrFlipped = true; +    } +} + +void DImgInterface::setExifOrient(bool exifOrient) +{ +    d->exifOrient = exifOrient; +} + +void DImgInterface::undo() +{ +    if (!d->undoMan->anyMoreUndo()) +    { +        emit signalUndoStateChanged(false, d->undoMan->anyMoreRedo(), !d->undoMan->isAtOrigin()); +        return; +    } + +    d->undoMan->undo(); +    emit signalUndoStateChanged(d->undoMan->anyMoreUndo(), d->undoMan->anyMoreRedo(), !d->undoMan->isAtOrigin()); +} + +void DImgInterface::redo() +{ +    if (!d->undoMan->anyMoreRedo()) +    { +        emit signalUndoStateChanged(d->undoMan->anyMoreUndo(), false, !d->undoMan->isAtOrigin()); +        return; +    } + +    d->undoMan->redo(); +    emit signalUndoStateChanged(d->undoMan->anyMoreUndo(), d->undoMan->anyMoreRedo(), !d->undoMan->isAtOrigin()); +} + +void DImgInterface::restore() +{ +    d->undoMan->clear(); +    load(d->filename, d->iofileSettings); +} + +/* +This code is unused and untested +void DImgInterface::save(const TQString& file, IOFileSettingsContainer *iofileSettings) +{ +    d->cmod.reset(); +    d->cmod.setGamma(d->gamma); +    d->cmod.setBrightness(d->brightness); +    d->cmod.setContrast(d->contrast); +    d->cmod.applyBCG(d->image); + +    d->cmod.reset(); +    d->gamma      = 1.0; +    d->contrast   = 1.0; +    d->brightness = 0.0; + +    TQString currentMimeType(TQImageIO::imageFormat(d->filename)); + +    d->needClearUndoManager = true; + +    saveAction(file, iofileSettings, currentMimeType); +} +*/ + +void DImgInterface::saveAs(const TQString& fileName, IOFileSettingsContainer *iofileSettings, +                           bool setExifOrientationTag, const TQString& givenMimeType) +{ +    // No need to toggle off undo, redo or save action during saving using  +    // signalUndoStateChanged(), this is will done by GUI implementation directly. + +    if (d->changedBCG) +    { +        d->cmod.reset(); +        d->cmod.setGamma(d->gamma); +        d->cmod.setBrightness(d->brightness); +        d->cmod.setContrast(d->contrast); +        d->cmod.applyBCG(d->image); +    } + +    // Try hard to find a mimetype. +    TQString mimeType = givenMimeType; + +    // This is possibly empty +    if (mimeType.isEmpty()) +        mimeType = getImageFormat(); + +    DDebug() << "Saving to :" << TQFile::encodeName(fileName).data() << " ("  +             << mimeType << ")" << endl; + +    // JPEG file format. +    if ( mimeType.upper() == TQString("JPG") || mimeType.upper() == TQString("JPEG") ||  +         mimeType.upper() == TQString("JPE")) +    { +       d->image.setAttribute("quality",     iofileSettings->JPEGCompression); +       d->image.setAttribute("subsampling", iofileSettings->JPEGSubSampling); +    } + +    // PNG file format. +    if ( mimeType.upper() == TQString("PNG") )  +       d->image.setAttribute("quality", iofileSettings->PNGCompression); + +    // TIFF file format. +    if ( mimeType.upper() == TQString("TIFF") || mimeType.upper() == TQString("TIF") )  +       d->image.setAttribute("compress", iofileSettings->TIFFCompression); + +    // JPEG 2000 file format. +    if ( mimeType.upper() == TQString("JP2") || mimeType.upper() == TQString("JPX") ||  +         mimeType.upper() == TQString("JPC") || mimeType.upper() == TQString("PGX")) +    {  +        if (iofileSettings->JPEG2000LossLess) +            d->image.setAttribute("quality", 100);    // LossLess compression +        else +            d->image.setAttribute("quality", iofileSettings->JPEG2000Compression); +    } + +    d->savingFilename = fileName; + +    // Get image Exif/Iptc data. +    DMetadata meta; +    meta.setExif(d->image.getExif()); +    meta.setIptc(d->image.getIptc()); + +    // Update Iptc preview. +    // NOTE: see B.K.O #130525. a JPEG segment is limited to 64K. If the IPTC byte array is +    // bigger than 64K duing of image preview tag size, the target JPEG image will be +    // broken. Note that IPTC image preview tag is limited to 256K!!! +    // There is no limitation with TIFF and PNG about IPTC byte array size. + +    TQImage preview = d->image.smoothScale(1280, 1024, TQSize::ScaleMin).copyTQImage(); + +    if ( mimeType.upper() != TQString("JPG") && mimeType.upper() != TQString("JPEG") && +         mimeType.upper() != TQString("JPE")) +    { +        // Non JPEG file, we update IPTC preview +        meta.setImagePreview(preview); +    } +    else +    { +        // JPEG file, we remove IPTC preview. +        meta.removeIptcTag("Iptc.Application2.Preview"); +        meta.removeIptcTag("Iptc.Application2.PreviewFormat"); +        meta.removeIptcTag("Iptc.Application2.PreviewVersion"); +    } + +    // Update Exif thumbnail. +    TQImage thumb = preview.smoothScale(160, 120, TQImage::ScaleMin); +    meta.setExifThumbnail(thumb); + +    // Update Exif Image dimensions. +    meta.setImageDimensions(d->image.size()); + +    // Update Exif Document Name tag with the original file name. +    meta.setExifTagString("Exif.Image.DocumentName", getImageFileName()); + +    // Update Exif Orientation tag if necessary. +    if( setExifOrientationTag ) +        meta.setImageOrientation(DMetadata::ORIENTATION_NORMAL); + +    // Store new Exif/Iptc data into image. +    d->image.setExif(meta.getExif()); +    d->image.setIptc(meta.getIptc()); + +    d->thread->save(d->image, fileName, mimeType); +} + +void DImgInterface::slotImageSaved(const TQString& filePath, bool success) +{ +    if (filePath != d->savingFilename) +        return; + +    if (!success) +        DWarning() << "error saving image '" << TQFile::encodeName(filePath).data() << endl; + +    emit signalImageSaved(filePath, success); +    emit signalUndoStateChanged(d->undoMan->anyMoreUndo(), d->undoMan->anyMoreRedo(), !d->undoMan->isAtOrigin()); +} + +void DImgInterface::slotSavingProgress(const TQString& filePath, float progress) +{ +    if (filePath == d->savingFilename) +        emit signalSavingProgress(filePath, progress); +} + +void DImgInterface::abortSaving() +{ +    // failure will be reported by a signal +    d->thread->stopSaving(d->savingFilename); +} + +void DImgInterface::switchToLastSaved(const TQString& newFilename) +{ +    // Higher level wants to use the current DImg object to represent the file +    // it has previously been saved to. +    d->filename = newFilename; + +    // Currently the only place where a DImg is connected to the file it originates from +    // is the format attribute. +    TQString savedformat = d->image.attribute("savedformat").toString(); +    if (!savedformat.isEmpty()) +        d->image.setAttribute("format", savedformat); +} + +void DImgInterface::setModified() +{ +    emit signalModified(); +    emit signalUndoStateChanged(d->undoMan->anyMoreUndo(), d->undoMan->anyMoreRedo(), !d->undoMan->isAtOrigin()); +} + +void DImgInterface::readMetadataFromFile(const TQString &file) +{ +    DMetadata meta(file); + +    //TODO: code is essentially the same as DImgLoader::readMetadata, +    //      put both in a common place. +    if (!meta.getComments().isNull()) +        d->image.setComments(meta.getComments()); +    if (!meta.getExif().isNull()) +        d->image.setExif(meta.getExif()); +    if (!meta.getIptc().isNull()) +        d->image.setIptc(meta.getIptc()); +} + +void DImgInterface::clearUndoManager() +{ +    d->undoMan->clear(); +    d->undoMan->setOrigin(); +    emit signalUndoStateChanged(false, false, false); +} + +void DImgInterface::setUndoManagerOrigin() +{ +    d->undoMan->setOrigin(); +    emit signalUndoStateChanged(d->undoMan->anyMoreUndo(), d->undoMan->anyMoreRedo(), !d->undoMan->isAtOrigin()); +} + +void DImgInterface::updateUndoState() +{ +    emit signalUndoStateChanged(d->undoMan->anyMoreUndo(), d->undoMan->anyMoreRedo(), !d->undoMan->isAtOrigin()); +} + +bool DImgInterface::imageValid() +{ +    return !d->image.isNull(); +} + +int DImgInterface::width() +{ +    return d->width; +} + +int DImgInterface::height() +{ +    return d->height; +} + +int DImgInterface::origWidth() +{ +    return d->origWidth; +} + +int DImgInterface::origHeight() +{ +    return d->origHeight; +} + +int DImgInterface::bytesDepth() +{ +    return d->image.bytesDepth(); +} + +bool DImgInterface::sixteenBit() +{ +    return d->image.sixteenBit(); +} + +bool DImgInterface::hasAlpha() +{ +    return d->image.hasAlpha(); +} + +bool DImgInterface::isReadOnly() +{ +    if (d->image.isNull()) +        return true; +    else +        return d->image.isReadOnly(); +} + +void DImgInterface::setSelectedArea(int x, int y, int w, int h) +{ +    d->selX = x; +    d->selY = y; +    d->selW = w; +    d->selH = h; +} + +void DImgInterface::getSelectedArea(int& x, int& y, int& w, int& h) +{ +    x = d->selX; +    y = d->selY; +    w = d->selW; +    h = d->selH; +} + +void DImgInterface::paintOnDevice(TQPaintDevice* p, +                                  int sx, int sy, int sw, int sh, +                                  int dx, int dy, int dw, int dh, +                                  int /*antialias*/) +{ +    if (d->image.isNull()) +        return; + +    DImg img = d->image.smoothScaleSection(sx, sy, sw, sh, dw, dh); +    d->cmod.applyBCG(img); +    img.convertDepth(32); + +    if (d->cmSettings->enableCMSetting && d->cmSettings->managedViewSetting) +    { +        TQPixmap pix(img.convertToPixmap(&d->monitorICCtrans)); +        bitBlt(p, dx, dy, &pix, 0, 0); +    } +    else +    { +        TQPixmap pix(img.convertToPixmap()); +        bitBlt(p, dx, dy, &pix, 0, 0); +    } + +    // Show the Over/Under exposure pixels indicators  + +    if (d->expoSettings->underExposureIndicator || d->expoSettings->overExposureIndicator) +    { +        TQImage pureColorMask = d->image.copy(sx, sy, sw, sh).pureColorMask(d->expoSettings); +        TQPixmap pixMask(pureColorMask.scale(dw, dh));  +        bitBlt(p, dx, dy, &pixMask, 0, 0); +    } +} + +void DImgInterface::paintOnDevice(TQPaintDevice* p, +                                  int sx, int sy, int sw, int sh, +                                  int dx, int dy, int dw, int dh, +                                  int mx, int my, int mw, int mh, +                                  int /*antialias*/) +{ +    if (d->image.isNull()) +        return; + +    DImg img = d->image.smoothScaleSection(sx, sy, sw, sh, dw, dh); +    d->cmod.applyBCG(img); +    img.convertDepth(32); + +    uint* data  = (uint*)img.bits(); +    uchar r, g, b, a; + +    for (int j=0; j < (int)img.height(); j++) +    { +        for (int i=0; i < (int)img.width(); i++) +        { +            if (i < (mx-dx) || i > (mx-dx+mw-1) || +                j < (my-dy) || j > (my-dy+mh-1)) +            { +                a = (*data >> 24) & 0xff; +                r = (*data >> 16) & 0xff; +                g = (*data >>  8) & 0xff; +                b = (*data      ) & 0xff; + +                r += (uchar)((RCOL - r) * OPACITY); +                g += (uchar)((GCOL - g) * OPACITY); +                b += (uchar)((BCOL - b) * OPACITY); + +                *data = (a << 24) | (r << 16) | (g << 8) | b; +            } + +            data++; +        } +    } + +    if (d->cmSettings->enableCMSetting && d->cmSettings->managedViewSetting) +    { +        TQPixmap pix(img.convertToPixmap(&d->monitorICCtrans)); +        bitBlt(p, dx, dy, &pix, 0, 0); +    } +    else +    { +        TQPixmap pix(img.convertToPixmap()); +        bitBlt(p, dx, dy, &pix, 0, 0); +    } + +    // Show the Over/Under exposure pixels indicators  + +    if (d->expoSettings->underExposureIndicator || d->expoSettings->overExposureIndicator) +    { +        TQImage pureColorMask = d->image.copy(sx, sy, sw, sh).pureColorMask(d->expoSettings); +        TQPixmap pixMask(pureColorMask.scale(dw, dh));  +        bitBlt(p, dx, dy, &pixMask, 0, 0); +    } +} + +void DImgInterface::zoom(double val) +{ +    d->zoom   = val; +    d->width  = (int)(d->origWidth  * val); +    d->height = (int)(d->origHeight * val); +} + +void DImgInterface::rotate90(bool saveUndo) +{ +    if (saveUndo) +    { +        d->undoMan->addAction(new UndoActionRotate(this, UndoActionRotate::R90)); +    } + +    d->image.rotate(DImg::ROT90); +    d->origWidth  = d->image.width(); +    d->origHeight = d->image.height(); + +    setModified(); +} + +void DImgInterface::rotate180(bool saveUndo) +{ +    if (saveUndo) +    { +        d->undoMan->addAction(new UndoActionRotate(this, UndoActionRotate::R180)); +    } + +    d->image.rotate(DImg::ROT180); +    d->origWidth  = d->image.width(); +    d->origHeight = d->image.height(); + +    setModified(); +} + +void DImgInterface::rotate270(bool saveUndo) +{ +    if (saveUndo) +    { +        d->undoMan->addAction(new UndoActionRotate(this, UndoActionRotate::R270)); +    } + +    d->image.rotate(DImg::ROT270); +    d->origWidth  = d->image.width(); +    d->origHeight = d->image.height(); + +    setModified(); +} + +void DImgInterface::flipHoriz(bool saveUndo) +{ +    if (saveUndo) +    { +        d->undoMan->addAction(new UndoActionFlip(this, UndoActionFlip::Horizontal)); +    } + +    d->image.flip(DImg::HORIZONTAL); + +    setModified(); +} + +void DImgInterface::flipVert(bool saveUndo) +{ +    if (saveUndo) +    { +        d->undoMan->addAction(new UndoActionFlip(this, UndoActionFlip::Vertical)); +    } + +    d->image.flip(DImg::VERTICAL); + +    setModified(); +} + +void DImgInterface::crop(int x, int y, int w, int h) +{ +    d->undoMan->addAction(new UndoActionIrreversible(this, "Crop")); + +    d->image.crop(x, y, w, h); + +    d->origWidth  = d->image.width(); +    d->origHeight = d->image.height(); + +    setModified(); +} + +void DImgInterface::resize(int w, int h) +{ +    d->undoMan->addAction(new UndoActionIrreversible(this, "Resize")); + +    d->image.resize(w, h); + +    d->origWidth  = d->image.width(); +    d->origHeight = d->image.height(); + +    setModified(); +} + +void DImgInterface::changeGamma(double gamma) +{ +    d->undoMan->addAction(new UndoActionBCG(this, d->gamma, d->brightness, +                                            d->contrast, gamma, d->brightness, +                                            d->contrast)); + +    d->gamma += gamma/10.0; + +    d->cmod.reset(); +    d->cmod.setGamma(d->gamma); +    d->cmod.setBrightness(d->brightness); +    d->cmod.setContrast(d->contrast); +    d->changedBCG = true; + +    setModified(); +} + +void DImgInterface::changeBrightness(double brightness) +{ +    d->undoMan->addAction(new UndoActionBCG(this, d->gamma, d->brightness, +                                            d->contrast, d->gamma, brightness, +                                            d->contrast)); + +    d->brightness += brightness/100.0; + +    d->cmod.reset(); +    d->cmod.setGamma(d->gamma); +    d->cmod.setBrightness(d->brightness); +    d->cmod.setContrast(d->contrast); +    d->changedBCG = true; + +    setModified(); +} + +void DImgInterface::changeContrast(double contrast) +{ +    d->undoMan->addAction(new UndoActionBCG(this, d->gamma, d->brightness, +                                            d->contrast, d->gamma, d->brightness, +                                            contrast)); + +    d->contrast += contrast/100.0; + +    d->cmod.reset(); +    d->cmod.setGamma(d->gamma); +    d->cmod.setBrightness(d->brightness); +    d->cmod.setContrast(d->contrast); +    d->changedBCG = true; + +    setModified(); +} + +void DImgInterface::changeBCG(double gamma, double brightness, double contrast) +{ +    d->gamma      = gamma; +    d->brightness = brightness; +    d->contrast   = contrast; + +    d->cmod.reset(); +    d->cmod.setGamma(d->gamma); +    d->cmod.setBrightness(d->brightness); +    d->cmod.setContrast(d->contrast); +    d->changedBCG = true; + +    setModified(); +} + +void DImgInterface::setBCG(double brightness, double contrast, double gamma) +{ +    d->undoMan->addAction(new UndoActionIrreversible(this, "Brightness, Contrast, Gamma")); + +    d->cmod.reset(); +    d->cmod.setGamma(gamma); +    d->cmod.setBrightness(brightness); +    d->cmod.setContrast(contrast); +    d->cmod.applyBCG(d->image); + +    d->cmod.reset(); +    d->gamma      = 1.0; +    d->contrast   = 1.0; +    d->brightness = 0.0; +    d->changedBCG = false; + +    setModified(); +} + +void DImgInterface::convertDepth(int depth) +{ +    d->undoMan->addAction(new UndoActionIrreversible(this, "Convert Color Depth")); +    d->image.convertDepth(depth); + +    setModified(); +} + +DImg* DImgInterface::getImg() +{ +    if (!d->image.isNull()) +    { +        return &d->image; +    } +    else +    { +        DWarning() << k_funcinfo << "d->image is NULL" << endl; +        return 0; +    } +} + +uchar* DImgInterface::getImage() +{ +    if (!d->image.isNull()) +    { +        return d->image.bits(); +    } +    else +    { +        DWarning() << k_funcinfo << "d->image is NULL" << endl; +        return 0; +    } +} + +void DImgInterface::putImage(const TQString &caller, uchar* data, int w, int h) +{ +    putImage(caller, data, w, h, d->image.sixteenBit()); +} + +void DImgInterface::putImage(const TQString &caller, uchar* data, int w, int h, bool sixteenBit) +{ +    d->undoMan->addAction(new UndoActionIrreversible(this, caller)); +    putImage(data, w, h, sixteenBit); +} + +void DImgInterface::putImage(uchar* data, int w, int h) +{ +    putImage(data, w, h, d->image.sixteenBit()); +} + +void DImgInterface::putImage(uchar* data, int w, int h, bool sixteenBit) +{ +    if (d->image.isNull()) +    { +       DWarning() << k_funcinfo << "d->image is NULL" << endl; +       return; +    } + +    if (!data) +    { +       DWarning() << k_funcinfo << "New image is NULL" << endl; +       return; +    } + +    if (w == -1 && h == -1) +    { +        // New image size +        w = d->origWidth; +        h = d->origHeight; +    } +    else +    { +        // New image size == original size +        d->origWidth  = w; +        d->origHeight = h; +    } + +    //DDebug() << k_funcinfo << data << " " << w << " " << h << endl; +    d->image.putImageData(w, h, sixteenBit, d->image.hasAlpha(), data); + +    setModified(); +} + +void DImgInterface::setEmbeddedICCToOriginalImage( TQString profilePath) +{ +    if (d->image.isNull()) +    { +        DWarning() << k_funcinfo << "d->image is NULL" << endl; +        return; +    } + +     DDebug() << k_funcinfo << "Embedding profile: " << profilePath << endl; +     d->image.getICCProfilFromFile( TQFile::encodeName(profilePath)); +     setModified(); +} + +uchar* DImgInterface::getImageSelection() +{ +    if (!d->selW || !d->selH) +        return 0; + +    if (!d->image.isNull()) +    { +        DImg im = d->image.copy(d->selX, d->selY, d->selW, d->selH); +        return im.stripImageData(); +    } + +    return 0; +} + +void DImgInterface::putImageSelection(const TQString &caller, uchar* data) +{ +    if (!data || d->image.isNull()) +        return; + +    d->undoMan->addAction(new UndoActionIrreversible(this, caller)); + +    d->image.bitBltImage(data, 0, 0, d->selW, d->selH, d->selX, d->selY, d->selW, d->selH, d->image.bytesDepth()); + +    setModified(); +} + +void DImgInterface::getUndoHistory(TQStringList &titles) +{ +    d->undoMan->getUndoHistory(titles); +} + +void DImgInterface::getRedoHistory(TQStringList &titles) +{ +    d->undoMan->getRedoHistory(titles); +} + +TQByteArray DImgInterface::getEmbeddedICC() +{ +    return d->image.getICCProfil(); +} + +TQByteArray DImgInterface::getExif() +{ +    return d->image.getExif(); +} + +TQByteArray DImgInterface::getIptc() +{ +    return d->image.getIptc(); +} + +TQString DImgInterface::getImageFilePath() +{ +    return d->filename; +} + +TQString DImgInterface::getImageFileName() +{ +    return d->filename.section( '/', -1 ); +} + +TQString DImgInterface::getImageFormat() +{ +    if (d->image.isNull()) +        return TQString(); + +    TQString mimeType = d->image.attribute("format").toString(); +    // It is a bug in the loader if format attribute is not given +    if (mimeType.isEmpty()) +    { +        DWarning() << "DImg object does not contain attribute \"format\"" << endl; +        mimeType = TQImageIO::imageFormat(d->filename); +    } +    return mimeType; +} + +ICCSettingsContainer* DImgInterface::getICCSettings() +{ +    return d->cmSettings; +} + +TQPixmap DImgInterface::convertToPixmap(DImg& img) +{ +    if (d->cmSettings->enableCMSetting && d->cmSettings->managedViewSetting) +        return img.convertToPixmap(&d->monitorICCtrans); + +    return img.convertToPixmap(); +} + +TQColor DImgInterface::underExposureColor() +{ +    return d->expoSettings->underExposureColor; +} + +TQColor DImgInterface::overExposureColor() +{ +    return d->expoSettings->overExposureColor; +} + +}  // namespace Digikam + | 
