00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
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
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;
00498
00499
00500
00501
00502
00503
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
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
00709 if (img.bitOrder() == QImage::LittleEndian) {
00710 img = img.convertBitOrder(QImage::BigEndian);
00711 }
00712
00713
00714 img = img.convertDepth( 32 );
00715 #if 0
00716
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
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
00764
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
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
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"