summaryrefslogtreecommitdiffstats
path: root/src/utilities/imageeditor/canvas
diff options
context:
space:
mode:
authorMichele Calgaro <michele.calgaro@yahoo.it>2024-11-22 18:41:30 +0900
committerMichele Calgaro <michele.calgaro@yahoo.it>2024-11-22 20:55:03 +0900
commit5bed6e4a4c916a97f8fe4d1b07f7eecf4d733b90 (patch)
treef89cc49efc9ca1d0e1579ecb079ee7e7088ff8c8 /src/utilities/imageeditor/canvas
parent0bfbf616d9c1fd7abb1bd02732389ab35e5f8771 (diff)
downloaddigikam-5bed6e4a4c916a97f8fe4d1b07f7eecf4d733b90.tar.gz
digikam-5bed6e4a4c916a97f8fe4d1b07f7eecf4d733b90.zip
Rename 'digikam' folder to 'src'
Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it> (cherry picked from commit ee0d99607c14cb63d3ebdb3a970b508949fa8219)
Diffstat (limited to 'src/utilities/imageeditor/canvas')
-rw-r--r--src/utilities/imageeditor/canvas/Makefile.am28
-rw-r--r--src/utilities/imageeditor/canvas/canvas.cpp1421
-rw-r--r--src/utilities/imageeditor/canvas/canvas.h209
-rw-r--r--src/utilities/imageeditor/canvas/colorcorrectiondlg.cpp186
-rw-r--r--src/utilities/imageeditor/canvas/colorcorrectiondlg.h72
-rw-r--r--src/utilities/imageeditor/canvas/dimginterface.cpp1270
-rw-r--r--src/utilities/imageeditor/canvas/dimginterface.h200
-rw-r--r--src/utilities/imageeditor/canvas/iccsettingscontainer.h82
-rw-r--r--src/utilities/imageeditor/canvas/imageplugin.cpp68
-rw-r--r--src/utilities/imageeditor/canvas/imageplugin.h70
-rw-r--r--src/utilities/imageeditor/canvas/imagepluginloader.cpp278
-rw-r--r--src/utilities/imageeditor/canvas/imagepluginloader.h79
-rw-r--r--src/utilities/imageeditor/canvas/iofilesettingscontainer.h84
-rw-r--r--src/utilities/imageeditor/canvas/undoaction.cpp185
-rw-r--r--src/utilities/imageeditor/canvas/undoaction.h144
-rw-r--r--src/utilities/imageeditor/canvas/undocache.cpp178
-rw-r--r--src/utilities/imageeditor/canvas/undocache.h62
-rw-r--r--src/utilities/imageeditor/canvas/undomanager.cpp253
-rw-r--r--src/utilities/imageeditor/canvas/undomanager.h76
19 files changed, 4945 insertions, 0 deletions
diff --git a/src/utilities/imageeditor/canvas/Makefile.am b/src/utilities/imageeditor/canvas/Makefile.am
new file mode 100644
index 00000000..740f854e
--- /dev/null
+++ b/src/utilities/imageeditor/canvas/Makefile.am
@@ -0,0 +1,28 @@
+METASOURCES = AUTO
+
+noinst_LTLIBRARIES = libdimgcanvas.la
+
+libdimgcanvas_la_SOURCES = dimginterface.cpp colorcorrectiondlg.cpp \
+ canvas.cpp undocache.cpp \
+ undoaction.cpp undomanager.cpp \
+ imagepluginloader.cpp imageplugin.cpp
+
+libdimgcanvas_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_TIFF)
+
+INCLUDES = -I$(top_srcdir)/src/digikam \
+ -I$(top_srcdir)/src/libs/dimg \
+ -I$(top_srcdir)/src/libs/dimg/filters \
+ -I$(top_srcdir)/src/libs/dmetadata \
+ -I$(top_srcdir)/src/libs/dialogs \
+ -I$(top_srcdir)/src/libs/histogram \
+ -I$(top_srcdir)/src/libs/threadimageio \
+ -I$(top_srcdir)/src/utilities/splashscreen \
+ -I$(top_srcdir)/src/utilities/imageeditor/editor \
+ -I$(top_srcdir)/src/utilities/imageeditor/rawimport \
+ -I$(top_srcdir)/src/libs/widgets/imageplugins \
+ -I$(top_srcdir)/src/libs/widgets/common \
+ $(LIBKEXIV2_CFLAGS) $(LIBKDCRAW_CFLAGS) $(all_includes)
+
+digikaminclude_HEADERS = imageplugin.h
+
+digikamincludedir = $(includedir)/digikam
diff --git a/src/utilities/imageeditor/canvas/canvas.cpp b/src/utilities/imageeditor/canvas/canvas.cpp
new file mode 100644
index 00000000..89758c3d
--- /dev/null
+++ b/src/utilities/imageeditor/canvas/canvas.cpp
@@ -0,0 +1,1421 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-01-09
+ * Description : image editor canvas management class
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Copyright (C) 2004-2008 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.
+ *
+ * ============================================================ */
+
+// C++ includes.
+
+#include <cstdio>
+#include <cmath>
+
+// TQt includes.
+
+#include <tqtooltip.h>
+#include <tqfile.h>
+#include <tqstring.h>
+#include <tqevent.h>
+#include <tqpoint.h>
+#include <tqpainter.h>
+#include <tqpen.h>
+#include <tqpixmap.h>
+#include <tqstyle.h>
+#include <tqapplication.h>
+#include <tqcursor.h>
+#include <tqimage.h>
+#include <tqregion.h>
+#include <tqtimer.h>
+#include <tqcache.h>
+#include <tqcolor.h>
+#include <tqdragobject.h>
+#include <tqclipboard.h>
+#include <tqtoolbutton.h>
+
+// KDE includes.
+
+#include <kcursor.h>
+#include <tdelocale.h>
+#include <kiconloader.h>
+#include <kdatetbl.h>
+#include <tdeglobalsettings.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "imagehistogram.h"
+#include "imagepaniconwidget.h"
+#include "dimginterface.h"
+#include "iccsettingscontainer.h"
+#include "exposurecontainer.h"
+#include "iofilesettingscontainer.h"
+#include "loadingcacheinterface.h"
+#include "canvas.h"
+#include "canvas.moc"
+
+namespace Digikam
+{
+
+class CanvasPrivate
+{
+
+public:
+
+ CanvasPrivate() :
+ tileSize(128), minZoom(0.1), maxZoom(12.0), zoomMultiplier(1.2)
+ {
+ rubber = 0;
+ pressedMoved = false;
+ pressedMoving = false;
+ ltActive = false;
+ rtActive = false;
+ lbActive = false;
+ rbActive = false;
+ midButtonPressed = false;
+ midButtonX = 0;
+ midButtonY = 0;
+ panIconPopup = 0;
+ panIconWidget = 0;
+ cornerButton = 0;
+ parent = 0;
+ im = 0;
+ rubber = 0;
+ autoZoom = false;
+ fullScreen = false;
+ zoom = 1.0;
+ tileTmpPix = new TQPixmap(tileSize, tileSize);
+
+ tileCache.setMaxCost((10*1024*1024)/(tileSize*tileSize*4));
+ tileCache.setAutoDelete(true);
+ }
+
+ bool autoZoom;
+ bool fullScreen;
+ bool pressedMoved;
+ bool pressedMoving;
+ bool ltActive;
+ bool rtActive;
+ bool lbActive;
+ bool rbActive;
+ bool midButtonPressed;
+
+ const int tileSize;
+ int midButtonX;
+ int midButtonY;
+
+ double zoom;
+ const double minZoom;
+ const double maxZoom;
+ const double zoomMultiplier;
+
+ TQToolButton *cornerButton;
+
+ TQRect *rubber;
+ TQRect pixmapRect;
+
+ TQCache<TQPixmap> tileCache;
+
+ TQPixmap* tileTmpPix;
+ TQPixmap qcheck;
+
+ TQColor bgColor;
+
+ TQWidget *parent;
+
+ TDEPopupFrame *panIconPopup;
+
+ DImgInterface *im;
+
+ ImagePanIconWidget *panIconWidget;
+};
+
+Canvas::Canvas(TQWidget *parent)
+ : TQScrollView(parent)
+{
+ d = new CanvasPrivate;
+ d->im = new DImgInterface();
+ d->parent = parent;
+ d->bgColor.setRgb(0, 0, 0);
+
+ d->qcheck.resize(16, 16);
+ TQPainter p(&d->qcheck);
+ p.fillRect(0, 0, 8, 8, TQColor(144, 144, 144));
+ p.fillRect(8, 8, 8, 8, TQColor(144, 144, 144));
+ p.fillRect(0, 8, 8, 8, TQColor(100, 100, 100));
+ p.fillRect(8, 0, 8, 8, TQColor(100, 100, 100));
+ p.end();
+
+ d->cornerButton = new TQToolButton(this);
+ d->cornerButton->setIconSet(SmallIcon("move"));
+ d->cornerButton->hide();
+ TQToolTip::add(d->cornerButton, i18n("Pan the image to a region"));
+ setCornerWidget(d->cornerButton);
+
+ viewport()->setBackgroundMode(TQt::NoBackground);
+ viewport()->setMouseTracking(false);
+ setFrameStyle( TQFrame::NoFrame );
+
+ // ------------------------------------------------------------
+
+ connect(this, TQ_SIGNAL(signalZoomChanged(double)),
+ this, TQ_SLOT(slotZoomChanged(double)));
+
+ connect(d->cornerButton, TQ_SIGNAL(pressed()),
+ this, TQ_SLOT(slotCornerButtonPressed()));
+
+ connect(d->im, TQ_SIGNAL(signalModified()),
+ this, TQ_SLOT(slotModified()));
+
+ connect(d->im, TQ_SIGNAL(signalUndoStateChanged(bool, bool, bool)),
+ this, TQ_SIGNAL(signalUndoStateChanged(bool, bool, bool)));
+
+ connect(d->im, TQ_SIGNAL(signalLoadingStarted(const TQString&)),
+ this, TQ_SIGNAL(signalLoadingStarted(const TQString&)));
+
+ connect(d->im, TQ_SIGNAL(signalImageLoaded(const TQString&, bool)),
+ this, TQ_SLOT(slotImageLoaded(const TQString&, bool)));
+
+ connect(d->im, TQ_SIGNAL(signalImageSaved(const TQString&, bool)),
+ this, TQ_SLOT(slotImageSaved(const TQString&, bool)));
+
+ connect(d->im, TQ_SIGNAL(signalLoadingProgress(const TQString&, float)),
+ this, TQ_SIGNAL(signalLoadingProgress(const TQString&, float)));
+
+ connect(d->im, TQ_SIGNAL(signalSavingProgress(const TQString&, float)),
+ this, TQ_SIGNAL(signalSavingProgress(const TQString&, float)));
+
+ connect(this, TQ_SIGNAL(signalSelected(bool)),
+ this, TQ_SLOT(slotSelected()));
+}
+
+Canvas::~Canvas()
+{
+ delete d->tileTmpPix;
+ delete d->im;
+
+ if (d->rubber)
+ delete d->rubber;
+
+ delete d;
+}
+
+void Canvas::resetImage()
+{
+ reset();
+ viewport()->setUpdatesEnabled(false);
+ d->im->resetImage();
+}
+
+void Canvas::reset()
+{
+ if (d->rubber)
+ {
+ delete d->rubber;
+ d->rubber = 0;
+ if (d->im->imageValid())
+ emit signalSelected(false);
+ }
+
+ d->tileCache.clear();
+}
+
+void Canvas::load(const TQString& filename, IOFileSettingsContainer *IOFileSettings)
+{
+ reset();
+
+ viewport()->setUpdatesEnabled(false);
+
+ d->im->load( filename, IOFileSettings, d->parent );
+
+ emit signalPrepareToLoad();
+}
+
+void Canvas::slotImageLoaded(const TQString& filePath, bool success)
+{
+ d->zoom = 1.0;
+ d->im->zoom(d->zoom);
+
+ if (d->autoZoom)
+ updateAutoZoom();
+
+ updateContentsSize(true);
+
+ viewport()->setUpdatesEnabled(true);
+ viewport()->update();
+
+ emit signalZoomChanged(d->zoom);
+
+ emit signalLoadingFinished(filePath, success);
+}
+
+void Canvas::preload(const TQString& /*filename*/)
+{
+// d->im->preload(filename);
+}
+
+/*
+These code part are unused and untested
+void Canvas::save(const TQString& filename, IOFileSettingsContainer *IOFileSettings)
+{
+ d->im->save(filename, IOFileSettings);
+ emit signalSavingStarted(filename);
+}
+
+void Canvas::saveAs(const TQString& filename,IOFileSettingsContainer *IOFileSettings,
+ const TQString& mimeType)
+{
+ d->im->saveAs(filename, IOFileSettings, mimeType);
+ emit signalSavingStarted(filename);
+}
+*/
+
+void Canvas::saveAs(const TQString& filename, IOFileSettingsContainer *IOFileSettings,
+ bool setExifOrientationTag, const TQString& mimeType)
+{
+ d->im->saveAs(filename, IOFileSettings, setExifOrientationTag, mimeType);
+ emit signalSavingStarted(filename);
+}
+
+void Canvas::slotImageSaved(const TQString& filePath, bool success)
+{
+ emit signalSavingFinished(filePath, success);
+}
+
+void Canvas::switchToLastSaved(const TQString& newFilename)
+{
+ d->im->switchToLastSaved(newFilename);
+}
+
+void Canvas::abortSaving()
+{
+ d->im->abortSaving();
+}
+
+void Canvas::setModified()
+{
+ d->im->setModified();
+}
+
+void Canvas::readMetadataFromFile(const TQString &file)
+{
+ d->im->readMetadataFromFile(file);
+}
+
+void Canvas::clearUndoHistory()
+{
+ d->im->clearUndoManager();
+}
+
+void Canvas::setUndoHistoryOrigin()
+{
+ d->im->setUndoManagerOrigin();
+}
+
+void Canvas::updateUndoState()
+{
+ d->im->updateUndoState();
+}
+
+DImg Canvas::currentImage()
+{
+ return DImg(*d->im->getImg());
+}
+
+TQString Canvas::currentImageFileFormat()
+{
+ return d->im->getImageFormat();
+}
+
+TQString Canvas::currentImageFilePath()
+{
+ return d->im->getImageFilePath();
+}
+
+int Canvas::imageWidth()
+{
+ return d->im->origWidth();
+}
+
+int Canvas::imageHeight()
+{
+ return d->im->origHeight();
+}
+
+bool Canvas::isReadOnly()
+{
+ return d->im->isReadOnly();
+}
+
+TQRect Canvas::getSelectedArea()
+{
+ int x, y, w, h;
+ d->im->getSelectedArea(x, y, w, h);
+ return ( TQRect(x, y, w, h) );
+}
+
+DImgInterface *Canvas::interface() const
+{
+ return d->im;
+}
+
+void Canvas::makeDefaultEditingCanvas()
+{
+ DImgInterface::setDefaultInterface(d->im);
+}
+
+double Canvas::calcAutoZoomFactor()
+{
+ if (!d->im->imageValid()) return d->zoom;
+
+ double srcWidth = d->im->origWidth();
+ double srcHeight = d->im->origHeight();
+ double dstWidth = contentsRect().width();
+ double dstHeight = contentsRect().height();
+ return TQMIN(dstWidth/srcWidth, dstHeight/srcHeight);
+}
+
+void Canvas::updateAutoZoom()
+{
+ d->zoom = calcAutoZoomFactor();
+ d->im->zoom(d->zoom);
+ emit signalZoomChanged(d->zoom);
+}
+
+void Canvas::updateContentsSize(bool deleteRubber)
+{
+ viewport()->setUpdatesEnabled(false);
+
+ if (deleteRubber && d->rubber)
+ {
+ delete d->rubber;
+ d->rubber = 0;
+ d->ltActive = false;
+ d->rtActive = false;
+ d->lbActive = false;
+ d->rbActive = false;
+ d->pressedMoved = false;
+ viewport()->unsetCursor();
+ viewport()->setMouseTracking(false);
+ if (d->im->imageValid())
+ emit signalSelected(false);
+ }
+
+ int wZ = d->im->width();
+ int hZ = d->im->height();
+
+ if (visibleWidth() > wZ || visibleHeight() > hZ)
+ {
+ // Center the image
+ int centerx = contentsRect().width()/2;
+ int centery = contentsRect().height()/2;
+ int xoffset = int(centerx - wZ/2);
+ int yoffset = int(centery - hZ/2);
+ xoffset = TQMAX(xoffset, 0);
+ yoffset = TQMAX(yoffset, 0);
+
+ d->pixmapRect = TQRect(xoffset, yoffset, wZ, hZ);
+ }
+ else
+ {
+ d->pixmapRect = TQRect(0, 0, wZ, hZ);
+ }
+
+ if (!deleteRubber && d->rubber)
+ {
+ int xSel, ySel, wSel, hSel;
+ d->im->getSelectedArea(xSel, ySel, wSel, hSel);
+ xSel = (int)((xSel * d->tileSize) / floor(d->tileSize / d->zoom));
+ ySel = (int)((ySel * d->tileSize) / floor(d->tileSize / d->zoom));
+ wSel = (int)((wSel * d->tileSize) / floor(d->tileSize / d->zoom));
+ hSel = (int)((hSel * d->tileSize) / floor(d->tileSize / d->zoom));
+ d->rubber->setX(xSel);
+ d->rubber->setY(ySel);
+ d->rubber->setWidth(wSel);
+ d->rubber->setHeight(hSel);
+ d->rubber->moveBy(d->pixmapRect.x(), d->pixmapRect.y());
+ }
+
+ d->tileCache.clear();
+ resizeContents(wZ, hZ);
+ viewport()->setUpdatesEnabled(true);
+}
+
+void Canvas::resizeEvent(TQResizeEvent* e)
+{
+ if (!e)
+ return;
+
+ TQScrollView::resizeEvent(e);
+
+ if (d->autoZoom)
+ updateAutoZoom();
+
+ updateContentsSize(false);
+
+ // No need to repaint. its called
+ // automatically after resize
+
+ // To be sure than corner widget used to pan image will be hide/show
+ // accordinly with resize event.
+ slotZoomChanged(d->zoom);
+}
+
+void Canvas::viewportPaintEvent(TQPaintEvent *e)
+{
+ TQRect er(e->rect());
+ er = TQRect(TQMAX(er.x() - 1, 0),
+ TQMAX(er.y() - 1, 0),
+ TQMIN(er.width() + 2, contentsRect().width()),
+ TQMIN(er.height() + 2, contentsRect().height()));
+
+ paintViewport(er, (d->zoom <= 1.0) ? true : false);
+}
+
+void Canvas::paintViewport(const TQRect& er, bool antialias)
+{
+ TQRect o_cr(viewportToContents(er.topLeft()), viewportToContents(er.bottomRight()));
+ TQRect cr = o_cr;
+
+ TQRegion clipRegion(er);
+ cr = d->pixmapRect.intersect(cr);
+
+ if (!cr.isEmpty() && d->im->imageValid())
+ {
+ clipRegion -= TQRect(contentsToViewport(cr.topLeft()), cr.size());
+
+ TQRect pr = TQRect(cr.x() - d->pixmapRect.x(), cr.y() - d->pixmapRect.y(),
+ cr.width(), cr.height());
+
+ int x1 = (int)floor((double)pr.x() / (double)d->tileSize) * d->tileSize;
+ int y1 = (int)floor((double)pr.y() / (double)d->tileSize) * d->tileSize;
+ int x2 = (int)ceilf((double)pr.right() / (double)d->tileSize) * d->tileSize;
+ int y2 = (int)ceilf((double)pr.bottom() / (double)d->tileSize) * d->tileSize;
+
+ TQPixmap pix(d->tileSize, d->tileSize);
+ int sx, sy, sw, sh;
+ int step = (int)floor(d->tileSize / d->zoom);
+
+ bool hasRubber = (d->rubber && d->pressedMoved && d->pressedMoving && d->rubber->intersects(pr));
+ if (hasRubber)
+ {
+ // remove rubber
+ drawRubber();
+ }
+
+ for (int j = y1 ; j < y2 ; j += d->tileSize)
+ {
+ for (int i = x1 ; i < x2 ; i += d->tileSize)
+ {
+ TQString key = TQString("%1,%2").arg(i).arg(j);
+ TQPixmap *pix = d->tileCache.find(key);
+
+ if (!pix)
+ {
+ if (antialias)
+ {
+ pix = new TQPixmap(d->tileSize, d->tileSize);
+ d->tileCache.insert(key, pix);
+ }
+ else
+ {
+ pix = d->tileTmpPix;
+ }
+
+ if (d->im->hasAlpha())
+ {
+ TQPainter p(pix);
+ p.drawTiledPixmap(0, 0, d->tileSize, d->tileSize,
+ d->qcheck, 0, 0);
+ p.end();
+ }
+ else
+ {
+ pix->fill(d->bgColor);
+ }
+
+ // NOTE : with implementations <= 0.9.1, the canvas doesn't work properly using high zoom level (> 500).
+ // The sx, sy, sw, sh values haven't be computed properly and "tile" artefacts been appears
+ // over the image. Look the example here:
+ // http://digikam3rdparty.free.fr/Screenshots/editorhighzoomartefact.png
+ // Note than these "tile" artifacts are not the real tiles of canvas.
+ // The new implementation below fix this problem to handle properly the areas to
+ // use from the source image to generate the canvas pixmap tiles.
+
+ sx = (int)floor((double)i / d->tileSize) * step;
+ sy = (int)floor((double)j / d->tileSize) * step;
+ sw = step;
+ sh = step;
+
+ if (d->rubber && d->pressedMoved && !d->pressedMoving)
+ {
+ TQRect rr(d->rubber->normalize());
+ TQRect r(i, j, d->tileSize, d->tileSize);
+
+ d->im->paintOnDevice(pix, sx, sy, sw, sh,
+ 0, 0, d->tileSize, d->tileSize,
+ rr.x() - i - d->pixmapRect.x(),
+ rr.y() - j - d->pixmapRect.y(),
+ rr.width(), rr.height(),
+ antialias);
+
+ rr.moveBy(-i -d->pixmapRect.x(), -j -d->pixmapRect.y());
+
+ TQPainter p(pix);
+ p.setPen(TQPen(TQColor(250, 250, 255), 1));
+ p.drawRect(rr);
+ if (rr.width() >= 10 && rr.height() >= 10)
+ {
+ p.drawRect(rr.x(), rr.y(), 5, 5);
+ p.drawRect(rr.x(), rr.y()+rr.height()-5, 5, 5);
+ p.drawRect(rr.x()+rr.width()-5, rr.y()+rr.height()-5, 5, 5);
+ p.drawRect(rr.x()+rr.width()-5, rr.y(), 5, 5);
+ }
+ p.end();
+ }
+ else
+ {
+ d->im->paintOnDevice(pix, sx, sy, sw, sh,
+ 0, 0, d->tileSize, d->tileSize,
+ antialias);
+ }
+ }
+
+ TQRect r(i, j, d->tileSize, d->tileSize);
+ TQRect ir = pr.intersect(r);
+ TQPoint pt(contentsToViewport(TQPoint(ir.x() + d->pixmapRect.x(),
+ ir.y() + d->pixmapRect.y())));
+
+ bitBlt(viewport(), pt.x(), pt.y(),
+ pix,
+ ir.x()-r.x(), ir.y()-r.y(),
+ ir.width(), ir.height());
+ }
+ }
+
+ if (hasRubber)
+ {
+ // restore rubber
+ drawRubber();
+ }
+ }
+
+ TQPainter painter(viewport());
+ painter.setClipRegion(clipRegion);
+ painter.fillRect(er, d->bgColor);
+ painter.end();
+}
+
+void Canvas::drawRubber()
+{
+ if (!d->rubber || !d->im->imageValid())
+ return;
+
+ TQPainter p(viewport());
+ p.setRasterOp(TQt::NotROP );
+ p.setPen(TQPen(TQt::color0, 1));
+ p.setBrush(NoBrush);
+
+ TQRect r(d->rubber->normalize());
+ r = TQRect(contentsToViewport(TQPoint(r.x(), r.y())), r.size());
+
+ TQPoint pnt(r.x(), r.y());
+
+ style().drawPrimitive(TQStyle::PE_FocusRect, &p,
+ TQRect(pnt.x(), pnt.y(), r.width(), r.height()),
+ colorGroup(), TQStyle::Style_Default,
+ TQStyleOption(colorGroup().base()));
+ p.end();
+}
+
+void Canvas::contentsMousePressEvent(TQMouseEvent *e)
+{
+ if (!e || e->button() == TQt::RightButton)
+ return;
+
+ d->midButtonPressed = false;
+
+ if (e->button() == TQt::LeftButton)
+ {
+ if (d->ltActive || d->rtActive ||
+ d->lbActive || d->rbActive)
+ {
+ Q_ASSERT( d->rubber );
+ if (!d->rubber)
+ return;
+
+ // Set diagonally opposite corner as anchor
+
+ TQRect r(d->rubber->normalize());
+
+ if (d->ltActive)
+ {
+ d->rubber->setTopLeft(r.bottomRight());
+ d->rubber->setBottomRight(r.topLeft());
+ }
+ else if (d->rtActive)
+ {
+ d->rubber->setTopLeft(r.bottomLeft());
+ d->rubber->setBottomRight(r.topRight());
+ }
+ else if (d->lbActive)
+ {
+ d->rubber->setTopLeft(r.topRight());
+ d->rubber->setBottomRight(r.bottomLeft());
+ }
+ else if (d->rbActive)
+ {
+ d->rubber->setTopLeft(r.topLeft());
+ d->rubber->setBottomRight(r.bottomLeft());
+ }
+
+ viewport()->setMouseTracking(false);
+ d->pressedMoved = false;
+ d->pressedMoving = true;
+
+ d->tileCache.clear();
+ viewport()->repaint(false);
+
+ return;
+ }
+ }
+ else if (e->button() == TQt::MidButton)
+ {
+ if (visibleWidth() < d->im->width() ||
+ visibleHeight() < d->im->height())
+ {
+ viewport()->setCursor(TQt::SizeAllCursor);
+ d->midButtonPressed = true;
+ d->midButtonX = e->x();
+ d->midButtonY = e->y();
+ }
+ return;
+ }
+
+ if (d->rubber)
+ {
+ delete d->rubber;
+ d->rubber = 0;
+ }
+
+ d->rubber = new TQRect(e->x(), e->y(), 0, 0);
+
+ if (d->pressedMoved)
+ {
+ d->tileCache.clear();
+ viewport()->update();
+ }
+
+ d->pressedMoved = false;
+ d->pressedMoving = true;
+
+ viewport()->setMouseTracking(false);
+}
+
+void Canvas::contentsMouseMoveEvent(TQMouseEvent *e)
+{
+ if (!e)
+ return;
+
+ if (e->state() & TQt::MidButton)
+ {
+ if (d->midButtonPressed)
+ {
+ scrollBy(d->midButtonX - e->x(),
+ d->midButtonY - e->y());
+ }
+ }
+ else if (!viewport()->hasMouseTracking())
+ {
+ if (!d->rubber)
+ return;
+
+ if (e->state() != TQt::LeftButton &&
+ !(d->ltActive || d->rtActive ||
+ d->lbActive || d->rbActive))
+ return;
+
+ // Clear old rubber.
+ if (d->pressedMoved)
+ drawRubber();
+
+ // Move content if necessary.
+ blockSignals(true);
+ setUpdatesEnabled(false);
+ ensureVisible(e->x(), e->y(), 10, 10);
+ setUpdatesEnabled(true);
+ blockSignals(false);
+
+ // draw the new rubber position.
+ int r, b;
+ r = (e->x() > d->pixmapRect.left()) ? e->x() : d->pixmapRect.left();
+ r = (r < d->pixmapRect.right()) ? r : d->pixmapRect.right();
+ b = (e->y() > d->pixmapRect.top()) ? e->y() : d->pixmapRect.top();
+ b = (b < d->pixmapRect.bottom()) ? b : d->pixmapRect.bottom();
+ d->rubber->setRight(r);
+ d->rubber->setBottom(b);
+ drawRubber();
+
+ d->pressedMoved = true;
+ d->pressedMoving = true;
+
+ // To refresh editor status bar with current selection.
+ emit signalSelectionChanged(calcSeletedArea());
+ }
+ else
+ {
+ if (!d->rubber)
+ return;
+
+ TQRect r(d->rubber->normalize());
+
+ TQRect lt(r.x()-5, r.y()-5, 10, 10);
+ TQRect rt(r.x()+r.width()-5, r.y()-5, 10, 10);
+ TQRect lb(r.x()-5, r.y()+r.height()-5, 10, 10);
+ TQRect rb(r.x()+r.width()-5, r.y()+r.height()-5, 10, 10);
+
+ d->ltActive = false;
+ d->rtActive = false;
+ d->lbActive = false;
+ d->rbActive = false;
+
+ if (lt.contains(e->x(), e->y()))
+ {
+ viewport()->setCursor(TQt::SizeFDiagCursor);
+ d->ltActive = true;
+ }
+ else if (rb.contains(e->x(), e->y()))
+ {
+ viewport()->setCursor(TQt::SizeFDiagCursor);
+ d->rbActive = true;
+ }
+ else if (lb.contains(e->x(), e->y()))
+ {
+ viewport()->setCursor(TQt::SizeBDiagCursor);
+ d->lbActive = true;
+ }
+ else if (rt.contains(e->x(), e->y()))
+ {
+ viewport()->setCursor(TQt::SizeBDiagCursor);
+ d->rtActive = true;
+ }
+ else
+ viewport()->unsetCursor();
+ }
+}
+
+void Canvas::contentsMouseReleaseEvent(TQMouseEvent *e)
+{
+ if (!e)
+ return;
+
+ d->midButtonPressed = false;
+
+ if (d->pressedMoving)
+ {
+ d->pressedMoving = false;
+ viewport()->update();
+ }
+
+ if (d->pressedMoved && d->rubber)
+ {
+ // Normalize rubber rectangle to always have the selection into the image
+ TQRect rec = d->rubber->normalize();
+
+ if (rec.left() < d->pixmapRect.left()) rec.setLeft(d->pixmapRect.left());
+ if (rec.right() > d->pixmapRect.right()) rec.setRight(d->pixmapRect.right());
+ if (rec.top() < d->pixmapRect.top()) rec.setTop(d->pixmapRect.top());
+ if (rec.bottom() > d->pixmapRect.bottom()) rec.setBottom(d->pixmapRect.bottom());
+
+ d->rubber->setLeft(rec.left());
+ d->rubber->setRight(rec.right());
+ d->rubber->setTop(rec.top());
+ d->rubber->setBottom(rec.bottom());
+
+ d->tileCache.clear();
+ viewport()->setMouseTracking(true);
+ if (d->im->imageValid())
+ emit signalSelected(true);
+ }
+ else
+ {
+ d->ltActive = false;
+ d->rtActive = false;
+ d->lbActive = false;
+ d->rbActive = false;
+ viewport()->setMouseTracking(false);
+ viewport()->unsetCursor();
+ if (d->im->imageValid())
+ emit signalSelected(false);
+ }
+
+ if (e->button() != TQt::LeftButton)
+ {
+ viewport()->unsetCursor();
+ }
+
+ if (e->button() == TQt::RightButton)
+ {
+ emit signalRightButtonClicked();
+ }
+}
+
+void Canvas::contentsWheelEvent(TQWheelEvent *e)
+{
+ e->accept();
+
+ if (e->state() & TQt::ShiftButton)
+ {
+ if (e->delta() < 0)
+ emit signalShowNextImage();
+ else if (e->delta() > 0)
+ emit signalShowPrevImage();
+ return;
+ }
+ else if (e->state() & TQt::ControlButton)
+ {
+ if (e->delta() < 0)
+ slotDecreaseZoom();
+ else if (e->delta() > 0)
+ slotIncreaseZoom();
+ return;
+ }
+
+ TQScrollView::contentsWheelEvent(e);
+}
+
+bool Canvas::maxZoom()
+{
+ return ((d->zoom * d->zoomMultiplier) >= d->maxZoom);
+}
+
+bool Canvas::minZoom()
+{
+ return ((d->zoom / d->zoomMultiplier) <= d->minZoom);
+}
+
+bool Canvas::exifRotated()
+{
+ return d->im->exifRotated();
+}
+
+double Canvas::snapZoom(double zoom)
+{
+ // If the zoom value gets changed from d->zoom to zoom
+ // across 50%, 100% or fit-to-window, then return the
+ // the corresponding special value. Otherwise zoom is returned unchanged.
+ double fit = calcAutoZoomFactor();
+ TQValueList<double> snapValues;
+ snapValues.append(0.5);
+ snapValues.append(1.0);
+ snapValues.append(fit);
+
+ qHeapSort(snapValues);
+ TQValueList<double>::const_iterator it;
+
+ if (d->zoom < zoom)
+ {
+ for(it = snapValues.constBegin(); it != snapValues.constEnd(); ++it)
+ {
+ double z = *it;
+ if ((d->zoom < z) && (zoom > z))
+ {
+ zoom = z;
+ break;
+ }
+ }
+ }
+ else
+ {
+ // We need to go through the list in reverse order,
+ // however, tqCopyBackward does not seem to work here, so
+ // a simple for loop over integers is used instead.
+ for(int i=snapValues.size()-1; i>=0; i--)
+ {
+ double z = snapValues[i];
+ if ((d->zoom > z) && (zoom < z))
+ {
+ zoom = z;
+ break;
+ }
+ }
+ }
+
+ return zoom;
+}
+
+void Canvas::slotIncreaseZoom()
+{
+ if (maxZoom())
+ return;
+
+ double zoom = d->zoom * d->zoomMultiplier;
+ zoom = snapZoom(zoom);
+ setZoomFactor(zoom);
+}
+
+void Canvas::slotDecreaseZoom()
+{
+ if (minZoom())
+ return;
+
+ double zoom = d->zoom / d->zoomMultiplier;
+ zoom = snapZoom(zoom);
+ setZoomFactor(zoom);
+}
+
+void Canvas::setZoomFactorSnapped(double zoom)
+{
+ double fit = calcAutoZoomFactor();
+
+ if (fabs(zoom-fit) < 0.05)
+ {
+ // If 1.0 or 0.5 are even closer to zoom than fit, then choose these.
+ if (fabs(zoom-fit) > fabs(zoom-1.0) )
+ {
+ zoom = 1.0;
+ }
+ else if (fabs(zoom-fit) > fabs(zoom-0.5) )
+ {
+ zoom = 0.5;
+ }
+ else
+ {
+ zoom = fit;
+ }
+ }
+ else
+ {
+ if (fabs(zoom-1.0) < 0.05)
+ {
+ zoom = 1.0;
+ }
+ if (fabs(zoom-0.5) < 0.05)
+ {
+ zoom = 0.5;
+ }
+ }
+ setZoomFactor(zoom);
+}
+
+double Canvas::zoomFactor()
+{
+ return d->zoom;
+}
+
+void Canvas::setZoomFactor(double zoom)
+{
+ if (d->autoZoom)
+ {
+ d->autoZoom = false;
+ emit signalToggleOffFitToWindow();
+ }
+
+ // Zoom using center of canvas and given zoom factor.
+
+ double cpx = contentsX() + visibleWidth() / 2.0;
+ double cpy = contentsY() + visibleHeight() / 2.0;
+
+ cpx = (cpx / d->tileSize) * floor(d->tileSize / d->zoom);
+ cpy = (cpy / d->tileSize) * floor(d->tileSize / d->zoom);
+
+ d->zoom = zoom;
+
+ d->im->zoom(d->zoom);
+ updateContentsSize(false);
+
+ viewport()->setUpdatesEnabled(false);
+ center((int)((cpx * d->tileSize) / floor(d->tileSize / d->zoom)),
+ (int)((cpy * d->tileSize) / floor(d->tileSize / d->zoom)));
+ viewport()->setUpdatesEnabled(true);
+ viewport()->update();
+
+ emit signalZoomChanged(d->zoom);
+}
+
+void Canvas::fitToSelect()
+{
+ int xSel, ySel, wSel, hSel;
+ d->im->getSelectedArea(xSel, ySel, wSel, hSel);
+
+ if (wSel && hSel )
+ {
+ // If selected area, use center of selection
+ // and recompute zoom factor accordinly.
+ double cpx = xSel + wSel / 2.0;
+ double cpy = ySel + hSel / 2.0;
+
+ double srcWidth = wSel;
+ double srcHeight = hSel;
+ double dstWidth = contentsRect().width();
+ double dstHeight = contentsRect().height();
+
+ d->zoom = TQMIN(dstWidth/srcWidth, dstHeight/srcHeight);
+
+ d->autoZoom = false;
+ emit signalToggleOffFitToWindow();
+ d->im->zoom(d->zoom);
+ updateContentsSize(true);
+
+ viewport()->setUpdatesEnabled(false);
+ center((int)((cpx * d->tileSize) / floor(d->tileSize / d->zoom)),
+ (int)((cpy * d->tileSize) / floor(d->tileSize / d->zoom)));
+ viewport()->setUpdatesEnabled(true);
+ viewport()->update();
+
+ emit signalZoomChanged(d->zoom);
+ }
+}
+
+bool Canvas::fitToWindow()
+{
+ return d->autoZoom;
+}
+
+void Canvas::toggleFitToWindow()
+{
+ d->autoZoom = !d->autoZoom;
+
+ if (d->autoZoom)
+ updateAutoZoom();
+ else
+ {
+ d->zoom = 1.0;
+ emit signalZoomChanged(d->zoom);
+ }
+
+ d->im->zoom(d->zoom);
+ updateContentsSize(false);
+ slotZoomChanged(d->zoom);
+ viewport()->update();
+}
+
+void Canvas::slotRotate90()
+{
+ d->im->rotate90();
+}
+
+void Canvas::slotRotate180()
+{
+ d->im->rotate180();
+}
+
+void Canvas::slotRotate270()
+{
+ d->im->rotate270();
+}
+
+void Canvas::slotFlipHoriz()
+{
+ d->im->flipHoriz();
+}
+
+void Canvas::slotFlipVert()
+{
+ d->im->flipVert();
+}
+
+void Canvas::slotCrop()
+{
+ int x, y, w, h;
+ d->im->getSelectedArea(x, y, w, h);
+
+ if (!w && !h ) // No current selection.
+ return;
+
+ d->im->crop(x, y, w, h);
+}
+
+void Canvas::resizeImage(int w, int h)
+{
+ d->im->resize(w, h);
+}
+
+void Canvas::setBackgroundColor(const TQColor& color)
+{
+ if (d->bgColor == color)
+ return;
+
+ d->bgColor = color;
+ viewport()->update();
+}
+
+void Canvas::setICCSettings(ICCSettingsContainer *cmSettings)
+{
+ d->im->setICCSettings(cmSettings);
+ d->tileCache.clear();
+ viewport()->update();
+}
+
+void Canvas::setExposureSettings(ExposureSettingsContainer *expoSettings)
+{
+ d->im->setExposureSettings(expoSettings);
+ d->tileCache.clear();
+ viewport()->update();
+}
+
+void Canvas::setExifOrient(bool exifOrient)
+{
+ d->im->setExifOrient(exifOrient);
+ viewport()->update();
+}
+
+void Canvas::increaseGamma()
+{
+ d->im->changeGamma(1);
+ d->tileCache.clear();
+ viewport()->update();
+}
+
+void Canvas::decreaseGamma()
+{
+ d->im->changeGamma(-1);
+ d->tileCache.clear();
+ viewport()->update();
+}
+
+void Canvas::increaseBrightness()
+{
+ d->im->changeBrightness(1);
+ d->tileCache.clear();
+ viewport()->update();
+}
+
+void Canvas::decreaseBrightness()
+{
+ d->im->changeBrightness(-1);
+ d->tileCache.clear();
+ viewport()->update();
+}
+
+void Canvas::increaseContrast()
+{
+ d->im->changeContrast(5);
+ d->tileCache.clear();
+ viewport()->update();
+}
+
+void Canvas::decreaseContrast()
+{
+ d->im->changeContrast(-5);
+ d->tileCache.clear();
+ viewport()->update();
+}
+
+void Canvas::slotRestore()
+{
+ d->im->restore();
+}
+
+void Canvas::slotUndo(int steps)
+{
+ while(steps > 0)
+ {
+ d->im->undo();
+ --steps;
+ }
+}
+
+void Canvas::getUndoHistory(TQStringList &titles)
+{
+ d->im->getUndoHistory(titles);
+}
+
+void Canvas::getRedoHistory(TQStringList &titles)
+{
+ d->im->getRedoHistory(titles);
+}
+
+void Canvas::slotRedo(int steps)
+{
+ while(steps > 0)
+ {
+ d->im->redo();
+ --steps;
+ }
+}
+
+void Canvas::slotCopy()
+{
+ int x, y, w, h;
+ d->im->getSelectedArea(x, y, w, h);
+
+ if (!w && !h ) // No current selection.
+ return;
+
+ TQApplication::setOverrideCursor (TQt::waitCursor);
+ uchar* data = d->im->getImageSelection();
+ DImg selDImg = DImg(w, h, d->im->sixteenBit(), d->im->hasAlpha(), data);
+ delete [] data;
+
+ TQImage selImg = selDImg.copyTQImage();
+ TQApplication::clipboard()->setData(new TQImageDrag(selImg), TQClipboard::Clipboard);
+ TQApplication::restoreOverrideCursor ();
+}
+
+void Canvas::slotSelected()
+{
+ int x=0, y=0, w=0, h=0;
+
+ if (d->rubber && d->pressedMoved)
+ {
+ TQRect sel = calcSeletedArea();
+ x = sel.x();
+ y = sel.y();
+ w = sel.width();
+ h = sel.height();
+ }
+
+ d->im->setSelectedArea(x, y, w, h);
+}
+
+TQRect Canvas::calcSeletedArea()
+{
+ int x=0, y=0, w=0, h=0;
+ TQRect r(d->rubber->normalize());
+
+ if (r.isValid())
+ {
+ r.moveBy(- d->pixmapRect.x(), - d->pixmapRect.y());
+
+ x = (int)(((double)r.x() / d->tileSize) * floor(d->tileSize / d->zoom));
+ y = (int)(((double)r.y() / d->tileSize) * floor(d->tileSize / d->zoom));
+ w = (int)(((double)r.width() / d->tileSize) * floor(d->tileSize / d->zoom));
+ h = (int)(((double)r.height() / d->tileSize) * floor(d->tileSize / d->zoom));
+
+ x = TQMIN(imageWidth(), TQMAX(x, 0));
+ y = TQMIN(imageHeight(), TQMAX(y, 0));
+ w = TQMIN(imageWidth(), TQMAX(w, 0));
+ h = TQMIN(imageHeight(), TQMAX(h, 0));
+
+ // Avoid empty selection by rubberband - at least mark one pixel
+ // At high zoom factors, the rubberband may operate at subpixel level!
+ if (w == 0)
+ w = 1;
+ if (h == 0)
+ h = 1;
+ }
+
+ return TQRect(x, y, w, h);
+}
+
+void Canvas::slotModified()
+{
+ if (d->autoZoom)
+ updateAutoZoom();
+ d->im->zoom(d->zoom);
+
+ updateContentsSize(true);
+ viewport()->update();
+
+ // To be sure than corner widget used to pan image will be hide/show
+ // accordinly with new image size (if changed).
+ slotZoomChanged(d->zoom);
+
+ emit signalChanged();
+}
+
+void Canvas::slotCornerButtonPressed()
+{
+ if (d->panIconPopup)
+ {
+ d->panIconPopup->hide();
+ delete d->panIconPopup;
+ d->panIconPopup = 0;
+ }
+
+ d->panIconPopup = new TDEPopupFrame(this);
+ ImagePanIconWidget *pan = new ImagePanIconWidget(180, 120, d->panIconPopup);
+ d->panIconPopup->setMainWidget(pan);
+
+ TQRect r((int)(contentsX() / d->zoom), (int)(contentsY() / d->zoom),
+ (int)(visibleWidth() / d->zoom), (int)(visibleHeight() / d->zoom));
+ pan->setRegionSelection(r);
+ pan->setMouseFocus();
+
+ connect(pan, TQ_SIGNAL(signalSelectionMoved(const TQRect&, bool)),
+ this, TQ_SLOT(slotPanIconSelectionMoved(const TQRect&, bool)));
+
+ connect(pan, TQ_SIGNAL(signalHiden()),
+ this, TQ_SLOT(slotPanIconHiden()));
+
+ TQPoint g = mapToGlobal(viewport()->pos());
+ g.setX(g.x()+ viewport()->size().width());
+ g.setY(g.y()+ viewport()->size().height());
+ d->panIconPopup->popup(TQPoint(g.x() - d->panIconPopup->width(),
+ g.y() - d->panIconPopup->height()));
+
+ pan->setCursorToLocalRegionSelectionCenter();
+}
+
+void Canvas::slotPanIconHiden()
+{
+ d->cornerButton->blockSignals(true);
+ d->cornerButton->animateClick();
+ d->cornerButton->blockSignals(false);
+}
+
+void Canvas::slotPanIconSelectionMoved(const TQRect& r, bool b)
+{
+ setContentsPos((int)(r.x()*d->zoom), (int)(r.y()*d->zoom));
+
+ if (b)
+ {
+ d->panIconPopup->hide();
+ delete d->panIconPopup;
+ d->panIconPopup = 0;
+ slotPanIconHiden();
+ }
+}
+
+void Canvas::slotZoomChanged(double /*zoom*/)
+{
+ updateScrollBars();
+
+ if (horizontalScrollBar()->isVisible() || verticalScrollBar()->isVisible())
+ d->cornerButton->show();
+ else
+ d->cornerButton->hide();
+}
+
+void Canvas::slotSelectAll()
+{
+ if (d->rubber)
+ {
+ delete d->rubber;
+ d->rubber = 0;
+ }
+
+ d->rubber = new TQRect(d->pixmapRect);
+ d->pressedMoved = true;
+ d->tileCache.clear();
+ viewport()->setMouseTracking(true);
+ viewport()->update();
+
+ if (d->im->imageValid())
+ emit signalSelected(true);
+}
+
+void Canvas::slotSelectNone()
+{
+ reset();
+ viewport()->update();
+}
+
+} // namespace Digikam
diff --git a/src/utilities/imageeditor/canvas/canvas.h b/src/utilities/imageeditor/canvas/canvas.h
new file mode 100644
index 00000000..c772098d
--- /dev/null
+++ b/src/utilities/imageeditor/canvas/canvas.h
@@ -0,0 +1,209 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-01-09
+ * Description : image editor canvas management class
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Copyright (C) 2004-2008 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.
+ *
+ * ============================================================ */
+
+#ifndef CANVAS_H
+#define CANVAS_H
+
+// TQt includes.
+
+#include <tqscrollview.h>
+#include <tqrect.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+#include "dimg.h"
+
+class TQString;
+class TQStringList;
+class TQPixmap;
+class TQPaintEvent;
+class TQResizeEvent;
+class TQWheelEvent;
+class TQKeyEvent;
+class TQColor;
+
+namespace Digikam
+{
+
+class CanvasPrivate;
+class DImgInterface;
+class ExposureSettingsContainer;
+class ICCSettingsContainer;
+class IOFileSettingsContainer;
+
+class DIGIKAM_EXPORT Canvas : public TQScrollView
+{
+ TQ_OBJECT
+
+
+public:
+
+ Canvas(TQWidget *parent=0);
+ ~Canvas();
+
+ void load(const TQString& filename, IOFileSettingsContainer *IOFileSettings);
+ void preload(const TQString& filename);
+
+ void saveAs(const TQString& filename, IOFileSettingsContainer *IOFileSettings,
+ bool setExifOrientationTag, const TQString& mimeType=TQString());
+ void resetImage();
+ void switchToLastSaved(const TQString& newFilename);
+ void abortSaving();
+ void setModified();
+ void readMetadataFromFile(const TQString &file);
+ void clearUndoHistory();
+ void setUndoHistoryOrigin();
+ void updateUndoState();
+ DImg currentImage();
+ TQString currentImageFileFormat();
+ TQString currentImageFilePath();
+
+ DImgInterface *interface() const;
+ void makeDefaultEditingCanvas();
+
+ double snapZoom(double z);
+ void setZoomFactorSnapped(double zoom);
+
+ double zoomFactor();
+ void setZoomFactor(double z);
+ bool fitToWindow();
+ bool maxZoom();
+ bool minZoom();
+ bool exifRotated();
+ int imageWidth();
+ int imageHeight();
+ TQRect getSelectedArea();
+
+ // If current image file format is only available in read only,
+ // typicially all RAW image file formats.
+ bool isReadOnly();
+
+ void resizeImage(int w, int h);
+
+ void setBackgroundColor(const TQColor& color);
+ void setICCSettings(ICCSettingsContainer *cmSettings);
+ void setExposureSettings(ExposureSettingsContainer *expoSettings);
+
+ void setExifOrient(bool exifOrient);
+
+ void increaseGamma();
+ void decreaseGamma();
+ void increaseBrightness();
+ void decreaseBrightness();
+ void increaseContrast();
+ void decreaseContrast();
+
+ void getUndoHistory(TQStringList &titles);
+ void getRedoHistory(TQStringList &titles);
+
+ void toggleFitToWindow();
+ void fitToSelect();
+
+signals:
+
+ void signalZoomChanged(double zoom);
+ void signalMaxZoom();
+ void signalMinZoom();
+ void signalChanged();
+ void signalUndoStateChanged(bool, bool, bool);
+ void signalSelected(bool);
+ void signalRightButtonClicked();
+ void signalShowNextImage();
+ void signalShowPrevImage();
+ void signalPrepareToLoad();
+ void signalLoadingStarted(const TQString &filename);
+ void signalLoadingFinished(const TQString &filename, bool success);
+ void signalLoadingProgress(const TQString& filePath, float progress);
+ void signalSavingStarted(const TQString &filename);
+ void signalSavingFinished(const TQString &filename, bool success);
+ void signalSavingProgress(const TQString& filePath, float progress);
+ void signalSelectionChanged(const TQRect&);
+ void signalToggleOffFitToWindow();
+
+public slots:
+
+ void slotIncreaseZoom();
+ void slotDecreaseZoom();
+
+ // image modifiers
+ void slotRotate90();
+ void slotRotate180();
+ void slotRotate270();
+
+ void slotFlipHoriz();
+ void slotFlipVert();
+
+ void slotCrop();
+
+ void slotRestore();
+ void slotUndo(int steps=1);
+ void slotRedo(int steps=1);
+
+ void slotCopy();
+
+ void slotSelectAll();
+ void slotSelectNone();
+
+protected:
+
+ void resizeEvent(TQResizeEvent* e);
+ void viewportPaintEvent(TQPaintEvent *e);
+ void contentsMousePressEvent(TQMouseEvent *e);
+ void contentsMouseMoveEvent(TQMouseEvent *e);
+ void contentsMouseReleaseEvent(TQMouseEvent *e);
+ void contentsWheelEvent(TQWheelEvent *e);
+
+private:
+
+ TQRect calcSeletedArea();
+ double calcAutoZoomFactor();
+ void updateAutoZoom();
+ void updateContentsSize(bool deleteRubber);
+
+ void drawRubber();
+ void paintViewport(const TQRect& er, bool antialias);
+
+ void reset();
+
+private slots:
+
+ void slotSelected();
+ void slotModified();
+ void slotImageLoaded(const TQString& filePath, bool success);
+ void slotImageSaved(const TQString& filePath, bool success);
+ void slotCornerButtonPressed();
+ void slotZoomChanged(double);
+ void slotPanIconSelectionMoved(const TQRect&, bool);
+ void slotPanIconHiden();
+
+private:
+
+ CanvasPrivate *d;
+};
+
+} // namespace Digikam
+
+#endif /* CANVAS_H */
+
diff --git a/src/utilities/imageeditor/canvas/colorcorrectiondlg.cpp b/src/utilities/imageeditor/canvas/colorcorrectiondlg.cpp
new file mode 100644
index 00000000..1403773f
--- /dev/null
+++ b/src/utilities/imageeditor/canvas/colorcorrectiondlg.cpp
@@ -0,0 +1,186 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-05-15
+ * Description : a dialog to see preview ICC color correction
+ * before to apply color profile.
+ *
+ * Copyright (C) 2006-2007 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.
+ *
+ * ============================================================ */
+
+// TQt includes.
+
+#include <tqlabel.h>
+#include <tqwhatsthis.h>
+#include <tqlayout.h>
+#include <tqframe.h>
+#include <tqstring.h>
+#include <tqfileinfo.h>
+#include <tqpushbutton.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kiconloader.h>
+#include <tdeapplication.h>
+#include <kseparator.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "dimg.h"
+#include "icctransform.h"
+#include "iccprofileinfodlg.h"
+#include "colorcorrectiondlg.h"
+#include "colorcorrectiondlg.moc"
+
+namespace Digikam
+{
+
+ColorCorrectionDlg::ColorCorrectionDlg(TQWidget* parent, DImg *preview,
+ IccTransform *iccTrans, const TQString& file)
+ : KDialogBase(parent, "", true, TQString(),
+ Help|Ok|Apply|Cancel, Ok, true)
+{
+ m_iccTrans = iccTrans;
+ m_parent = parent;
+ setHelp("iccprofile.anchor", "digikam");
+ setButtonText(Ok, i18n("Convert"));
+ setButtonTip(Ok, i18n("Apply the default color workspace profile to the image"));
+ setButtonText(Cancel, i18n("Do Nothing"));
+ setButtonTip(Cancel, i18n("Do not change the image"));
+ setButtonText(Apply, i18n("Assign"));
+ setButtonTip(Apply, i18n("Only embed the color workspace profile in the image, don't change the image"));
+
+ TQFileInfo fi(file);
+ setCaption(fi.fileName());
+
+ TQWidget *page = new TQWidget(this);
+ TQGridLayout* grid = new TQGridLayout(page, 3, 2, 0, KDialog::spacingHint());
+
+ TQLabel *originalTitle = new TQLabel(i18n("Original Image:"), page);
+ TQLabel *previewOriginal = new TQLabel(page);
+ TQLabel *targetTitle = new TQLabel(i18n("Corrected Image:"), page);
+ TQLabel *previewTarget = new TQLabel(page);
+ TQLabel *logo = new TQLabel(page);
+ TQLabel *message = new TQLabel(page);
+ TQLabel *currentProfileTitle = new TQLabel(i18n("Current workspace color profile:"), page);
+ TQLabel *currentProfileDesc = new TQLabel(TQString("<b>%1</b>").arg(m_iccTrans->getOutpoutProfileDescriptor()), page);
+ TQPushButton *currentProfInfo = new TQPushButton(i18n("Info..."), page);
+ TQLabel *embeddedProfileTitle = new TQLabel(i18n("Embedded color profile:"), page);
+ TQLabel *embeddedProfileDesc = new TQLabel(TQString("<b>%1</b>").arg(m_iccTrans->getEmbeddedProfileDescriptor()), page);
+ TQPushButton *embeddedProfInfo = new TQPushButton(i18n("Info..."), page);
+ KSeparator *line = new KSeparator(TQt::Horizontal, page);
+
+ if (m_iccTrans->embeddedProfile().isEmpty())
+ {
+ message->setText(i18n("<p>This image has not been assigned a color profile.</p>"
+ "<p>Do you want to convert it to your workspace color profile?</p>"));
+
+ line->hide();
+ embeddedProfileTitle->hide();
+ embeddedProfileDesc->hide();
+ embeddedProfInfo->hide();
+ }
+ else
+ {
+ message->setText(i18n("<p>This image has been assigned to a color profile that does not "
+ "match your default workspace color profile.</p>"
+ "<p>Do you want to convert it to your workspace color profile?</p>"));
+ }
+
+ previewOriginal->setPixmap(preview->convertToPixmap());
+ previewTarget->setPixmap(preview->convertToPixmap(m_iccTrans));
+ TDEIconLoader* iconLoader = TDEApplication::kApplication()->iconLoader();
+ logo->setPixmap(iconLoader->loadIcon("digikam", TDEIcon::NoGroup, 128, TDEIcon::DefaultState, 0, true));
+
+ grid->addMultiCellWidget(originalTitle, 0, 0, 0, 0);
+ grid->addMultiCellWidget(previewOriginal, 1, 1, 0, 0);
+ grid->addMultiCellWidget(targetTitle, 2, 2, 0, 0);
+ grid->addMultiCellWidget(previewTarget, 3, 3, 0, 0);
+
+ TQVBoxLayout *vlay = new TQVBoxLayout( KDialog::spacingHint() );
+ vlay->addWidget(logo);
+ vlay->addWidget(message);
+
+ vlay->addWidget(new KSeparator(TQt::Horizontal, page));
+ vlay->addWidget(currentProfileTitle);
+ vlay->addWidget(currentProfileDesc);
+
+ TQHBoxLayout *hlay1 = new TQHBoxLayout( KDialog::spacingHint() );
+ hlay1->addWidget(currentProfInfo);
+ hlay1->addStretch();
+ vlay->addLayout(hlay1);
+
+ vlay->addWidget(line);
+ vlay->addWidget(embeddedProfileTitle);
+ vlay->addWidget(embeddedProfileDesc);
+
+ TQHBoxLayout *hlay2 = new TQHBoxLayout( KDialog::spacingHint() );
+ hlay2->addWidget(embeddedProfInfo);
+ hlay2->addStretch();
+ vlay->addLayout(hlay2);
+ vlay->addStretch();
+
+ grid->addMultiCell(new TQSpacerItem(KDialog::spacingHint(), KDialog::spacingHint(),
+ TQSizePolicy::Minimum, TQSizePolicy::Expanding), 0, 3, 1, 1);
+ grid->addMultiCellLayout(vlay, 0, 3, 2, 2);
+
+ setMainWidget(page);
+
+ // --------------------------------------------------------------------
+
+ connect(currentProfInfo, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotCurrentProfInfo()) );
+
+ connect(embeddedProfInfo, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotEmbeddedProfInfo()) );
+
+ connect(this, TQ_SIGNAL(applyClicked()),
+ this, TQ_SLOT(slotApplyClicked()));
+}
+
+ColorCorrectionDlg::~ColorCorrectionDlg()
+{
+}
+
+void ColorCorrectionDlg::slotCurrentProfInfo()
+{
+ if (m_iccTrans->outputProfile().isEmpty())
+ return;
+
+ ICCProfileInfoDlg infoDlg(m_parent, TQString(), m_iccTrans->outputProfile());
+ infoDlg.exec();
+}
+
+void ColorCorrectionDlg::slotEmbeddedProfInfo()
+{
+ if (m_iccTrans->embeddedProfile().isEmpty())
+ return;
+
+ ICCProfileInfoDlg infoDlg(m_parent, TQString(), m_iccTrans->embeddedProfile());
+ infoDlg.exec();
+}
+
+void ColorCorrectionDlg::slotApplyClicked()
+{
+ DDebug() << "colorcorrectiondlg: Apply pressed" << endl;
+ done(-1);
+}
+
+} // NameSpace Digikam
+
diff --git a/src/utilities/imageeditor/canvas/colorcorrectiondlg.h b/src/utilities/imageeditor/canvas/colorcorrectiondlg.h
new file mode 100644
index 00000000..7cc4c19d
--- /dev/null
+++ b/src/utilities/imageeditor/canvas/colorcorrectiondlg.h
@@ -0,0 +1,72 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-05-15
+ * Description : a dialog to see preview ICC color correction
+ * before to apply color profile.
+ *
+ * Copyright (C) 2006-2007 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.
+ *
+ * ============================================================ */
+
+#ifndef COLORCORRECTIONDLG_H
+#define COLORCORRECTIONDLG_H
+
+// TQt includes.
+
+#include <tqstring.h>
+
+// KDE includes.
+
+#include <kdialogbase.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class IccTransform;
+class DImg;
+
+class DIGIKAM_EXPORT ColorCorrectionDlg : public KDialogBase
+{
+ TQ_OBJECT
+
+
+public:
+
+ ColorCorrectionDlg(TQWidget *parent, DImg *preview,
+ IccTransform *iccTrans, const TQString& file);
+ ~ColorCorrectionDlg();
+
+private slots:
+
+ void slotCurrentProfInfo();
+ void slotEmbeddedProfInfo();
+ void slotApplyClicked();
+
+private:
+
+ TQWidget *m_parent;
+
+ IccTransform *m_iccTrans;
+};
+
+} // Namespace Digikam
+
+#endif /* COLORCORRECTIONDLG_H */
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
+
diff --git a/src/utilities/imageeditor/canvas/dimginterface.h b/src/utilities/imageeditor/canvas/dimginterface.h
new file mode 100644
index 00000000..9a41eb05
--- /dev/null
+++ b/src/utilities/imageeditor/canvas/dimginterface.h
@@ -0,0 +1,200 @@
+/* ============================================================
+ *
+ * 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.
+ *
+ * ============================================================ */
+
+#ifndef DIMGINTERFACE_H
+#define DIMGINTERFACE_H
+
+// TQt includes.
+
+#include <tqobject.h>
+#include <tqstring.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+#include "dimg.h"
+
+class TQWidget;
+class TQPixmap;
+
+namespace Digikam
+{
+
+class ICCSettingsContainer;
+class ExposureSettingsContainer;
+class IOFileSettingsContainer;
+class LoadingDescription;
+class DImgInterfacePrivate;
+
+class DIGIKAM_EXPORT DImgInterface : public TQObject
+{
+ TQ_OBJECT
+
+
+public:
+
+ static DImgInterface* defaultInterface();
+ static void setDefaultInterface(DImgInterface *defaultInterface);
+
+ DImgInterface();
+ ~DImgInterface();
+
+ void load(const TQString& filename, IOFileSettingsContainer *iofileSettings, TQWidget *parent=0);
+
+ void setICCSettings(ICCSettingsContainer *cmSettings);
+ void setExposureSettings(ExposureSettingsContainer *expoSettings);
+ void setExifOrient(bool exifOrient);
+
+ void undo();
+ void redo();
+ void restore();
+
+ void saveAs(const TQString& file, IOFileSettingsContainer *iofileSettings,
+ bool setExifOrientationTag, const TQString& mimeType=TQString());
+
+ void switchToLastSaved(const TQString& newFilename);
+ void abortSaving();
+ void setModified();
+ void readMetadataFromFile(const TQString &file);
+ void clearUndoManager();
+ void setUndoManagerOrigin();
+ void updateUndoState();
+ void resetImage();
+
+ void zoom(double val);
+
+ void paintOnDevice(TQPaintDevice* p,
+ int sx, int sy, int sw, int sh,
+ int dx, int dy, int dw, int dh,
+ int antialias);
+ void 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);
+
+ bool imageValid();
+ int width();
+ int height();
+ int origWidth();
+ int origHeight();
+ int bytesDepth();
+ bool hasAlpha();
+ bool sixteenBit();
+ bool exifRotated();
+ bool isReadOnly();
+
+ void setSelectedArea(int x, int y, int w, int h);
+ void getSelectedArea(int& x, int& y, int& w, int& h);
+
+ void rotate90(bool saveUndo=true);
+ void rotate180(bool saveUndo=true);
+ void rotate270(bool saveUndo=true);
+
+ void flipHoriz(bool saveUndo=true);
+ void flipVert(bool saveUndo=true);
+
+ void crop(int x, int y, int w, int h);
+
+ void resize(int w, int h);
+
+ void changeGamma(double gamma);
+ void changeBrightness(double brightness);
+ void changeContrast(double contrast);
+ void changeBCG(double gamma, double brightness, double contrast);
+
+ void setBCG(double brightness, double contrast, double gamma);
+
+ void convertDepth(int depth);
+
+ void getUndoHistory(TQStringList &titles);
+ void getRedoHistory(TQStringList &titles);
+
+ DImg* getImg();
+ uchar* getImage();
+
+ void putImage(uchar* data, int w, int h);
+ void putImage(uchar* data, int w, int h, bool sixteenBit);
+ void putImage(const TQString &caller, uchar* data, int w, int h);
+ void putImage(const TQString &caller, uchar* data, int w, int h, bool sixteenBit);
+
+ uchar* getImageSelection();
+ void putImageSelection(const TQString &caller, uchar* data);
+
+ void setEmbeddedICCToOriginalImage( TQString profilePath);
+
+ /** Convert a DImg image to a pixmap for screen using color
+ managemed view if necessary */
+ TQPixmap convertToPixmap(DImg& img);
+
+ TQByteArray getEmbeddedICC();
+ TQByteArray getExif();
+ TQByteArray getIptc();
+
+ ICCSettingsContainer *getICCSettings();
+
+ TQString getImageFileName();
+ TQString getImageFilePath();
+ TQString getImageFormat();
+
+ TQColor underExposureColor();
+ TQColor overExposureColor();
+
+protected slots:
+
+ void slotImageLoaded(const LoadingDescription &loadingDescription, const DImg& img);
+ void slotImageSaved(const TQString& filePath, bool success);
+ void slotLoadingProgress(const LoadingDescription &loadingDescription, float progress);
+ void slotSavingProgress(const TQString& filePath, float progress);
+
+signals:
+
+ void signalModified();
+ void signalUndoStateChanged(bool moreUndo, bool moreRedo, bool canSave);
+ void signalLoadingStarted(const TQString& filename);
+ void signalLoadingProgress(const TQString& filePath, float progress);
+ void signalImageLoaded(const TQString& filePath, bool success);
+ void signalSavingProgress(const TQString& filePath, float progress);
+ void signalImageSaved(const TQString& filePath, bool success);
+
+private slots:
+
+ void slotUseRawImportSettings();
+ void slotUseDefaultSettings();
+
+private:
+
+ void exifRotate(const TQString& filename);
+ void resetValues();
+
+private:
+
+ static DImgInterface *m_defaultInterface;
+
+ DImgInterfacePrivate *d;
+};
+
+} // namespace Digikam
+
+#endif /* DIMGINTERFACE_H */
diff --git a/src/utilities/imageeditor/canvas/iccsettingscontainer.h b/src/utilities/imageeditor/canvas/iccsettingscontainer.h
new file mode 100644
index 00000000..eadb12fb
--- /dev/null
+++ b/src/utilities/imageeditor/canvas/iccsettingscontainer.h
@@ -0,0 +1,82 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2005-12-08
+ * Description : ICC Settings Container.
+ *
+ * Copyright (C) 2005-2007 by F.J. Cruz <fj.cruz@supercable.es>
+ * Copyright (C) 2005-2008 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.
+ *
+ * ============================================================ */
+
+#ifndef ICCSETTINGSCONTAINER_H
+#define ICCSETTINGSCONTAINER_H
+
+// TQt includes.
+
+#include <tqstring.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class DIGIKAM_EXPORT ICCSettingsContainer
+{
+
+public:
+
+ ICCSettingsContainer()
+ {
+ enableCMSetting = false; // NOTE: by default, ICC color management is disable.
+
+ askOrApplySetting = false;
+ BPCSetting = false;
+ managedViewSetting = false;
+
+ renderingSetting = 0;
+
+ workspaceSetting = TQString();
+ monitorSetting = TQString();
+ inputSetting = TQString();
+ proofSetting = TQString();
+ };
+
+ ~ICCSettingsContainer(){};
+
+public:
+
+ bool enableCMSetting;
+
+ // FALSE -> apply
+ // TRUE -> ask
+ bool askOrApplySetting;
+ bool BPCSetting;
+ bool managedViewSetting;
+
+ int renderingSetting;
+
+ TQString workspaceSetting;
+ TQString monitorSetting;
+ TQString inputSetting;
+ TQString proofSetting;
+};
+
+} // namespace Digikam
+
+#endif // ICCSETTINGSCONTAINER_H
diff --git a/src/utilities/imageeditor/canvas/imageplugin.cpp b/src/utilities/imageeditor/canvas/imageplugin.cpp
new file mode 100644
index 00000000..b330cb5a
--- /dev/null
+++ b/src/utilities/imageeditor/canvas/imageplugin.cpp
@@ -0,0 +1,68 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-06-04
+ * Description : image plugins interface for image editor
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Copyright (C) 2006-2008 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.
+ *
+ * ============================================================ */
+
+// Local includes.
+
+#include "editortool.h"
+#include "editortooliface.h"
+#include "imageplugin.h"
+#include "imageplugin.moc"
+
+namespace Digikam
+{
+
+ImagePlugin::ImagePlugin(TQObject *parent, const char* name)
+ : TQObject(parent, name)
+{
+}
+
+ImagePlugin::~ImagePlugin()
+{
+}
+
+void ImagePlugin::setEnabledSelectionActions(bool)
+{
+}
+
+void ImagePlugin::setEnabledActions(bool)
+{
+}
+
+void ImagePlugin::loadTool(EditorTool* tool)
+{
+ EditorToolIface::editorToolIface()->loadTool(tool);
+
+ connect(tool, TQ_SIGNAL(okClicked()),
+ this, TQ_SLOT(slotToolDone()));
+
+ connect(tool, TQ_SIGNAL(cancelClicked()),
+ this, TQ_SLOT(slotToolDone()));
+}
+
+void ImagePlugin::slotToolDone()
+{
+ EditorToolIface::editorToolIface()->unLoadTool();
+}
+
+} // namespace Digikam
diff --git a/src/utilities/imageeditor/canvas/imageplugin.h b/src/utilities/imageeditor/canvas/imageplugin.h
new file mode 100644
index 00000000..ef506256
--- /dev/null
+++ b/src/utilities/imageeditor/canvas/imageplugin.h
@@ -0,0 +1,70 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-06-04
+ * Description : image plugins interface for image editor.
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Copyright (C) 2006-2008 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.
+ *
+ * ============================================================ */
+
+#ifndef IMAGEPLUGIN_H
+#define IMAGEPLUGIN_H
+
+// TQt includes.
+
+#include <tqobject.h>
+
+// KDE includes.
+
+#include <kxmlguiclient.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+class TQWidget;
+
+namespace Digikam
+{
+
+class EditorTool;
+
+class DIGIKAM_EXPORT ImagePlugin : public TQObject, public KXMLGUIClient
+{
+ TQ_OBJECT
+
+
+public:
+
+ ImagePlugin(TQObject *parent, const char* name=0);
+ virtual ~ImagePlugin();
+
+ virtual void setEnabledSelectionActions(bool enable);
+ virtual void setEnabledActions(bool enable);
+
+ void loadTool(EditorTool* tool);
+
+private slots:
+
+ void slotToolDone();
+};
+
+} //namespace Digikam
+
+#endif /* IMAGEPLUGIN_H */
+
diff --git a/src/utilities/imageeditor/canvas/imagepluginloader.cpp b/src/utilities/imageeditor/canvas/imagepluginloader.cpp
new file mode 100644
index 00000000..43c8a16c
--- /dev/null
+++ b/src/utilities/imageeditor/canvas/imagepluginloader.cpp
@@ -0,0 +1,278 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-06-04
+ * Description : image plugins loader for image editor.
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Copyright (C) 2004-2007 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.
+ *
+ * ============================================================ */
+
+// KDE includes.
+
+#include <ktrader.h>
+#include <tdeparts/componentfactory.h>
+#include <tdeapplication.h>
+#include <tdelocale.h>
+#include <kxmlguiclient.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "splashscreen.h"
+#include "imagepluginloader.h"
+
+namespace Digikam
+{
+
+// List of obsolete image plugins name.
+
+static const char* ObsoleteImagePluginsList[] =
+{
+ "digikamimageplugin_blowup", // Merged with "Resize" tool since 0.9.2.
+ "digikamimageplugin_solarize", // Renamed "ColorFx" since 0.9.2.
+ "digikamimageplugin_unsharp", // Merged with "Sharpen" tool since 0.9.2.
+ "digikamimageplugin_refocus", // Merged with "Sharpen" tool since 0.9.2.
+ "digikamimageplugin_despeckle", // Renamed "Noise Reduction" since 0.9.2.
+ "-1"
+};
+
+class ImagePluginLoaderPrivate
+{
+
+public:
+
+ typedef TQPair<TQString, ImagePlugin*> PluginType;
+ typedef TQValueList< PluginType > PluginList;
+
+public:
+
+ ImagePluginLoaderPrivate()
+ {
+ splash = 0;
+
+ for (int i=0 ; TQString(ObsoleteImagePluginsList[i]) != TQString("-1") ; i++)
+ obsoleteImagePluginsList << ObsoleteImagePluginsList[i];
+ }
+
+ TQStringList obsoleteImagePluginsList;
+
+ SplashScreen *splash;
+
+ PluginList pluginList;
+};
+
+ImagePluginLoader* ImagePluginLoader::m_instance=0;
+
+ImagePluginLoader* ImagePluginLoader::instance()
+{
+ return m_instance;
+}
+
+ImagePluginLoader::ImagePluginLoader(TQObject *parent, SplashScreen *splash)
+ : TQObject(parent)
+{
+ m_instance = this;
+ d = new ImagePluginLoaderPrivate;
+ d->splash = splash;
+
+ TQStringList imagePluginsList2Load;
+
+ TDETrader::OfferList offers = TDETrader::self()->query("Digikam/ImagePlugin");
+ TDETrader::OfferList::ConstIterator iter;
+
+ for (iter = offers.begin() ; iter != offers.end() ; ++iter)
+ {
+ KService::Ptr service = *iter;
+ if (!d->obsoleteImagePluginsList.contains(service->library()))
+ imagePluginsList2Load.append(service->library());
+ }
+
+ loadPluginsFromList(imagePluginsList2Load);
+}
+
+ImagePluginLoader::~ImagePluginLoader()
+{
+ delete d;
+ m_instance = 0;
+}
+
+void ImagePluginLoader::loadPluginsFromList(const TQStringList& list)
+{
+ if (d->splash)
+ d->splash->message(i18n("Loading Image Plugins"));
+
+ TDETrader::OfferList offers = TDETrader::self()->query("Digikam/ImagePlugin");
+ TDETrader::OfferList::ConstIterator iter;
+
+ int cpt = 0;
+
+ // Load plugin core at the first time.
+
+ for(iter = offers.begin(); iter != offers.end(); ++iter)
+ {
+ KService::Ptr service = *iter;
+ ImagePlugin *plugin;
+
+ if (service->library() == "digikamimageplugin_core")
+ {
+ if (!pluginIsLoaded(service->name()) )
+ {
+ int error=-1;
+ plugin = KParts::ComponentFactory::createInstanceFromService<ImagePlugin>(
+ service, this, service->name().local8Bit(), 0, &error);
+
+ if (plugin && (dynamic_cast<KXMLGUIClient*>(plugin) != 0))
+ {
+ d->pluginList.append(ImagePluginLoaderPrivate::PluginType(service->name(), plugin));
+
+ DDebug() << "ImagePluginLoader: Loaded plugin " << service->name() << endl;
+
+ ++cpt;
+ }
+ else
+ {
+ DWarning() << "ImagePluginLoader:: createInstanceFromLibrary returned 0 for "
+ << service->name()
+ << " (" << service->library() << ")"
+ << " with error code "
+ << error << endl;
+ if (error == KParts::ComponentFactory::ErrNoLibrary)
+ DWarning() << "KLibLoader says: "
+ << KLibLoader::self()->lastErrorMessage() << endl;
+ }
+ }
+ break;
+ }
+ }
+
+ // Load all other image plugins after (make a coherant menu construction in Image Editor).
+
+ for (iter = offers.begin(); iter != offers.end(); ++iter)
+ {
+ KService::Ptr service = *iter;
+ ImagePlugin *plugin;
+
+ if (!list.contains(service->library()) && service->library() != "digikamimageplugin_core")
+ {
+ if ((plugin = pluginIsLoaded(service->name())) != NULL)
+ d->pluginList.remove(ImagePluginLoaderPrivate::PluginType(service->name(),plugin));
+ }
+ else
+ {
+ if( pluginIsLoaded(service->name()) )
+ continue;
+ else
+ {
+ int error=-1;
+ plugin = KParts::ComponentFactory::createInstanceFromService<ImagePlugin>(
+ service, this, service->name().local8Bit(), 0);
+
+ if (plugin && (dynamic_cast<KXMLGUIClient*>(plugin) != 0))
+ {
+ d->pluginList.append(ImagePluginLoaderPrivate::PluginType(service->name(), plugin));
+
+ DDebug() << "ImagePluginLoader: Loaded plugin " << service->name() << endl;
+
+ ++cpt;
+ }
+ else
+ {
+ DWarning() << "ImagePluginLoader:: createInstanceFromLibrary returned 0 for "
+ << service->name()
+ << " (" << service->library() << ")"
+ << " with error code "
+ << error << endl;
+ if (error == KParts::ComponentFactory::ErrNoLibrary)
+ DWarning() << "KLibLoader says: "
+ << KLibLoader::self()->lastErrorMessage() << endl;
+ }
+ }
+ }
+ }
+
+ d->splash = 0; // Splashcreen is only lanched at the first time.
+ // If user change plugins list to use in setup, don't try to
+ // use the old splashscreen instance.
+}
+
+ImagePlugin* ImagePluginLoader::pluginIsLoaded(const TQString& name)
+{
+ if ( d->pluginList.isEmpty() )
+ return 0;
+
+ for (ImagePluginLoaderPrivate::PluginList::iterator it = d->pluginList.begin();
+ it != d->pluginList.end(); ++it)
+ {
+ if ((*it).first == name )
+ return (*it).second;
+ }
+
+ return 0;
+}
+
+ImagePlugin* ImagePluginLoader::pluginInstance(const TQString& libraryName)
+{
+ TDETrader::OfferList offers = TDETrader::self()->query("Digikam/ImagePlugin");
+ TDETrader::OfferList::ConstIterator iter;
+
+ for(iter = offers.begin(); iter != offers.end(); ++iter)
+ {
+ KService::Ptr service = *iter;
+
+ if(service->library() == libraryName)
+ {
+ return ( pluginIsLoaded(service->name()) );
+ }
+ }
+
+ return 0;
+}
+
+bool ImagePluginLoader::pluginLibraryIsLoaded(const TQString& libraryName)
+{
+ TDETrader::OfferList offers = TDETrader::self()->query("Digikam/ImagePlugin");
+ TDETrader::OfferList::ConstIterator iter;
+
+ for(iter = offers.begin(); iter != offers.end(); ++iter)
+ {
+ KService::Ptr service = *iter;
+
+ if(service->library() == libraryName)
+ {
+ if( pluginIsLoaded(service->name()) )
+ return true;
+ }
+ }
+
+ return false;
+}
+
+TQPtrList<ImagePlugin> ImagePluginLoader::pluginList()
+{
+ TQPtrList<ImagePlugin> list;
+
+ for (ImagePluginLoaderPrivate::PluginList::iterator it = d->pluginList.begin();
+ it != d->pluginList.end(); ++it)
+ {
+ list.append((*it).second);
+ }
+
+ return list;
+}
+
+} // namespace Digikam
diff --git a/src/utilities/imageeditor/canvas/imagepluginloader.h b/src/utilities/imageeditor/canvas/imagepluginloader.h
new file mode 100644
index 00000000..55ffe933
--- /dev/null
+++ b/src/utilities/imageeditor/canvas/imagepluginloader.h
@@ -0,0 +1,79 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-06-04
+ * Description : image plugins loader for image editor.
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Copyright (C) 2004-2007 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.
+ *
+ * ============================================================ */
+
+#ifndef IMAGEPLUGINLOADER_H
+#define IMAGEPLUGINLOADER_H
+
+// TQt includes.
+
+#include <tqobject.h>
+#include <tqptrlist.h>
+#include <tqstring.h>
+#include <tqvaluelist.h>
+#include <tqpair.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+#include "imageplugin.h"
+
+namespace Digikam
+{
+
+class SplashScreen;
+class ImagePluginLoaderPrivate;
+
+class DIGIKAM_EXPORT ImagePluginLoader : public TQObject
+{
+
+public:
+
+ ImagePluginLoader(TQObject *parent, SplashScreen *splash=0);
+ ~ImagePluginLoader();
+
+ static ImagePluginLoader* instance();
+
+ TQPtrList<ImagePlugin> pluginList();
+ void loadPluginsFromList(const TQStringList& list);
+
+ // Return true if plugin library is loaded in memory.
+ // 'libraryName' is internal plugin library name not i18n.
+ bool pluginLibraryIsLoaded(const TQString& libraryName);
+
+ ImagePlugin* pluginInstance(const TQString& libraryName);
+
+private:
+
+ ImagePlugin* pluginIsLoaded(const TQString& name);
+
+private:
+
+ static ImagePluginLoader *m_instance;
+
+ ImagePluginLoaderPrivate *d;
+};
+
+} // namespace Digikam
+
+#endif /* IMAGEPLUGINLOADER_H */
diff --git a/src/utilities/imageeditor/canvas/iofilesettingscontainer.h b/src/utilities/imageeditor/canvas/iofilesettingscontainer.h
new file mode 100644
index 00000000..360299b3
--- /dev/null
+++ b/src/utilities/imageeditor/canvas/iofilesettingscontainer.h
@@ -0,0 +1,84 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-01-03
+ * Description : IO file Settings Container.
+ *
+ * Copyright (C) 2006-2008 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.
+ *
+ * ============================================================ */
+
+#ifndef IOFILESETTINGSCONTAINER_H
+#define IOFILESETTINGSCONTAINER_H
+
+// Local includes.
+
+#include "drawdecoding.h"
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class DIGIKAM_EXPORT IOFileSettingsContainer
+{
+
+public:
+
+ IOFileSettingsContainer()
+ {
+ JPEGCompression = 75;
+ JPEGSubSampling = 1; // Medium subsampling
+ PNGCompression = 9;
+ TIFFCompression = false;
+ JPEG2000Compression = 75;
+ JPEG2000LossLess = true;
+ useRAWImport = true;
+ };
+
+ ~IOFileSettingsContainer(){};
+
+public:
+
+ // JPEG quality value.
+ int JPEGCompression;
+
+ // JPEG chroma subsampling value.
+ int JPEGSubSampling;
+
+ // PNG compression value.
+ int PNGCompression;
+
+ // TIFF deflat compression.
+ bool TIFFCompression;
+
+ // JPEG2000 quality value.
+ int JPEG2000Compression;
+
+ // JPEG2000 lossless compression.
+ bool JPEG2000LossLess;
+
+ // Use Raw Import tool to load a RAW picture.
+ bool useRAWImport;
+
+ // ------------------------------------------------------
+ // RAW File decoding options :
+
+ DRawDecoding rawDecodingSettings;
+};
+
+} // namespace Digikam
+
+#endif // IOFILESETTINGSCONTAINER_H
diff --git a/src/utilities/imageeditor/canvas/undoaction.cpp b/src/utilities/imageeditor/canvas/undoaction.cpp
new file mode 100644
index 00000000..bb4ff756
--- /dev/null
+++ b/src/utilities/imageeditor/canvas/undoaction.cpp
@@ -0,0 +1,185 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2005-02-06
+ * Description : undo actions manager for image editor.
+ *
+ * Copyright (C) 2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Copyright (C) 2005 by Joern Ahrens <joern.ahrens@kdemail.net>
+ *
+ * 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.
+ *
+ * ============================================================ */
+
+// Local includes.
+
+#include "ddebug.h"
+#include "dimginterface.h"
+#include "undoaction.h"
+
+namespace Digikam
+{
+
+UndoAction::UndoAction(DImgInterface* iface)
+ : m_iface(iface)
+{
+ m_title = i18n("unknown");
+}
+
+UndoAction::~UndoAction()
+{
+}
+
+TQString UndoAction::getTitle() const
+{
+ return m_title;
+}
+
+UndoActionRotate::UndoActionRotate(DImgInterface* iface,
+ UndoActionRotate::Angle angle)
+ : UndoAction(iface), m_angle(angle)
+{
+ switch(m_angle)
+ {
+ case(R90):
+ m_title = i18n("Rotate 90 Degrees");
+ break;
+ case(R180):
+ m_title = i18n("Rotate 180 Degrees");
+ break;
+ case(R270):
+ m_title = i18n("Rotate 270 Degrees");
+ break;
+ }
+}
+
+UndoActionRotate::~UndoActionRotate()
+{
+}
+
+void UndoActionRotate::rollBack()
+{
+ switch(m_angle)
+ {
+ case(R90):
+ m_iface->rotate270(false);
+ return;
+ case(R180):
+ m_iface->rotate180(false);
+ return;
+ case(R270):
+ m_iface->rotate90(false);
+ return;
+ default:
+ DWarning() << "Unknown rotate angle specified" << endl;
+ }
+}
+
+void UndoActionRotate::execute()
+{
+ switch(m_angle)
+ {
+ case R90:
+ m_iface->rotate90(false);
+ return;
+ case R180:
+ m_iface->rotate180(false);
+ return;
+ case R270:
+ m_iface->rotate270(false);
+ return;
+ default:
+ DWarning() << "Unknown rotate angle specified" << endl;
+ }
+}
+
+UndoActionFlip::UndoActionFlip(DImgInterface* iface,
+ UndoActionFlip::Direction dir)
+ : UndoAction(iface), m_dir(dir)
+{
+ if(m_dir ==TQt::Horizontal)
+ m_title = i18n("Flip Horizontal");
+ else if(m_dir ==TQt::Vertical)
+ m_title = i18n("Flip Vertical");
+}
+
+UndoActionFlip::~UndoActionFlip()
+{
+}
+
+void UndoActionFlip::rollBack()
+{
+ switch(m_dir)
+ {
+ case TQt::Horizontal:
+ m_iface->flipHoriz(false);
+ return;
+ case TQt::Vertical:
+ m_iface->flipVert(false);
+ return;
+ default:
+ DWarning() << "Unknown flip direction specified" << endl;
+ }
+}
+
+void UndoActionFlip::execute()
+{
+ rollBack();
+}
+
+UndoActionBCG::UndoActionBCG(DImgInterface* iface,
+ double oldGamma, double oldBrightness,
+ double oldContrast, double newGamma,
+ double newBrightness, double newContrast)
+ : UndoAction(iface), m_oldGamma(oldGamma), m_oldBrightness(oldBrightness),
+ m_oldContrast(oldContrast), m_newGamma(newGamma), m_newBrightness(newBrightness),
+ m_newContrast(newContrast)
+{
+ m_title = i18n("Brightness,Contrast,Gamma");
+}
+
+UndoActionBCG::~UndoActionBCG()
+{
+}
+
+void UndoActionBCG::rollBack()
+{
+ m_iface->changeBCG(m_oldGamma, m_oldBrightness, m_oldContrast);
+}
+
+void UndoActionBCG::execute()
+{
+ m_iface->changeBCG(m_newGamma, m_newBrightness, m_newContrast);
+}
+
+UndoActionIrreversible::UndoActionIrreversible(DImgInterface* iface,
+ const TQString &title)
+ : UndoAction(iface)
+{
+ m_title = title;
+}
+
+UndoActionIrreversible::~UndoActionIrreversible()
+{
+}
+
+void UndoActionIrreversible::rollBack()
+{
+}
+
+void UndoActionIrreversible::execute()
+{
+}
+
+} // namespace Digikam
diff --git a/src/utilities/imageeditor/canvas/undoaction.h b/src/utilities/imageeditor/canvas/undoaction.h
new file mode 100644
index 00000000..5f29486e
--- /dev/null
+++ b/src/utilities/imageeditor/canvas/undoaction.h
@@ -0,0 +1,144 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2005-02-06
+ * Description : undo actions manager for image editor.
+ *
+ * Copyright (C) 2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Copyright (C) 2005 by Joern Ahrens <joern.ahrens@kdemail.net>
+ *
+ * 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.
+ *
+ * ============================================================ */
+
+#ifndef UNDOACTION_H
+#define UNDOACTION_H
+
+// KDE includes.
+
+#include <tdelocale.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class DImgInterface;
+
+class DIGIKAM_EXPORT UndoAction
+{
+
+public:
+
+ UndoAction(DImgInterface* iface);
+ virtual ~UndoAction();
+
+ virtual void rollBack() = 0;
+ virtual void execute() = 0;
+
+ TQString getTitle() const;
+
+protected:
+
+ DImgInterface *m_iface;
+ TQString m_title;
+};
+
+class DIGIKAM_EXPORT UndoActionRotate : public UndoAction
+{
+
+public:
+
+ enum Angle
+ {
+ R90,
+ R180,
+ R270
+ };
+
+ UndoActionRotate(DImgInterface* iface, Angle angle);
+ ~UndoActionRotate();
+
+ void rollBack();
+ void execute();
+
+private:
+
+ int m_angle;
+};
+
+class DIGIKAM_EXPORT UndoActionFlip : public UndoAction
+{
+
+public:
+
+ enum Direction
+ {
+ Horizontal,
+ Vertical
+ };
+
+ UndoActionFlip(DImgInterface* iface, Direction dir);
+ ~UndoActionFlip();
+
+ void rollBack();
+ void execute();
+
+private:
+
+ int m_dir;
+};
+
+class DIGIKAM_EXPORT UndoActionBCG : public UndoAction
+{
+
+public:
+
+ UndoActionBCG(DImgInterface* iface,
+ double oldGamma, double oldBrightness,
+ double oldContrast, double newGamma,
+ double newBrightness, double newContrast);
+ ~UndoActionBCG();
+
+ void rollBack();
+ void execute();
+
+private:
+
+ double m_oldGamma;
+ double m_oldBrightness;
+ double m_oldContrast;
+ double m_newGamma;
+ double m_newBrightness;
+ double m_newContrast;
+};
+
+class DIGIKAM_EXPORT UndoActionIrreversible : public UndoAction
+{
+
+public:
+
+ UndoActionIrreversible(DImgInterface* iface,
+ const TQString &caller=i18n("Unknown"));
+ ~UndoActionIrreversible();
+
+ void rollBack();
+ void execute();
+};
+
+} // namespace Digikam
+
+#endif /* UNDOACTION_H */
diff --git a/src/utilities/imageeditor/canvas/undocache.cpp b/src/utilities/imageeditor/canvas/undocache.cpp
new file mode 100644
index 00000000..5f36ae75
--- /dev/null
+++ b/src/utilities/imageeditor/canvas/undocache.cpp
@@ -0,0 +1,178 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2005-02-05
+ * Description : undo cache manager for image editor
+ *
+ * Copyright (C) 2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Copyright (C) 2005 by Joern Ahrens <joern.ahrens@kdemail.net>
+ *
+ * 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.
+ *
+ * ============================================================ */
+
+// C Ansi includes.
+
+extern "C"
+{
+#include <unistd.h>
+}
+
+// TQt includes.
+
+#include <tqcstring.h>
+#include <tqstring.h>
+#include <tqfile.h>
+#include <tqdatastream.h>
+#include <tqstringlist.h>
+
+// KDE includes.
+
+#include <kstandarddirs.h>
+#include <tdeaboutdata.h>
+#include <kinstance.h>
+#include <tdeglobal.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "undocache.h"
+
+namespace Digikam
+{
+
+class UndoCachePriv
+{
+public:
+
+ TQString cachePrefix;
+ TQStringList cacheFilenames;
+};
+
+UndoCache::UndoCache()
+{
+ d = new UndoCachePriv;
+
+ TQString cacheDir;
+ cacheDir = locateLocal("cache",
+ TDEGlobal::instance()->aboutData()->programName() + '/');
+
+ d->cachePrefix = TQString("%1undocache-%2")
+ .arg(cacheDir)
+ .arg(getpid());
+}
+
+UndoCache::~UndoCache()
+{
+ clear();
+ delete d;
+}
+
+/**
+ * delete all cache files
+ */
+void UndoCache::clear()
+{
+ for (TQStringList::iterator it = d->cacheFilenames.begin();
+ it != d->cacheFilenames.end(); ++it)
+ {
+ ::unlink(TQFile::encodeName(*it));
+ }
+
+ d->cacheFilenames.clear();
+}
+
+/**
+ * write the data into a cache file
+ */
+bool UndoCache::putData(int level, int w, int h, int bytesDepth, uchar* data)
+{
+ TQString cacheFile = TQString("%1-%2.bin")
+ .arg(d->cachePrefix)
+ .arg(level);
+
+ TQFile file(cacheFile);
+
+ if (file.exists() || !file.open(IO_WriteOnly))
+ return false;
+
+ TQDataStream ds(&file);
+ ds << w;
+ ds << h;
+ ds << bytesDepth;
+
+ TQByteArray ba(w*h*bytesDepth);
+ memcpy (ba.data(), data, w*h*bytesDepth);
+ ds << ba;
+
+ file.close();
+
+ d->cacheFilenames.append(cacheFile);
+
+ return true;
+}
+
+/**
+ * get the data from a cache file
+ */
+uchar* UndoCache::getData(int level, int& w, int& h, int& bytesDepth, bool del)
+{
+ TQString cacheFile = TQString("%1-%2.bin")
+ .arg(d->cachePrefix)
+ .arg(level);
+
+ TQFile file(cacheFile);
+ if (!file.open(IO_ReadOnly))
+ return 0;
+
+ TQDataStream ds(&file);
+ ds >> w;
+ ds >> h;
+ ds >> bytesDepth;
+
+ uchar *data = new uchar[w*h*bytesDepth];
+ if (!data)
+ return 0;
+
+ TQByteArray ba(w*h*bytesDepth);
+ ds >> ba;
+ memcpy (data, ba.data(), w*h*bytesDepth);
+
+ file.close();
+
+ if(del)
+ {
+ ::unlink(TQFile::encodeName(cacheFile));
+ d->cacheFilenames.remove(cacheFile);
+ }
+
+ return data;
+}
+
+/**
+ * delete a cache file
+ */
+void UndoCache::erase(int level)
+{
+ TQString cacheFile = TQString("%1-%2.bin")
+ .arg(d->cachePrefix)
+ .arg(level);
+
+ if(d->cacheFilenames.find(cacheFile) == d->cacheFilenames.end())
+ return;
+
+ ::unlink(TQFile::encodeName(cacheFile));
+}
+
+} // namespace Digikam
diff --git a/src/utilities/imageeditor/canvas/undocache.h b/src/utilities/imageeditor/canvas/undocache.h
new file mode 100644
index 00000000..732c7c3e
--- /dev/null
+++ b/src/utilities/imageeditor/canvas/undocache.h
@@ -0,0 +1,62 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2005-02-05
+ * Description : undo cache manager for image editor.
+ *
+ * Copyright (C) 2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Copyright (C) 2005 by Joern Ahrens <joern.ahrens@kdemail.net>
+ *
+ * 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.
+ *
+ * ============================================================ */
+
+#ifndef UNDOCACHE_H
+#define UNDOCACHE_H
+
+// TQt includes.
+
+#include <tqglobal.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class UndoCachePriv;
+
+class DIGIKAM_EXPORT UndoCache
+{
+
+public:
+
+ UndoCache();
+ ~UndoCache();
+
+ void clear();
+ bool putData(int level, int w, int h, int bytesDepth, uchar* data);
+ uchar *getData(int level, int& w, int& h, int& bytesDepth, bool del=true);
+
+ void erase(int level);
+
+private:
+
+ UndoCachePriv *d;
+};
+
+} // namespace Digikam
+
+#endif /* UNDOCACHE_H */
diff --git a/src/utilities/imageeditor/canvas/undomanager.cpp b/src/utilities/imageeditor/canvas/undomanager.cpp
new file mode 100644
index 00000000..87085d5d
--- /dev/null
+++ b/src/utilities/imageeditor/canvas/undomanager.cpp
@@ -0,0 +1,253 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2005-02-06
+ * Description : an image editor actions undo/redo manager
+ *
+ * Copyright (C) 2005-2006 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Copyright (C) 2005-2006 Joern Ahrens <joern.ahrens@kdemail.net>
+ *
+ * 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.
+ *
+ * ============================================================ */
+
+// C++ includes.
+
+#include <typeinfo>
+#include <climits>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "dimginterface.h"
+#include "undoaction.h"
+#include "undocache.h"
+#include "undomanager.h"
+
+namespace Digikam
+{
+
+class UndoManagerPriv
+{
+
+public:
+
+ UndoManagerPriv()
+ {
+ dimgiface = 0;
+ undoCache = 0;
+ origin = 0;
+ }
+
+ TQValueList<UndoAction*> undoActions;
+ TQValueList<UndoAction*> redoActions;
+ int origin;
+
+ UndoCache *undoCache;
+
+ DImgInterface *dimgiface;
+};
+
+UndoManager::UndoManager(DImgInterface* iface)
+{
+ d = new UndoManagerPriv;
+ d->dimgiface = iface;
+ d->undoCache = new UndoCache;
+}
+
+UndoManager::~UndoManager()
+{
+ clear(true);
+ delete d->undoCache;
+ delete d;
+}
+
+void UndoManager::addAction(UndoAction* action)
+{
+ if (!action)
+ return;
+
+ // All redo actions are invalid now
+ clearRedoActions();
+
+ d->undoActions.push_back(action);
+
+ if (typeid(*action) == typeid(UndoActionIrreversible))
+ {
+ int w = d->dimgiface->origWidth();
+ int h = d->dimgiface->origHeight();
+ int bytesDepth = d->dimgiface->bytesDepth();
+ uchar* data = d->dimgiface->getImage();
+
+ d->undoCache->putData(d->undoActions.size(), w, h, bytesDepth, data);
+ }
+
+ // if origin is at one of the redo action that are now invalid,
+ // it is no longer reachable
+ if (d->origin < 0)
+ d->origin = INT_MAX;
+ else
+ d->origin++;
+}
+
+void UndoManager::undo()
+{
+ if (d->undoActions.isEmpty())
+ return;
+
+ UndoAction* action = d->undoActions.back();
+
+ if (typeid(*action) == typeid(UndoActionIrreversible))
+ {
+ // Save the current state for the redo operation
+
+ int w = d->dimgiface->origWidth();
+ int h = d->dimgiface->origHeight();
+ int bytesDepth = d->dimgiface->bytesDepth();
+ uchar* data = d->dimgiface->getImage();
+
+ d->undoCache->putData(d->undoActions.size() + 1, w, h, bytesDepth, data);
+
+ // And now, undo the action
+
+ int newW, newH, newBytesDepth;
+ uchar *newData = d->undoCache->getData(d->undoActions.size(), newW, newH, newBytesDepth, false);
+ if (newData)
+ {
+ d->dimgiface->putImage(newData, newW, newH, newBytesDepth == 8 ? true : false);
+ delete [] newData;
+ }
+ }
+ else
+ {
+ action->rollBack();
+ }
+
+ d->undoActions.pop_back();
+ d->redoActions.push_back(action);
+ d->origin--;
+}
+
+void UndoManager::redo()
+{
+ if(d->redoActions.isEmpty())
+ return;
+
+ UndoAction *action = d->redoActions.back();
+
+ if(typeid(*action) == typeid(UndoActionIrreversible))
+ {
+ int w, h, bytesDepth;
+ uchar *data = d->undoCache->getData(d->undoActions.size() + 2, w, h, bytesDepth, false);
+ if (data)
+ {
+ d->dimgiface->putImage(data, w, h, bytesDepth == 8 ? true : false);
+ delete[] data;
+ }
+ }
+ else
+ {
+ action->execute();
+ }
+
+ d->redoActions.pop_back();
+ d->undoActions.push_back(action);
+ d->origin++;
+}
+
+void UndoManager::clear(bool clearCache)
+{
+ clearUndoActions();
+ clearRedoActions();
+ setOrigin();
+
+ if(clearCache)
+ d->undoCache->clear();
+}
+
+void UndoManager::clearUndoActions()
+{
+ UndoAction *action;
+ TQValueList<UndoAction*>::iterator it;
+
+ for(it = d->undoActions.begin(); it != d->undoActions.end(); ++it)
+ {
+ action = *it;
+ delete action;
+ }
+ d->undoActions.clear();
+}
+
+void UndoManager::clearRedoActions()
+{
+ if(!anyMoreRedo())
+ return;
+
+ UndoAction *action;
+ TQValueList<UndoAction*>::iterator it;
+
+ // get the level of the first redo action
+ int level = d->undoActions.size() + 1;
+ for(it = d->redoActions.begin(); it != d->redoActions.end(); ++it)
+ {
+ action = *it;
+ d->undoCache->erase(level);
+ delete action;
+ level++;
+ }
+ d->undoCache->erase(level);
+ d->redoActions.clear();
+}
+
+bool UndoManager::anyMoreUndo()
+{
+ return !d->undoActions.isEmpty();
+}
+
+bool UndoManager::anyMoreRedo()
+{
+ return !d->redoActions.isEmpty();
+}
+
+void UndoManager::getUndoHistory(TQStringList &titles)
+{
+ TQValueList<UndoAction*>::iterator it;
+
+ for(it = d->undoActions.begin(); it != d->undoActions.end(); ++it)
+ {
+ titles.push_front((*it)->getTitle());
+ }
+}
+
+void UndoManager::getRedoHistory(TQStringList &titles)
+{
+ TQValueList<UndoAction*>::iterator it;
+
+ for(it = d->redoActions.begin(); it != d->redoActions.end(); ++it)
+ {
+ titles.push_front((*it)->getTitle());
+ }
+}
+
+bool UndoManager::isAtOrigin()
+{
+ return d->origin == 0;
+}
+
+void UndoManager::setOrigin()
+{
+ d->origin = 0;
+}
+
+} // namespace Digikam
diff --git a/src/utilities/imageeditor/canvas/undomanager.h b/src/utilities/imageeditor/canvas/undomanager.h
new file mode 100644
index 00000000..a36ba12f
--- /dev/null
+++ b/src/utilities/imageeditor/canvas/undomanager.h
@@ -0,0 +1,76 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2005-02-06
+ * Description : an image editor actions undo/redo manager
+ *
+ * Copyright (C) 2005-2006 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Copyright (C) 2005-2006 by Joern Ahrens <joern.ahrens@kdemail.net>
+ *
+ * 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.
+ *
+ * ============================================================ */
+
+#ifndef UNDOMANAGER_H
+#define UNDOMANAGER_H
+
+// TQt includes.
+
+#include <tqstringlist.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class DImgInterface;
+class UndoManagerPriv;
+class UndoAction;
+
+class DIGIKAM_EXPORT UndoManager
+{
+
+public:
+
+ UndoManager(DImgInterface* iface);
+ ~UndoManager();
+
+ void undo();
+ void redo();
+
+ void clear(bool clearCache=true);
+ bool anyMoreUndo();
+ bool anyMoreRedo();
+ void getUndoHistory(TQStringList &titles);
+ void getRedoHistory(TQStringList &titles);
+ bool isAtOrigin();
+ void setOrigin();
+
+ void addAction(UndoAction* action);
+
+private:
+
+ void clearUndoActions();
+ void clearRedoActions();
+
+private:
+
+ UndoManagerPriv *d;
+};
+
+} // namespace Digikam
+
+#endif /* UNDOMANAGER_H */