krita

kis_paint_device.cc

00001 /*
00002  *  Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
00003  *  Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  */
00019 #include <qrect.h>
00020 #include <qwmatrix.h>
00021 #include <qimage.h>
00022 #include <qdatetime.h>
00023 #include <qapplication.h>
00024 #include <qvaluelist.h>
00025 #include <qtimer.h>
00026 
00027 #include <kcommand.h>
00028 #include <klocale.h>
00029 #include <kdebug.h>
00030 
00031 #include <KoStore.h>
00032 
00033 #include "kis_global.h"
00034 #include "kis_types.h"
00035 #include "kis_painter.h"
00036 #include "kis_fill_painter.h"
00037 #include "kis_undo_adapter.h"
00038 #include "kis_iterator.h"
00039 #include "kis_iterators_pixel.h"
00040 #include "kis_iteratorpixeltrait.h"
00041 #include "kis_random_accessor.h"
00042 #include "kis_random_sub_accessor.h"
00043 #include "kis_profile.h"
00044 #include "kis_color.h"
00045 #include "kis_integer_maths.h"
00046 #include "kis_colorspace_factory_registry.h"
00047 #include "kis_selection.h"
00048 #include "kis_layer.h"
00049 #include "kis_paint_device_iface.h"
00050 #include "kis_paint_device.h"
00051 #include "kis_datamanager.h"
00052 #include "kis_memento.h"
00053 
00054 #include "kis_exif_info.h"
00055 
00056 namespace {
00057 
00058     class KisPaintDeviceCommand : public KNamedCommand {
00059         typedef KNamedCommand super;
00060 
00061     public:
00062         KisPaintDeviceCommand(const QString& name, KisPaintDeviceSP paintDevice);
00063         virtual ~KisPaintDeviceCommand() {}
00064 
00065         virtual void execute() = 0;
00066         virtual void unexecute() = 0;
00067 
00068     protected:
00069         void setUndo(bool undo);
00070 
00071         KisPaintDeviceSP m_paintDevice;
00072     };
00073 
00074     KisPaintDeviceCommand::KisPaintDeviceCommand(const QString& name, KisPaintDeviceSP paintDevice) :
00075         super(name), m_paintDevice(paintDevice)
00076     {
00077     }
00078 
00079     void KisPaintDeviceCommand::setUndo(bool undo)
00080     {
00081         if (m_paintDevice->undoAdapter()) {
00082             m_paintDevice->undoAdapter()->setUndo(undo);
00083         }
00084     }
00085 
00086     class MoveCommand : public KNamedCommand {
00087         typedef KNamedCommand super;
00088 
00089     public:
00090         MoveCommand(KisPaintDeviceSP device, const QPoint& oldpos, const QPoint& newpos);
00091         virtual ~MoveCommand();
00092 
00093         virtual void execute();
00094         virtual void unexecute();
00095 
00096     private:
00097         void moveTo(const QPoint& pos);
00098         void undoOff();
00099         void undoOn();
00100 
00101     private:
00102         KisPaintDeviceSP m_device;
00103         QPoint m_oldPos;
00104         QPoint m_newPos;
00105     };
00106 
00107     MoveCommand::MoveCommand(KisPaintDeviceSP device, const QPoint& oldpos, const QPoint& newpos) :
00108         super(i18n("Move Layer"))
00109     {
00110         m_device = device;
00111         m_oldPos = oldpos;
00112         m_newPos = newpos;
00113     }
00114 
00115     MoveCommand::~MoveCommand()
00116     {
00117     }
00118 
00119     void MoveCommand::undoOff()
00120     {
00121         if (m_device->undoAdapter()) {
00122             m_device->undoAdapter()->setUndo(false);
00123         }
00124     }
00125 
00126     void MoveCommand::undoOn()
00127     {
00128         if (m_device->undoAdapter()) {
00129             m_device->undoAdapter()->setUndo(true);
00130         }
00131     }
00132 
00133     void MoveCommand::execute()
00134     {
00135         undoOff();
00136         moveTo(m_newPos);
00137         undoOn();
00138     }
00139 
00140     void MoveCommand::unexecute()
00141     {
00142         undoOff();
00143         moveTo(m_oldPos);
00144         undoOn();
00145     }
00146 
00147     void MoveCommand::moveTo(const QPoint& pos)
00148     {
00149         m_device->move(pos.x(), pos.y());
00150     }
00151 
00152     class KisConvertLayerTypeCmd : public KNamedCommand {
00153         typedef KNamedCommand super;
00154 
00155     public:
00156         KisConvertLayerTypeCmd(KisUndoAdapter *adapter, KisPaintDeviceSP paintDevice,
00157                        KisDataManagerSP beforeData, KisColorSpace * beforeColorSpace,
00158                        KisDataManagerSP afterData, KisColorSpace * afterColorSpace
00159                 ) : super(i18n("Convert Layer Type"))
00160             {
00161                 m_adapter = adapter;
00162                 m_paintDevice = paintDevice;
00163                 m_beforeData = beforeData;
00164                 m_beforeColorSpace = beforeColorSpace;
00165                 m_afterData = afterData;
00166                 m_afterColorSpace = afterColorSpace;
00167             }
00168 
00169         virtual ~KisConvertLayerTypeCmd()
00170             {
00171             }
00172 
00173     public:
00174         virtual void execute()
00175             {
00176                 m_adapter->setUndo(false);
00177                 m_paintDevice->setData(m_afterData, m_afterColorSpace);
00178                 m_adapter->setUndo(true);
00179             }
00180 
00181         virtual void unexecute()
00182             {
00183                 m_adapter->setUndo(false);
00184                 m_paintDevice->setData(m_beforeData, m_beforeColorSpace);
00185                 m_adapter->setUndo(true);
00186             }
00187 
00188     private:
00189         KisUndoAdapter *m_adapter;
00190 
00191         KisPaintDeviceSP m_paintDevice;
00192 
00193         KisDataManagerSP m_beforeData;
00194         KisColorSpace * m_beforeColorSpace;
00195 
00196         KisDataManagerSP m_afterData;
00197         KisColorSpace * m_afterColorSpace;
00198     };
00199 
00200 }
00201 
00202 KisPaintDevice::KisPaintDevice(KisColorSpace * colorSpace, const char * name) :
00203         QObject(0, name), KShared(), m_exifInfo(0)
00204 {
00205     if (colorSpace == 0) {
00206         kdWarning(41001) << "Cannot create paint device without colorstrategy!\n";
00207         return;
00208     }
00209     m_longRunningFilterTimer = 0;
00210     m_dcop = 0;
00211 
00212     m_x = 0;
00213     m_y = 0;
00214 
00215     m_pixelSize = colorSpace->pixelSize();
00216     m_nChannels = colorSpace->nChannels();
00217 
00218     Q_UINT8* defPixel = new Q_UINT8 [ m_pixelSize ];
00219     colorSpace->fromQColor(Qt::black, OPACITY_TRANSPARENT, defPixel);
00220 
00221     m_datamanager = new KisDataManager(m_pixelSize, defPixel);
00222     delete [] defPixel;
00223 
00224     Q_CHECK_PTR(m_datamanager);
00225     m_extentIsValid = true;
00226 
00227     m_parentLayer = 0;
00228 
00229     m_colorSpace = colorSpace;
00230 
00231     m_hasSelection = false;
00232     m_selectionDeselected = false;
00233     m_selection = 0;
00234 
00235     m_longRunningFilters = colorSpace->createBackgroundFilters();
00236     if (!m_longRunningFilters.isEmpty()) {
00237         m_longRunningFilterTimer = new QTimer(this);
00238         connect(m_longRunningFilterTimer, SIGNAL(timeout()), this, SLOT(runBackgroundFilters()));
00239         m_longRunningFilterTimer->start(800);
00240     }
00241 }
00242 
00243 KisPaintDevice::KisPaintDevice(KisLayer *parent, KisColorSpace * colorSpace, const char * name) :
00244         QObject(0, name), KShared(), m_exifInfo(0)
00245 {
00246 
00247     m_longRunningFilterTimer = 0;
00248     m_dcop = 0;
00249 
00250     m_x = 0;
00251     m_y = 0;
00252 
00253     m_hasSelection = false;
00254     m_selectionDeselected = false;
00255     m_selection = 0;
00256 
00257     m_parentLayer = parent;
00258 
00259     if (colorSpace == 0 && parent != 0 && parent->image() != 0) {
00260         m_colorSpace = parent->image()->colorSpace();
00261     }
00262     else {
00263         m_colorSpace = colorSpace;
00264     }
00265 
00266     Q_ASSERT( m_colorSpace );
00267 
00268     m_pixelSize = m_colorSpace->pixelSize();
00269     m_nChannels = m_colorSpace->nChannels();
00270 
00271     Q_UINT8* defPixel = new Q_UINT8[ m_pixelSize ];
00272     m_colorSpace->fromQColor(Qt::black, OPACITY_TRANSPARENT, defPixel);
00273 
00274     m_datamanager = new KisDataManager(m_pixelSize, defPixel);
00275     delete [] defPixel;
00276     Q_CHECK_PTR(m_datamanager);
00277     m_extentIsValid = true;
00278 
00279 
00280     m_longRunningFilters = m_colorSpace->createBackgroundFilters();
00281     if (!m_longRunningFilters.isEmpty()) {
00282         m_longRunningFilterTimer = new QTimer(this);
00283         connect(m_longRunningFilterTimer, SIGNAL(timeout()), this, SLOT(runBackgroundFilters()));
00284         m_longRunningFilterTimer->start(800);
00285     }
00286 }
00287 
00288 
00289 KisPaintDevice::KisPaintDevice(const KisPaintDevice& rhs) : QObject(), KShared(rhs)
00290 {
00291     if (this != &rhs) {
00292         m_longRunningFilterTimer = 0;
00293         m_parentLayer = 0;
00294         m_dcop = rhs.m_dcop;
00295         if (rhs.m_datamanager) {
00296             m_datamanager = new KisDataManager(*rhs.m_datamanager);
00297             Q_CHECK_PTR(m_datamanager);
00298         }
00299         else {
00300             kdWarning() << "rhs " << rhs.name() << " has no datamanager\n";
00301         }
00302         m_extentIsValid = rhs.m_extentIsValid;
00303         m_x = rhs.m_x;
00304         m_y = rhs.m_y;
00305         m_colorSpace = rhs.m_colorSpace;
00306         m_hasSelection = false;
00307         m_selection = 0;
00308         m_pixelSize = rhs.m_pixelSize;
00309         m_nChannels = rhs.m_nChannels;
00310         if(rhs.m_exifInfo)
00311         {
00312             m_exifInfo = new KisExifInfo(*rhs.m_exifInfo);
00313         }
00314         else {
00315             m_exifInfo = 0;
00316         }
00317     }
00318 }
00319 
00320 KisPaintDevice::~KisPaintDevice()
00321 {
00322     delete m_dcop;
00323     delete m_longRunningFilterTimer;
00324     QValueList<KisFilter*>::iterator it;
00325     QValueList<KisFilter*>::iterator end = m_longRunningFilters.end();
00326     for (it = m_longRunningFilters.begin(); it != end; ++it) {
00327         KisFilter * f = (*it);
00328         delete f;
00329     }
00330     m_longRunningFilters.clear();
00331     //delete m_exifInfo;
00332 }
00333 
00334 DCOPObject *KisPaintDevice::dcopObject()
00335 {
00336     if (!m_dcop) {
00337         m_dcop = new KisPaintDeviceIface(this);
00338         Q_CHECK_PTR(m_dcop);
00339     }
00340     return m_dcop;
00341 }
00342 
00343 KisLayer *KisPaintDevice::parentLayer() const
00344 {
00345     return m_parentLayer;
00346 }
00347 
00348 void KisPaintDevice::setParentLayer(KisLayer *parentLayer)
00349 {
00350     m_parentLayer = parentLayer;
00351 }
00352 
00353 void KisPaintDevice::setDirty(const QRect & rc)
00354 {
00355     if (m_parentLayer) m_parentLayer->setDirty(rc);
00356 }
00357 
00358 void KisPaintDevice::setDirty()
00359 {
00360     if (m_parentLayer) m_parentLayer->setDirty();
00361 }
00362 
00363 KisImage *KisPaintDevice::image() const
00364 {
00365     if (m_parentLayer) {
00366         return m_parentLayer->image();
00367     } else {
00368         return 0;
00369     }
00370 }
00371 
00372 
00373 void KisPaintDevice::move(Q_INT32 x, Q_INT32 y)
00374 {
00375     QRect dirtyRect = extent();
00376 
00377     m_x = x;
00378     m_y = y;
00379 
00380     dirtyRect |= extent();
00381 
00382     if(m_selection)
00383     {
00384         m_selection->setX(x);
00385         m_selection->setY(y);
00386     }
00387 
00388     setDirty(dirtyRect);
00389 
00390     emit positionChanged(this);
00391 }
00392 
00393 void KisPaintDevice::move(const QPoint& pt)
00394 {
00395     move(pt.x(), pt.y());
00396 }
00397 
00398 KNamedCommand * KisPaintDevice::moveCommand(Q_INT32 x, Q_INT32 y)
00399 {
00400     KNamedCommand * cmd = new MoveCommand(this, QPoint(m_x, m_y), QPoint(x, y));
00401     Q_CHECK_PTR(cmd);
00402     cmd->execute();
00403     return cmd;
00404 }
00405 
00406 void KisPaintDevice::extent(Q_INT32 &x, Q_INT32 &y, Q_INT32 &w, Q_INT32 &h) const
00407 {
00408     m_datamanager->extent(x, y, w, h);
00409     x += m_x;
00410     y += m_y;
00411 }
00412 
00413 QRect KisPaintDevice::extent() const
00414 {
00415     Q_INT32 x, y, w, h;
00416     extent(x, y, w, h);
00417     return QRect(x, y, w, h);
00418 }
00419 
00420 bool KisPaintDevice::extentIsValid() const
00421 {
00422     return m_extentIsValid;
00423 }
00424 
00425 void KisPaintDevice::setExtentIsValid(bool isValid)
00426 {
00427     m_extentIsValid = isValid;
00428 }
00429 
00430 void KisPaintDevice::exactBounds(Q_INT32 &x, Q_INT32 &y, Q_INT32 &w, Q_INT32 &h) const
00431 {
00432     QRect r = exactBounds();
00433     x = r.x();
00434     y = r.y();
00435     w = r.width();
00436     h = r.height();
00437 }
00438 
00439 QRect KisPaintDevice::exactBoundsOldMethod() const
00440 {
00441     Q_INT32 x, y, w, h, boundX, boundY, boundW, boundH;
00442     extent(x, y, w, h);
00443 
00444     extent(boundX, boundY, boundW, boundH);
00445 
00446     const Q_UINT8* defaultPixel = m_datamanager->defaultPixel();
00447 
00448     bool found = false;
00449 
00450     for (Q_INT32 y2 = y; y2 < y + h ; ++y2) {
00451         KisHLineIterator it = const_cast<KisPaintDevice *>(this)->createHLineIterator(x, y2, w, false);
00452         while (!it.isDone() && found == false) {
00453             if (memcmp(it.rawData(), defaultPixel, m_pixelSize) != 0) {
00454                 boundY = y2;
00455                 found = true;
00456                 break;
00457             }
00458             ++it;
00459         }
00460         if (found) break;
00461     }
00462 
00463     found = false;
00464 
00465     for (Q_INT32 y2 = y + h; y2 > y ; --y2) {
00466         KisHLineIterator it = const_cast<KisPaintDevice *>(this)->createHLineIterator(x, y2, w, false);
00467         while (!it.isDone() && found == false) {
00468             if (memcmp(it.rawData(), defaultPixel, m_pixelSize) != 0) {
00469                 boundH = y2 - boundY + 1;
00470                 found = true;
00471                 break;
00472             }
00473             ++it;
00474         }
00475         if (found) break;
00476     }
00477     found = false;
00478 
00479     for (Q_INT32 x2 = x; x2 < x + w ; ++x2) {
00480         KisVLineIterator it = const_cast<KisPaintDevice *>(this)->createVLineIterator(x2, y, h, false);
00481         while (!it.isDone() && found == false) {
00482             if (memcmp(it.rawData(), defaultPixel, m_pixelSize) != 0) {
00483                 boundX = x2;
00484                 found = true;
00485                 break;
00486             }
00487             ++it;
00488         }
00489         if (found) break;
00490     }
00491 
00492     found = false;
00493 
00494     // Look for right edge )
00495     for (Q_INT32 x2 = x + w; x2 > x ; --x2) {
00496         KisVLineIterator it = const_cast<KisPaintDevice *>(this)->createVLineIterator(x2, y, h, false);
00497         while (!it.isDone() && found == false) {
00498             if (memcmp(it.rawData(), defaultPixel, m_pixelSize) != 0) {
00499                 boundW = x2 - boundX + 1; // XXX: I commented this
00500                                           // +1 out, but why? It
00501                                           // should be correct, since
00502                                           // we've found the first
00503                                           // pixel that should be
00504                                           // included, and it should
00505                                           // be added to the width.
00506                 found = true;
00507                 break;
00508             }
00509             ++it;
00510         }
00511         if (found) break;
00512     }
00513 
00514     return QRect(boundX, boundY, boundW, boundH);
00515 }
00516 
00517 QRect KisPaintDevice::exactBoundsImprovedOldMethod() const
00518 {
00519     // Solution n°2
00520     Q_INT32  x, y, w, h, boundX2, boundY2, boundW2, boundH2;
00521     extent(x, y, w, h);
00522     extent(boundX2, boundY2, boundW2, boundH2);
00523 
00524     const Q_UINT8* defaultPixel = m_datamanager->defaultPixel();
00525     bool found = false;
00526     {
00527         KisHLineIterator it = const_cast<KisPaintDevice *>(this)->createHLineIterator(x, y, w, false);
00528         for (Q_INT32 y2 = y; y2 < y + h ; ++y2) {
00529             while (!it.isDone() && found == false) {
00530                 if (memcmp(it.rawData(), defaultPixel, m_pixelSize) != 0) {
00531                     boundY2 = y2;
00532                     found = true;
00533                     break;
00534                 }
00535                 ++it;
00536             }
00537             if (found) break;
00538             it.nextRow();
00539         }
00540     }
00541 
00542     found = false;
00543 
00544     for (Q_INT32 y2 = y + h; y2 > y ; --y2) {
00545         KisHLineIterator it = const_cast<KisPaintDevice *>(this)->createHLineIterator(x, y2, w, false);
00546         while (!it.isDone() && found == false) {
00547             if (memcmp(it.rawData(), defaultPixel, m_pixelSize) != 0) {
00548                 boundH2 = y2 - boundY2 + 1;
00549                 found = true;
00550                 break;
00551             }
00552             ++it;
00553         }
00554         if (found) break;
00555     }
00556     found = false;
00557 
00558     {
00559         KisVLineIterator it = const_cast<KisPaintDevice *>(this)->createVLineIterator(x, boundY2, boundH2, false);
00560         for (Q_INT32 x2 = x; x2 < x + w ; ++x2) {
00561             while (!it.isDone() && found == false) {
00562                 if (memcmp(it.rawData(), defaultPixel, m_pixelSize) != 0) {
00563                     boundX2 = x2;
00564                     found = true;
00565                     break;
00566                 }
00567                 ++it;
00568             }
00569             if (found) break;
00570             it.nextCol();
00571         }
00572     }
00573 
00574     found = false;
00575 
00576     // Look for right edge )
00577     {
00578         for (Q_INT32 x2 = x + w; x2 > x ; --x2) {
00579             KisVLineIterator it = const_cast<KisPaintDevice *>(this)->createVLineIterator(/*x + w*/ x2, boundY2, boundH2, false);
00580             while (!it.isDone() && found == false) {
00581                 if (memcmp(it.rawData(), defaultPixel, m_pixelSize) != 0) {
00582                     boundW2 = x2 - boundX2 + 1; // XXX: I commented this
00583                                             // +1 out, but why? It
00584                                             // should be correct, since
00585                                             // we've found the first
00586                                             // pixel that should be
00587                                             // included, and it should
00588                                             // be added to the width.
00589                     found = true;
00590                     break;
00591                 }
00592                 ++it;
00593             }
00594             if (found) break;
00595         }
00596     }
00597     return QRect(boundX2, boundY2, boundW2, boundH2);
00598 }
00599 
00600 
00601 QRect KisPaintDevice::exactBounds() const
00602 {
00603     // XXX: Look, this code should never have gone into a release,
00604     // right?
00605     //QRect r1 = exactBoundsOldMethod();
00606     QRect r2 = exactBoundsImprovedOldMethod();
00607     //if(r1 != r2)
00608     //{
00609     //    kdDebug() << "EXACTBOUNDSERROR : " << r1 << " " << r2 << endl;
00610     //}
00611     return r2;
00612 }
00613 
00614 void KisPaintDevice::crop(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h)
00615 {
00616      m_datamanager->setExtent(x - m_x, y - m_y, w, h);
00617 }
00618 
00619 
00620 void KisPaintDevice::crop(QRect r)
00621 {
00622     r.moveBy(-m_x, -m_y); m_datamanager->setExtent(r);
00623 }
00624 
00625 void KisPaintDevice::clear()
00626 {
00627     m_datamanager->clear();
00628 }
00629 
00630 void KisPaintDevice::fill(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, const Q_UINT8 *fillPixel)
00631 {
00632     m_datamanager->clear(x, y, w, h, fillPixel);
00633 }
00634 
00635 void KisPaintDevice::mirrorX()
00636 {
00637     QRect r;
00638     if (hasSelection()) {
00639         r = selection()->selectedRect();
00640     }
00641     else {
00642         r = exactBounds();
00643     }
00644 
00645     for (Q_INT32 y = r.top(); y <= r.bottom(); ++y) {
00646         KisHLineIteratorPixel srcIt = createHLineIterator(r.x(), y, r.width(), false);
00647         KisHLineIteratorPixel dstIt = createHLineIterator(r.x(), y, r.width(), true);
00648 
00649         dstIt += r.width() - 1;
00650 
00651         while (!srcIt.isDone()) {
00652             if (srcIt.isSelected()) {
00653                 memcpy(dstIt.rawData(), srcIt.oldRawData(), m_pixelSize);
00654             }
00655             ++srcIt;
00656             --dstIt;
00657 
00658         }
00659     }
00660     if (m_parentLayer) {
00661         m_parentLayer->setDirty(r);
00662     }
00663 }
00664 
00665 void KisPaintDevice::mirrorY()
00666 {
00667     /* Read a line from bottom to top and and from top to bottom and write their values to each other */
00668     QRect r;
00669     if (hasSelection()) {
00670         r = selection()->selectedRect();
00671     }
00672     else {
00673         r = exactBounds();
00674     }
00675 
00676 
00677     Q_INT32 y1, y2;
00678     for (y1 = r.top(), y2 = r.bottom(); y1 <= r.bottom(); ++y1, --y2) {
00679         KisHLineIteratorPixel itTop = createHLineIterator(r.x(), y1, r.width(), true);
00680         KisHLineIteratorPixel itBottom = createHLineIterator(r.x(), y2, r.width(), false);
00681         while (!itTop.isDone() && !itBottom.isDone()) {
00682             if (itBottom.isSelected()) {
00683                 memcpy(itTop.rawData(), itBottom.oldRawData(), m_pixelSize);
00684             }
00685             ++itBottom;
00686             ++itTop;
00687         }
00688     }
00689 
00690     if (m_parentLayer) {
00691         m_parentLayer->setDirty(r);
00692     }
00693 }
00694 
00695 KisMementoSP KisPaintDevice::getMemento()
00696 {
00697     return m_datamanager->getMemento();
00698 }
00699 
00700 void KisPaintDevice::rollback(KisMementoSP memento) { m_datamanager->rollback(memento); }
00701 
00702 void KisPaintDevice::rollforward(KisMementoSP memento) { m_datamanager->rollforward(memento); }
00703 
00704 bool KisPaintDevice::write(KoStore *store)
00705 {
00706     bool retval = m_datamanager->write(store);
00707     emit ioProgress(100);
00708 
00709         return retval;
00710 }
00711 
00712 bool KisPaintDevice::read(KoStore *store)
00713 {
00714     bool retval = m_datamanager->read(store);
00715     emit ioProgress(100);
00716 
00717         return retval;
00718 }
00719 
00720 void KisPaintDevice::convertTo(KisColorSpace * dstColorSpace, Q_INT32 renderingIntent)
00721 {
00722     kdDebug(41004) << "Converting " << name() << " to " << dstColorSpace->id().id() << " from "
00723               << m_colorSpace->id().id() << "\n";
00724     if ( (colorSpace()->id() == dstColorSpace->id()) )
00725     {
00726         return;
00727     }
00728 
00729     KisPaintDevice dst(dstColorSpace);
00730     dst.setX(getX());
00731     dst.setY(getY());
00732 
00733     Q_INT32 x, y, w, h;
00734     extent(x, y, w, h);
00735 
00736     for (Q_INT32 row = y; row < y + h; ++row) {
00737 
00738         Q_INT32 column = x;
00739         Q_INT32 columnsRemaining = w;
00740 
00741         while (columnsRemaining > 0) {
00742 
00743             Q_INT32 numContiguousDstColumns = dst.numContiguousColumns(column, row, row);
00744             Q_INT32 numContiguousSrcColumns = numContiguousColumns(column, row, row);
00745 
00746             Q_INT32 columns = QMIN(numContiguousDstColumns, numContiguousSrcColumns);
00747             columns = QMIN(columns, columnsRemaining);
00748 
00749             //const Q_UINT8 *srcData = pixel(column, row);
00750             //Q_UINT8 *dstData = dst.writablePixel(column, row);
00751             KisHLineIteratorPixel srcIt = createHLineIterator(column, row, columns, false);
00752             KisHLineIteratorPixel dstIt = dst.createHLineIterator(column, row, columns, true);
00753 
00754             const Q_UINT8 *srcData = srcIt.rawData();
00755             Q_UINT8 *dstData = dstIt.rawData();
00756 
00757 
00758             m_colorSpace->convertPixelsTo(srcData, dstData, dstColorSpace, columns, renderingIntent);
00759 
00760             column += columns;
00761             columnsRemaining -= columns;
00762         }
00763     }
00764 
00765     KisDataManagerSP oldData = m_datamanager;
00766     KisColorSpace *oldColorSpace = m_colorSpace;
00767 
00768     setData(dst.m_datamanager, dstColorSpace);
00769 
00770     if (undoAdapter() && undoAdapter()->undo()) {
00771         undoAdapter()->addCommand(new KisConvertLayerTypeCmd(undoAdapter(), this, oldData, oldColorSpace, m_datamanager, m_colorSpace));
00772     }
00773 }
00774 
00775 void KisPaintDevice::setProfile(KisProfile * profile)
00776 {
00777     if (profile == 0) return;
00778 
00779     KisColorSpace * dstSpace =
00780             KisMetaRegistry::instance()->csRegistry()->getColorSpace( colorSpace()->id(),
00781                                                                       profile);
00782     if (dstSpace)
00783         m_colorSpace = dstSpace;
00784 
00785 }
00786 
00787 void KisPaintDevice::setData(KisDataManagerSP data, KisColorSpace * colorSpace)
00788 {
00789     m_datamanager = data;
00790     m_colorSpace = colorSpace;
00791     m_pixelSize = m_colorSpace->pixelSize();
00792     m_nChannels = m_colorSpace->nChannels();
00793 
00794     if (m_parentLayer) {
00795         m_parentLayer->setDirty(extent());
00796         m_parentLayer->notifyPropertyChanged();
00797     }
00798 }
00799 
00800 KisUndoAdapter *KisPaintDevice::undoAdapter() const
00801 {
00802     if (m_parentLayer && m_parentLayer->image()) {
00803         return m_parentLayer->image()->undoAdapter();
00804     }
00805     return 0;
00806 }
00807 
00808 void KisPaintDevice::convertFromQImage(const QImage& image, const QString &srcProfileName,
00809                                            Q_INT32 offsetX, Q_INT32 offsetY)
00810 {
00811     QImage img = image;
00812 
00813     // Krita is little-endian inside.
00814     if (img.bitOrder() == QImage::LittleEndian) {
00815     img = img.convertBitOrder(QImage::BigEndian);
00816     }
00817     kdDebug() << k_funcinfo << img.bitOrder()<< endl;
00818     // Krita likes bgra (convertDepth returns *this is the img is alread 32 bits)
00819     img = img.convertDepth( 32 );
00820 #if 0
00821     // XXX: Apply import profile
00822     if (colorSpace() == KisMetaRegistry::instance()->csRegistry() ->getColorSpace(KisID("RGBA",""),"")) {
00823         writeBytes(img.bits(), 0, 0, img.width(), img.height());
00824     }
00825     else {
00826 #endif
00827         Q_UINT8 * dstData = new Q_UINT8[img.width() * img.height() * pixelSize()];
00828         KisMetaRegistry::instance()->csRegistry()
00829                 ->getColorSpace(KisID("RGBA",""),srcProfileName)->
00830                         convertPixelsTo(img.bits(), dstData, colorSpace(), img.width() * img.height());
00831         writeBytes(dstData, offsetX, offsetY, img.width(), img.height());
00832 //    }
00833 }
00834 
00835 QImage KisPaintDevice::convertToQImage(KisProfile *  dstProfile, float exposure)
00836 {
00837     Q_INT32 x1;
00838     Q_INT32 y1;
00839     Q_INT32 w;
00840     Q_INT32 h;
00841 
00842     x1 = - getX();
00843     y1 = - getY();
00844 
00845     if (image()) {
00846         w = image()->width();
00847         h = image()->height();
00848     }
00849     else {
00850         extent(x1, y1, w, h);
00851     }
00852 
00853     return convertToQImage(dstProfile, x1, y1, w, h, exposure);
00854 }
00855 
00856 // XXX: is this faster than building the QImage ourselves? It makes
00857 QImage KisPaintDevice::convertToQImage(KisProfile *  dstProfile, Q_INT32 x1, Q_INT32 y1, Q_INT32 w, Q_INT32 h, float exposure)
00858 {
00859     if (w < 0)
00860         return QImage();
00861 
00862     if (h < 0)
00863         return QImage();
00864 
00865     Q_UINT8 * data = new Q_UINT8 [w * h * m_pixelSize];
00866     Q_CHECK_PTR(data);
00867 
00868     // XXX: Is this really faster than converting line by line and building the QImage directly?
00869     //      This copies potentially a lot of data.
00870     readBytes(data, x1, y1, w, h);
00871     QImage image = colorSpace()->convertToQImage(data, w, h, dstProfile, INTENT_PERCEPTUAL, exposure);
00872     delete[] data;
00873 
00874     return image;
00875 }
00876 
00877 KisPaintDeviceSP KisPaintDevice::createThumbnailDevice(Q_INT32 w, Q_INT32 h)
00878 {
00879     KisPaintDeviceSP thumbnail = new KisPaintDevice(colorSpace(), "thumbnail");
00880 
00881     thumbnail->clear();
00882 
00883     int srcw, srch;
00884     if( image() )
00885     {
00886         srcw = image()->width();
00887         srch = image()->height();
00888     }
00889     else
00890     {
00891         const QRect e = exactBounds();
00892         srcw = e.width();
00893         srch = e.height();
00894     }
00895 
00896     if (w > srcw)
00897     {
00898         w = srcw;
00899         h = Q_INT32(double(srcw) / w * h);
00900     }
00901     if (h > srch)
00902     {
00903         h = srch;
00904         w = Q_INT32(double(srch) / h * w);
00905     }
00906 
00907     if (srcw > srch)
00908         h = Q_INT32(double(srch) / srcw * w);
00909     else if (srch > srcw)
00910         w = Q_INT32(double(srcw) / srch * h);
00911 
00912     for (Q_INT32 y=0; y < h; ++y) {
00913         Q_INT32 iY = (y * srch ) / h;
00914         for (Q_INT32 x=0; x < w; ++x) {
00915             Q_INT32 iX = (x * srcw ) / w;
00916             thumbnail->setPixel(x, y, colorAt(iX, iY));
00917         }
00918     }
00919 
00920     return thumbnail;
00921 
00922 }
00923 
00924 
00925 QImage KisPaintDevice::createThumbnail(Q_INT32 w, Q_INT32 h)
00926 {
00927     int srcw, srch;
00928     if( image() )
00929     {
00930         srcw = image()->width();
00931         srch = image()->height();
00932     }
00933     else
00934     {
00935         const QRect e = extent();
00936         srcw = e.width();
00937         srch = e.height();
00938     }
00939 
00940     if (w > srcw)
00941     {
00942         w = srcw;
00943         h = Q_INT32(double(srcw) / w * h);
00944     }
00945     if (h > srch)
00946     {
00947         h = srch;
00948         w = Q_INT32(double(srch) / h * w);
00949     }
00950 
00951     if (srcw > srch)
00952         h = Q_INT32(double(srch) / srcw * w);
00953     else if (srch > srcw)
00954         w = Q_INT32(double(srcw) / srch * h);
00955 
00956     QColor c;
00957     Q_UINT8 opacity;
00958     QImage img(w,h,32);
00959 
00960     for (Q_INT32 y=0; y < h; ++y) {
00961         Q_INT32 iY = (y * srch ) / h;
00962         for (Q_INT32 x=0; x < w; ++x) {
00963             Q_INT32 iX = (x * srcw ) / w;
00964             pixel(iX, iY, &c, &opacity);
00965             const QRgb rgb = c.rgb();
00966             img.setPixel(x, y, qRgba(qRed(rgb), qGreen(rgb), qBlue(rgb), opacity));
00967         }
00968     }
00969 
00970     return img;
00971 }
00972 
00973 KisRectIteratorPixel KisPaintDevice::createRectIterator(Q_INT32 left, Q_INT32 top, Q_INT32 w, Q_INT32 h, bool writable)
00974 {
00975     if(hasSelection())
00976         return KisRectIteratorPixel(this, m_datamanager, m_selection->m_datamanager, left, top, w, h, m_x, m_y, writable);
00977     else
00978         return KisRectIteratorPixel(this, m_datamanager, NULL, left, top, w, h, m_x, m_y, writable);
00979 }
00980 
00981 KisHLineIteratorPixel  KisPaintDevice::createHLineIterator(Q_INT32 x, Q_INT32 y, Q_INT32 w, bool writable)
00982 {
00983     if(hasSelection())
00984         return KisHLineIteratorPixel(this, m_datamanager, m_selection->m_datamanager, x, y, w, m_x, m_y, writable);
00985     else
00986         return KisHLineIteratorPixel(this, m_datamanager, NULL, x, y, w, m_x, m_y, writable);
00987 }
00988 
00989 KisVLineIteratorPixel  KisPaintDevice::createVLineIterator(Q_INT32 x, Q_INT32 y, Q_INT32 h, bool writable)
00990 {
00991     if(hasSelection())
00992         return KisVLineIteratorPixel(this, m_datamanager, m_selection->m_datamanager, x, y, h, m_x, m_y, writable);
00993     else
00994         return KisVLineIteratorPixel(this, m_datamanager, NULL, x, y, h, m_x, m_y, writable);
00995 
00996 }
00997 
00998 KisRandomAccessorPixel KisPaintDevice::createRandomAccessor(Q_INT32 x, Q_INT32 y, bool writable) {
00999     if(hasSelection())
01000         return KisRandomAccessorPixel(m_datamanager, m_selection->m_datamanager, x, y, m_x, m_y, writable);
01001     else
01002         return KisRandomAccessorPixel(m_datamanager, NULL, x, y, m_x, m_y, writable);
01003 }
01004 
01005 KisRandomSubAccessorPixel KisPaintDevice::createRandomSubAccessor()
01006 {
01007     return KisRandomSubAccessorPixel(this);
01008 }
01009 
01010 void KisPaintDevice::emitSelectionChanged()
01011 {
01012     if (m_parentLayer && m_parentLayer->image()) {
01013         m_parentLayer->image()->slotSelectionChanged();
01014     }
01015 }
01016 
01017 void KisPaintDevice::emitSelectionChanged(const QRect& r)
01018 {
01019     if (m_parentLayer && m_parentLayer->image()) {
01020         m_parentLayer->image()->slotSelectionChanged(r);
01021     }
01022 }
01023 
01024 KisSelectionSP KisPaintDevice::selection()
01025 {
01026     if ( m_selectionDeselected && m_selection ) {
01027         m_selectionDeselected = false;
01028     }
01029     else if (!m_selection) {
01030         m_selection = new KisSelection(this);
01031         Q_CHECK_PTR(m_selection);
01032         m_selection->setX(m_x);
01033         m_selection->setY(m_y);
01034     }
01035     m_hasSelection = true;
01036 
01037     return m_selection;
01038 }
01039 
01040 
01041 bool KisPaintDevice::hasSelection()
01042 {
01043     return m_hasSelection;
01044 }
01045 
01046 bool KisPaintDevice::selectionDeselected()
01047 {
01048     return m_selectionDeselected;
01049 }
01050 
01051 
01052 void KisPaintDevice::deselect()
01053 {
01054     if (m_selection && m_hasSelection) {
01055         m_hasSelection = false;
01056         m_selectionDeselected = true;
01057     }
01058 }
01059 
01060 void KisPaintDevice::reselect()
01061 {
01062     m_hasSelection = true;
01063     m_selectionDeselected = false;
01064 }
01065 
01066 void KisPaintDevice::addSelection(KisSelectionSP selection) {
01067 
01068     KisPainter painter(this->selection().data());
01069     QRect r = selection->selectedExactRect();
01070     painter.bitBlt(r.x(), r.y(), COMPOSITE_OVER, selection.data(), r.x(), r.y(), r.width(), r.height());
01071     painter.end();
01072 }
01073 
01074 void KisPaintDevice::subtractSelection(KisSelectionSP selection) {
01075     KisPainter painter(this->selection().data());
01076     selection->invert();
01077 
01078     QRect r = selection->selectedExactRect();
01079     painter.bitBlt(r.x(), r.y(), COMPOSITE_ERASE, selection.data(), r.x(), r.y(), r.width(), r.height());
01080 
01081     selection->invert();
01082     painter.end();
01083 }
01084 
01085 void KisPaintDevice::clearSelection()
01086 {
01087     if (!hasSelection()) return;
01088 
01089     QRect r = m_selection->selectedExactRect();
01090 
01091     if (r.isValid()) {
01092 
01093         for (Q_INT32 y = 0; y < r.height(); y++) {
01094 
01095             KisHLineIterator devIt = createHLineIterator(r.x(), r.y() + y, r.width(), true);
01096             KisHLineIterator selectionIt = m_selection->createHLineIterator(r.x(), r.y() + y, r.width(), false);
01097 
01098             while (!devIt.isDone()) {
01099                 // XXX: Optimize by using stretches
01100 
01101                 m_colorSpace->applyInverseAlphaU8Mask( devIt.rawData(), selectionIt.rawData(), 1);
01102 
01103                 ++devIt;
01104                 ++selectionIt;
01105             }
01106         }
01107 
01108         if (m_parentLayer) {
01109             m_parentLayer->setDirty(r);
01110         }
01111     }
01112 }
01113 
01114 void KisPaintDevice::applySelectionMask(KisSelectionSP mask)
01115 {
01116     QRect r = mask->selectedRect();
01117     crop(r);
01118 
01119     for (Q_INT32 y = r.top(); y <= r.bottom(); ++y) {
01120 
01121         KisHLineIterator pixelIt = createHLineIterator(r.x(), y, r.width(), true);
01122         KisHLineIterator maskIt = mask->createHLineIterator(r.x(), y, r.width(), false);
01123 
01124         while (!pixelIt.isDone()) {
01125             // XXX: Optimize by using stretches
01126 
01127             m_colorSpace->applyAlphaU8Mask( pixelIt.rawData(), maskIt.rawData(), 1);
01128 
01129             ++pixelIt;
01130             ++maskIt;
01131         }
01132     }
01133 }
01134 
01135 KisSelectionSP KisPaintDevice::setSelection( KisSelectionSP selection)
01136 {
01137     if (selection) {
01138         KisSelectionSP oldSelection = m_selection;
01139         m_selection = selection;
01140         m_hasSelection = true;
01141         return oldSelection;
01142     }
01143     else return 0;
01144 }
01145 
01146 bool KisPaintDevice::pixel(Q_INT32 x, Q_INT32 y, QColor *c, Q_UINT8 *opacity)
01147 {
01148     KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, false);
01149 
01150     Q_UINT8 *pix = iter.rawData();
01151 
01152     if (!pix) return false;
01153 
01154     colorSpace()->toQColor(pix, c, opacity);
01155 
01156     return true;
01157 }
01158 
01159 
01160 bool KisPaintDevice::pixel(Q_INT32 x, Q_INT32 y, KisColor * kc)
01161 {
01162     KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, false);
01163 
01164     Q_UINT8 *pix = iter.rawData();
01165 
01166     if (!pix) return false;
01167 
01168     kc->setColor(pix, m_colorSpace);
01169 
01170     return true;
01171 }
01172 
01173 KisColor KisPaintDevice::colorAt(Q_INT32 x, Q_INT32 y)
01174 {
01175     //return KisColor(m_datamanager->pixel(x - m_x, y - m_y), m_colorSpace);
01176     KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, true);
01177     return KisColor(iter.rawData(), m_colorSpace);
01178 }
01179 
01180 bool KisPaintDevice::setPixel(Q_INT32 x, Q_INT32 y, const QColor& c, Q_UINT8  opacity)
01181 {
01182     KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, true);
01183 
01184     colorSpace()->fromQColor(c, opacity, iter.rawData());
01185 
01186     return true;
01187 }
01188 
01189 bool KisPaintDevice::setPixel(Q_INT32 x, Q_INT32 y, const KisColor& kc)
01190 {
01191     Q_UINT8 * pix;
01192     if (kc.colorSpace() != m_colorSpace) {
01193         KisColor kc2 (kc, m_colorSpace);
01194         pix = kc2.data();
01195     }
01196     else {
01197         pix = kc.data();
01198     }
01199 
01200     KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, true);
01201     memcpy(iter.rawData(), pix, m_colorSpace->pixelSize());
01202 
01203     return true;
01204 }
01205 
01206 
01207 Q_INT32 KisPaintDevice::numContiguousColumns(Q_INT32 x, Q_INT32 minY, Q_INT32 maxY)
01208 {
01209     return m_datamanager->numContiguousColumns(x - m_x, minY - m_y, maxY - m_y);
01210 }
01211 
01212 Q_INT32 KisPaintDevice::numContiguousRows(Q_INT32 y, Q_INT32 minX, Q_INT32 maxX)
01213 {
01214     return m_datamanager->numContiguousRows(y - m_y, minX - m_x, maxX - m_x);
01215 }
01216 
01217 Q_INT32 KisPaintDevice::rowStride(Q_INT32 x, Q_INT32 y)
01218 {
01219     return m_datamanager->rowStride(x - m_x, y - m_y);
01220 }
01221 
01222 const Q_UINT8* KisPaintDevice::pixel(Q_INT32 x, Q_INT32 y)
01223 {
01224     return m_datamanager->pixel(x - m_x, y - m_y);
01225 }
01226 
01227 Q_UINT8* KisPaintDevice::writablePixel(Q_INT32 x, Q_INT32 y)
01228 {
01229     return m_datamanager->writablePixel(x - m_x, y - m_y);
01230 }
01231 
01232 void KisPaintDevice::setX(Q_INT32 x)
01233 {
01234     m_x = x;
01235     if(m_selection && m_selection != this)
01236         m_selection->setX(x);
01237 }
01238 
01239 void KisPaintDevice::setY(Q_INT32 y)
01240 {
01241     m_y = y;
01242     if(m_selection && m_selection != this)
01243         m_selection->setY(y);
01244 }
01245 
01246 
01247 void KisPaintDevice::readBytes(Q_UINT8 * data, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h)
01248 {
01249     m_datamanager->readBytes(data, x - m_x, y - m_y, w, h);
01250 }
01251 
01252 void KisPaintDevice::writeBytes(const Q_UINT8 * data, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h)
01253 {
01254     m_datamanager->writeBytes( data, x - m_x, y - m_y, w, h);
01255 }
01256 
01257 
01258 KisDataManagerSP KisPaintDevice::dataManager() const
01259 {
01260     return m_datamanager;
01261 }
01262 
01263 KisExifInfo* KisPaintDevice::exifInfo()
01264 {
01265     if(!m_exifInfo)
01266         m_exifInfo = new KisExifInfo();
01267     return m_exifInfo;
01268 }
01269 
01270 void KisPaintDevice::runBackgroundFilters()
01271 {
01272     QRect rc = extent();
01273     if (!m_longRunningFilters.isEmpty()) {
01274         QValueList<KisFilter*>::iterator it;
01275         QValueList<KisFilter*>::iterator end = m_longRunningFilters.end();
01276         for (it = m_longRunningFilters.begin(); it != end; ++it) {
01277             (*it)->process(this, this, 0, rc);
01278         }
01279     }
01280     if (m_parentLayer) m_parentLayer->setDirty(rc);
01281 }
01282 
01283 #include "kis_paint_device.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys