/* * copyright (c) 2002 patrick julien * * 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 #include #include #include #include #include #include #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 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 KisDataManagerSP; class KisMemento; typedef KSharedPtr 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. * Note: 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 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_