diff options
Diffstat (limited to 'krita/core/kis_paint_device.h')
-rw-r--r-- | krita/core/kis_paint_device.h | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/krita/core/kis_paint_device.h b/krita/core/kis_paint_device.h new file mode 100644 index 00000000..3b1dcfe7 --- /dev/null +++ b/krita/core/kis_paint_device.h @@ -0,0 +1,596 @@ +/* + * copyright (c) 2002 patrick julien <freak@codepimps.org> + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ +#ifndef KIS_PAINT_DEVICE_IMPL_H_ +#define KIS_PAINT_DEVICE_IMPL_H_ + +#include <qcolor.h> +#include <qobject.h> +#include <qpixmap.h> +#include <qptrlist.h> +#include <qrect.h> +#include <qvaluelist.h> +#include <qstring.h> + +#include "kis_types.h" +#include "kdebug.h" +#include "kis_global.h" +#include "kis_image.h" +#include "kis_colorspace.h" +#include "kis_canvas_controller.h" +#include "kis_color.h" +#include <koffice_export.h> + +class DCOPObject; + +class QImage; +class QSize; +class QPoint; +class QWMatrix; +class QTimer; + +class KNamedCommand; + +class KoStore; + +class KisExifInfo; +class KisHLineIteratorPixel; +class KisImage; +class KisRectIteratorPixel; +class KisVLineIteratorPixel; +class KisRandomAccessorPixel; +class KisRandomSubAccessorPixel; +class KisUndoAdapter; +class KisFilter; +class KisDataManager; +typedef KSharedPtr<KisDataManager> KisDataManagerSP; + +class KisMemento; +typedef KSharedPtr<KisMemento> KisMementoSP; + + +/** + * A paint device contains the actual pixel data and offers methods + * to read and write pixels. A paint device has an integer x,y position + * (i.e., are not positioned on the image with sub-pixel accuracy). + * A KisPaintDevice doesn't have any fixed size, the size change dynamicaly + * when pixels are accessed by an iterator. + */ +class KRITACORE_EXPORT KisPaintDevice + : public QObject + , public KShared +{ + + Q_OBJECT + +public: + + /** + * Create a new paint device with the specified colorspace. + * + * @param colorSpace the colorspace of this paint device + * @param name for debugging purposes + */ + KisPaintDevice(KisColorSpace * colorSpace, const char * name = 0); + + /** + * Create a new paint device with the specified colorspace. The + * parentLayer will be notified of changes to this paint device. + * + * @param parentLayer the layer that contains this paint device. + * @param colorSpace the colorspace of this paint device + * @param name for debugging purposes + */ + KisPaintDevice(KisLayer *parentLayer, KisColorSpace * colorSpace, const char * name = 0); + + KisPaintDevice(const KisPaintDevice& rhs); + virtual ~KisPaintDevice(); + virtual DCOPObject *dcopObject(); + + void lock(bool lock) { m_lock = lock; } + +public: + + /** + * Write the pixels of this paint device into the specified file store. + */ + virtual bool write(KoStore *store); + + /** + * Fill this paint device with the pixels from the specified file store. + */ + virtual bool read(KoStore *store); + +public: + + /** + * Moves the device to these new coordinates (so no incremental move or so) + */ + virtual void move(Q_INT32 x, Q_INT32 y); + + /** + * Convenience method for the above + */ + virtual void move(const QPoint& pt); + + /** + * Move the paint device to the specified location and make it possible to + * undo the move. + */ + virtual KNamedCommand * moveCommand(Q_INT32 x, Q_INT32 y); + + /** + * Returns true of x,y is within the extent of this paint device + */ + bool contains(Q_INT32 x, Q_INT32 y) const; + + /** + * Convenience method for the above + */ + bool contains(const QPoint& pt) const; + + /** + * Retrieve the bounds of the paint device. The size is not exact, + * but may be larger if the underlying datamanager works that way. + * For instance, the tiled datamanager keeps the extent to the nearest + * multiple of 64. + */ + virtual void extent(Q_INT32 &x, Q_INT32 &y, Q_INT32 &w, Q_INT32 &h) const; + virtual QRect extent() const; + + /** + * XXX: This should be a temporay hack, awaiting a proper fix. + * + * Indicates whether the extent really represents the extent. For example, + * the KisBackground checkerboard pattern is generated by filling the + * default tile but it will return an empty extent. + */ + bool extentIsValid() const; + + /// Convience method for the above + void setExtentIsValid(bool isValid); + + /** + * Get the exact bounds of this paint device. This may be very slow, + * especially on larger paint devices because it does a linear scanline search. + */ + virtual void exactBounds(Q_INT32 &x, Q_INT32 &y, Q_INT32 &w, Q_INT32 &h) const; + virtual QRect exactBounds() const; + virtual QRect exactBoundsOldMethod() const; + virtual QRect exactBoundsImprovedOldMethod() const; + + /** + * Cut the paint device down to the specified rect + */ + void crop(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h); + + /// Convience method for the above + void crop(QRect r); + + /** + * Complete erase the current paint device. Its size will become 0. + */ + virtual void clear(); + + /** + * Fill the given rectangle with the given pixel. + */ + void fill(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, const Q_UINT8 *fillPixel); + + /** + * Read the bytes representing the rectangle described by x, y, w, h into + * data. If data is not big enough, Krita will gladly overwrite the rest + * of your precious memory. + * + * Since this is a copy, you need to make sure you have enough memory. + * + * Reading from areas not previously initialized will read the default + * pixel value into data but not initialize that region. + */ + virtual void readBytes(Q_UINT8 * data, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h); + + /** + * Copy the bytes in data into the rect specified by x, y, w, h. If the + * data is too small or uninitialized, Krita will happily read parts of + * memory you never wanted to be read. + * + * If the data is written to areas of the paint device not previously initialized, + * the paint device will grow. + */ + virtual void writeBytes(const Q_UINT8 * data, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h); + + /** + * Get the number of contiguous columns starting at x, valid for all values + * of y between minY and maxY. + */ + Q_INT32 numContiguousColumns(Q_INT32 x, Q_INT32 minY, Q_INT32 maxY); + + /** + * Get the number of contiguous rows starting at y, valid for all values + * of x between minX and maxX. + */ + Q_INT32 numContiguousRows(Q_INT32 y, Q_INT32 minX, Q_INT32 maxX); + + /** + * Get the row stride at pixel (x, y). This is the number of bytes to add to a + * pointer to pixel (x, y) to access (x, y + 1). + */ + Q_INT32 rowStride(Q_INT32 x, Q_INT32 y); + + /** + * Get a read-only pointer to pixel (x, y). + */ + KDE_DEPRECATED const Q_UINT8* pixel(Q_INT32 x, Q_INT32 y); + + /** + * Get a read-write pointer to pixel (x, y). + */ + KDE_DEPRECATED Q_UINT8* writablePixel(Q_INT32 x, Q_INT32 y); + + /** + * Converts the paint device to a different colorspace + */ + virtual void convertTo(KisColorSpace * dstColorSpace, Q_INT32 renderingIntent = INTENT_PERCEPTUAL); + + /** + * Changes the profile of the colorspace of this paint device to the given + * profile. If the given profile is 0, nothing happens. + */ + virtual void setProfile(KisProfile * profile); + + /** + * Fill this paint device with the data from img; starting at (offsetX, offsetY) + * @param srcProfileName name of the RGB profile to interpret the img as. "" is interpreted as sRGB + */ + virtual void convertFromQImage(const QImage& img, const QString &srcProfileName, Q_INT32 offsetX = 0, Q_INT32 offsetY = 0); + + /** + * Create an RGBA QImage from a rectangle in the paint device. + * + * @param x Left coordinate of the rectangle + * @param y Top coordinate of the rectangle + * @param w Width of the rectangle in pixels + * @param h Height of the rectangle in pixels + * @param dstProfile RGB profile to use in conversion. May be 0, in which + * case it's up to the colour strategy to choose a profile (most + * like sRGB). + * @param exposure The exposure setting used to render a preview of a high dynamic range image. + */ + virtual QImage convertToQImage(KisProfile * dstProfile, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, float exposure = 0.0f); + + /** + * Create an RGBA QImage from a rectangle in the paint device. The rectangle is defined by the parent image's bounds. + * + * @param dstProfile RGB profile to use in conversion. May be 0, in which + * case it's up to the colour strategy to choose a profile (most + * like sRGB). + * @param exposure The exposure setting used to render a preview of a high dynamic range image. + */ + virtual QImage convertToQImage(KisProfile * dstProfile, float exposure = 0.0f); + + /** + * Creates a paint device thumbnail of the paint device, retaining the aspect ratio. + * The width and height of the returned device won't exceed \p maxw and \p maxw, but they may be smaller. + */ + + KisPaintDeviceSP createThumbnailDevice(Q_INT32 w, Q_INT32 h); + + /** + * Creates a thumbnail of the paint device, retaining the aspect ratio. + * The width and height of the returned QImage won't exceed \p maxw and \p maxw, but they may be smaller. + * The colors are not corrected for display! + */ + virtual QImage createThumbnail(Q_INT32 maxw, Q_INT32 maxh); + + + /** + * Fill c and opacity with the values found at x and y. + * + * The color values will be transformed from the profile of + * this paint device to the display profile. + * + * @return true if the operation was succesful. + */ + bool pixel(Q_INT32 x, Q_INT32 y, QColor *c, Q_UINT8 *opacity); + + + /** + * Fill kc with the values found at x and y. This method differs + * from the above in using KisColor, which can be of any colorspace + * + * The color values will be transformed from the profile of + * this paint device to the display profile. + * + * @return true if the operation was succesful. + */ + bool pixel(Q_INT32 x, Q_INT32 y, KisColor * kc); + + /** + * Return the KisColor of the pixel at x,y. + */ + KisColor colorAt(Q_INT32 x, Q_INT32 y); + + /** + * Set the specified pixel to the specified color. Note that this + * bypasses KisPainter. the PaintDevice is here used as an equivalent + * to QImage, not QPixmap. This means that this is not undoable; also, + * there is no compositing with an existing value at this location. + * + * The color values will be transformed from the display profile to + * the paint device profile. + * + * Note that this will use 8-bit values and may cause a significant + * degradation when used on 16-bit or hdr quality images. + * + * @return true if the operation was succesful + * + */ + bool setPixel(Q_INT32 x, Q_INT32 y, const QColor& c, Q_UINT8 opacity); + + bool setPixel(Q_INT32 x, Q_INT32 y, const KisColor& kc); + + KisColorSpace * colorSpace() const; + + KisDataManagerSP dataManager() const; + + /** + * Replace the pixel data, color strategy, and profile. + */ + void setData(KisDataManagerSP data, KisColorSpace * colorSpace); + + /** + * The X offset of the paint device + */ + Q_INT32 getX() const; + + /** + * The Y offset of the paint device + */ + Q_INT32 getY() const; + + /** + * Return the X offset of the paint device + */ + void setX(Q_INT32 x); + + /** + * Return the Y offset of the paint device + */ + void setY(Q_INT32 y); + + + /** + * Return the number of bytes a pixel takes. + */ + virtual Q_INT32 pixelSize() const; + + /** + * Return the number of channels a pixel takes + */ + virtual Q_INT32 nChannels() const; + + /** + * Return the image that contains this paint device, or 0 if it is not + * part of an image. This is the same as calling parentLayer()->image(). + */ + KisImage *image() const; + + /** + * Returns the KisLayer that contains this paint device, or 0 if this is not + * part of a layer. + */ + KisLayer *parentLayer() const; + + /** + * Set the KisLayer that contains this paint device, or 0 if this is not + * part of a layer. + */ + void setParentLayer(KisLayer *parentLayer); + + /** + * Add the specified rect top the parent layer (if present) + */ + virtual void setDirty(const QRect & rc); + + /** + * Set the parent layer completely dirty, if this paint device has one. + */ + virtual void setDirty(); + + + /** + * Mirror the device along the X axis + */ + void mirrorX(); + /** + * Mirror the device along the Y axis + */ + void mirrorY(); + + KisMementoSP getMemento(); + void rollback(KisMementoSP memento); + void rollforward(KisMementoSP memento); + + /** + * This function return an iterator which points to the first pixel of an rectangle + */ + KisRectIteratorPixel createRectIterator(Q_INT32 left, Q_INT32 top, Q_INT32 w, Q_INT32 h, bool writable); + + /** + * This function return an iterator which points to the first pixel of a horizontal line + */ + KisHLineIteratorPixel createHLineIterator(Q_INT32 x, Q_INT32 y, Q_INT32 w, bool writable); + + /** + * This function return an iterator which points to the first pixel of a vertical line + */ + KisVLineIteratorPixel createVLineIterator(Q_INT32 x, Q_INT32 y, Q_INT32 h, bool writable); + + /** + * This function creates a random accessor which allow to randomly access any pixels on + * the paint device. + * <b>Note:</b> random access is way slower than iterators, allways use iterators whenever + * you can + */ + KisRandomAccessorPixel createRandomAccessor(Q_INT32 x, Q_INT32 y, bool writable); + + /** + * This function create a random accessor which can easily access to sub pixel values. + */ + KisRandomSubAccessorPixel createRandomSubAccessor(); + + /** Get the current selection or create one if this paintdevice hasn't got a selection yet. */ + KisSelectionSP selection(); + + /** Adds the specified selection to the currently active selection for this paintdevice */ + void addSelection(KisSelectionSP selection); + + /** Subtracts the specified selection from the currently active selection for this paindevice */ + void subtractSelection(KisSelectionSP selection); + + /** Whether there is a valid selection for this paintdevice. */ + bool hasSelection(); + + /** Whether the previous selection was deselected. */ + bool selectionDeselected(); + + /** Deselect the selection for this paintdevice. */ + void deselect(); + + /** Reinstates the old selection */ + void reselect(); + + /** Clear the selected pixels from the paint device */ + void clearSelection(); + + /** + * Apply a mask to the image data, i.e. multiply each pixel's opacity by its + * selectedness in the mask. + */ + void applySelectionMask(KisSelectionSP mask); + + /** + * Sets the selection of this paint device to the new selection, + * returns the old selection, if there was an old selection, + * otherwise 0 + */ + KisSelectionSP setSelection(KisSelectionSP selection); + + /** + * Notify the owning image that the current selection has changed. + */ + void emitSelectionChanged(); + + /** + * Notify the owning image that the current selection has changed. + * + * @param r the area for which the selection has changed + */ + void emitSelectionChanged(const QRect& r); + + + KisUndoAdapter *undoAdapter() const; + + /** + * Return the exifInfo associated with this layer. If no exif infos are + * available, the function will create it. + */ + KisExifInfo* exifInfo(); + /** + * This function return true if the layer has exif info associated with it. + */ + bool hasExifInfo() { return m_exifInfo != 0; } +signals: + void positionChanged(KisPaintDeviceSP device); + void ioProgress(Q_INT8 percentage); + void profileChanged(KisProfile * profile); + +private slots: + + void runBackgroundFilters(); + +private: + KisPaintDevice& operator=(const KisPaintDevice&); + +protected: + KisDataManagerSP m_datamanager; + +private: + /* The KisLayer that contains this paint device, or 0 if this is not + * part of a layer. + */ + KisLayer *m_parentLayer; + + bool m_extentIsValid; + + Q_INT32 m_x; + Q_INT32 m_y; + KisColorSpace * m_colorSpace; + // Cached for quick access + Q_INT32 m_pixelSize; + Q_INT32 m_nChannels; + + // Whether the selection is active + bool m_hasSelection; + bool m_selectionDeselected; + + // Contains the actual selection. For now, there can be only + // one selection per layer. XXX: is this a limitation? + KisSelectionSP m_selection; + + DCOPObject * m_dcop; + + KisExifInfo* m_exifInfo; + + QValueList<KisFilter*> m_longRunningFilters; + QTimer * m_longRunningFilterTimer; + + bool m_lock; +}; + +inline Q_INT32 KisPaintDevice::pixelSize() const +{ + Q_ASSERT(m_pixelSize > 0); + return m_pixelSize; +} + +inline Q_INT32 KisPaintDevice::nChannels() const +{ + Q_ASSERT(m_nChannels > 0); + return m_nChannels; +; +} + +inline KisColorSpace * KisPaintDevice::colorSpace() const +{ + Q_ASSERT(m_colorSpace != 0); + return m_colorSpace; +} + + +inline Q_INT32 KisPaintDevice::getX() const +{ + return m_x; +} + +inline Q_INT32 KisPaintDevice::getY() const +{ + return m_y; +} + +#endif // KIS_PAINT_DEVICE_IMPL_H_ + |