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