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