You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/krita/core/kis_image.h

461 lines
15 KiB

/*
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
* 2006 Boudewijn Rempt <boud@valdyas.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KIS_IMAGE_H_
#define KIS_IMAGE_H_
#include <qobject.h>
#include <qstring.h>
#include <qvaluevector.h>
#include <qmutex.h>
#include <config.h>
#include <ksharedptr.h>
#include <kurl.h>
#include "KoUnit.h"
#include "kis_composite_op.h"
#include "kis_global.h"
#include "kis_types.h"
#include "kis_annotation.h"
#include "kis_paint_device.h"
#include <koffice_export.h>
class DCOPObject;
class KCommand;
class KoCommandHistory;
class KisColorSpace;
class KisNameServer;
class KisUndoAdapter;
class KisPainter;
class KCommand;
class KisColor;
class KisFilterStrategy;
class KisImageIface;
class KisProfile;
class KisProgressDisplayInterface;
class KisPaintLayer;
class KisPerspectiveGrid;
class KRITACORE_EXPORT KisImage : public QObject, public KShared {
Q_OBJECT
public:
KisImage(KisUndoAdapter * adapter, Q_INT32 width, Q_INT32 height, KisColorSpace * colorSpace, const QString& name);
KisImage(const KisImage& rhs);
virtual ~KisImage();
virtual DCOPObject *dcopObject();
public:
typedef enum enumPaintFlags {
PAINT_IMAGE_ONLY = 0,
PAINT_BACKGROUND = 1,
PAINT_SELECTION = 2,
PAINT_MASKINACTIVELAYERS = 4,
PAINT_EMBEDDED_RECT = 8 // If the current layer is an embedded part draw a rect around it
} PaintFlags;
/// Paint the specified rect onto the painter, adjusting the colors using the
/// given profile. The exposure setting is used if the image has a high dynamic range.
virtual void renderToPainter(Q_INT32 x1,
Q_INT32 y1,
Q_INT32 x2,
Q_INT32 y2,
QPainter &painter,
KisProfile *profile,
PaintFlags paintFlags,
float exposure = 0.0f);
/**
* Render the projection onto a QImage. In contrast with the above method, the
* selection is not rendered.
*/
virtual QImage convertToQImage(Q_INT32 x1,
Q_INT32 y1,
Q_INT32 x2,
Q_INT32 y2,
KisProfile * profile,
float exposure = 0.0f);
virtual QImage convertToQImage(const QRect& r, const QSize& fullImageSize, KisProfile *profile, PaintFlags paintFlags, float exposure = 0.0f);
KisBackgroundSP background() const;
KisSubstrateSP substrate() const;
public:
/**
* Lock the image to make sure no recompositing-causing signals get emitted
* while you're messing with the layers. Don't forget to unlock again.
*/
void lock();
/**
* Unlock the image to make sure the rest of Krita learns about changes in the image
* again. If the rootLayer is dirty on unlocking, an imgUpdated signal is sent out
* immediately.
*/
void unlock();
/**
* Returns true if the image is locked.
*/
bool locked() const;
KisColor backgroundColor() const;
void setBackgroundColor(const KisColor & color);
QString name() const;
void setName(const QString& name);
QString description() const;
void setDescription(const QString& description);
QString nextLayerName() const;
void rollBackLayerName();
KisPerspectiveGrid* perspectiveGrid();
void createPerspectiveGrid(QPoint topLeft, QPoint topRight, QPoint bottomRight, QPoint bottomLeft);
/**
* Resize the image to the specified width and height. The resize
* method handles the creating on an undo step itself.
*
* @param w the new width of the image
* @param h the new height of the image
* @param x the x position of the crop on all layer if cropLayers is true
* @param y the y position of the crop on all layer if cropLayers is true
* @param cropLayers if true, all layers are cropped to the new size.
*/
void resize(Q_INT32 w, Q_INT32 h, Q_INT32 x = 0, Q_INT32 y = 0, bool cropLayers = false);
/**
* Resize the image to the specified width and height. The resize
* method handles the creating on an undo step itself.
*
* @param rc the rect describing the new width and height of the image
* @param cropLayers if true, all layers are cropped to the new rect
*/
void resize(const QRect& rc, bool cropLayers = false);
void scale(double sx, double sy, KisProgressDisplayInterface *m_progress, KisFilterStrategy *filterStrategy);
void rotate(double radians, KisProgressDisplayInterface *m_progress);
void shear(double angleX, double angleY, KisProgressDisplayInterface *m_progress);
/**
* Convert the image and all its layers to the dstColorSpace
*/
void convertTo(KisColorSpace * dstColorSpace, Q_INT32 renderingIntent = INTENT_PERCEPTUAL);
// Get the profile associated with this image
KisProfile * getProfile() const;
/**
* Set the profile of the image to the new profile and do the same for
* all layers that have the same colorspace and profile as the image.
* It doesn't do any pixel conversion.
*
* This is essential if you have loaded an image that didn't
* have an embedded profile to which you want to attach the right profile.
*/
void setProfile(const KisProfile * profile);
/**
* Replace the current undo adapter with the specified undo adapter.
* The current undo adapter will _not_ be deleted.
*/
void setUndoAdapter(KisUndoAdapter * undoAdapter);
/**
* Returns the current undo adapter. You can add new commands to the
* undo stack using the adapter
*/
KisUndoAdapter *undoAdapter() const;
/**
* Returns true if this image wants undo information, false otherwise
*/
bool undo() const;
/**
* Tell the image it's modified; this emits the sigImageModified signal. This happens
* when the image needs to be saved
*/
void setModified();
KisColorSpace * colorSpace() const;
// Resolution of the image == XXX: per inch?
double xRes();
double yRes();
void setResolution(double xres, double yres);
Q_INT32 width() const;
Q_INT32 height() const;
bool empty() const;
/**
* returns a paintdevice that contains the merged layers of this image, within
* the bounds of this image (with the colorspace and profile of this image)
*/
KisPaintDeviceSP mergedImage();
/*
* Returns the colour of the merged image at pixel (x, y).
*/
KisColor mergedPixel(Q_INT32 x, Q_INT32 y);
/// Creates a new paint layer with the specified properties, adds it to the image, and returns it.
KisLayerSP newLayer(const QString& name, Q_UINT8 opacity,
const KisCompositeOp& compositeOp = KisCompositeOp(), KisColorSpace * colorstrategy = 0);
/// Get the active painting device. Returns 0 if the active layer does not have a paint device.
KisPaintDeviceSP activeDevice();
void setLayerProperties(KisLayerSP layer, Q_UINT8 opacity, const KisCompositeOp& compositeOp, const QString& name);
KisGroupLayerSP rootLayer() const;
KisLayerSP activeLayer() const;
/// Return the projection; that is, the complete, composited representation
/// of this image.
KisPaintDeviceSP projection();
KisLayerSP activate(KisLayerSP layer);
KisLayerSP findLayer(const QString& name) const;
KisLayerSP findLayer(int id) const;
/// Move layer to specified position
bool moveLayer(KisLayerSP layer, KisGroupLayerSP parent, KisLayerSP aboveThis);
/**
* Add an already existing layer to the image. The layer is put on top
* of the layers in the specified layergroup
* @param layer the layer to be added
* @param parent the parent layer
*/
bool addLayer(KisLayerSP layer, KisGroupLayerSP parent);
/**
* Add already existing layer to image.
*
* @param layer the layer to be added
* @param parent the parent layer
* @param aboveThis in the list with child layers of the specified
* parent, add this layer above the specified sibling.
* if 0, the layer is put in the lowermost position in
* its group.
* @param notify If true, the image is immediately recomposited, if false,
* no recomposition is done yet. The added layer is all
*
* returns false if adding the layer didn't work, true if the layer got added
*/
bool addLayer(KisLayerSP layer, KisGroupLayerSP parent, KisLayerSP aboveThis);
/// Remove layer
bool removeLayer(KisLayerSP layer);
/// Move layer up one slot
bool raiseLayer(KisLayerSP layer);
/// Move layer down one slot
bool lowerLayer(KisLayerSP layer);
/// Move layer to top slot
bool toTop(KisLayerSP layer);
/// Move layer to bottom slot
bool toBottom(KisLayerSP layer);
Q_INT32 nlayers() const;
Q_INT32 nHiddenLayers() const;
KCommand *raiseLayerCommand(KisLayerSP layer);
KCommand *lowerLayerCommand(KisLayerSP layer);
KCommand *topLayerCommand(KisLayerSP layer);
KCommand *bottomLayerCommand(KisLayerSP layer);
/**
* Merge all visible layers and discard hidden ones.
* The resulting layer will be activated.
*/
void flatten();
/**
* Merge the specified layer with the layer
* below this layer, remove the specified layer.
*/
void mergeLayer(KisLayerSP l);
QRect bounds() const;
/// use if the layers have changed _completely_ (eg. when flattening)
void notifyLayersChanged();
void notifyPropertyChanged(KisLayerSP layer);
void notifyImageLoaded();
void notifyLayerUpdated(KisLayerSP layer, QRect rc);
void setColorSpace(KisColorSpace * colorSpace);
void setRootLayer(KisGroupLayerSP rootLayer);
//KisGuideMgr *guides() const;
/**
* Add an annotation for this image. This can be anything: Gamma, EXIF, etc.
* Note that the "icc" annotation is reserved for the colour strategies.
* If the annotation already exists, overwrite it with this one.
*/
void addAnnotation(KisAnnotationSP annotation);
/** get the annotation with the given type, can return 0 */
KisAnnotationSP annotation(QString type);
/** delete the annotation, if the image contains it */
void removeAnnotation(QString type);
/**
* Start of an iteration over the annotations of this image (including the ICC Profile)
*/
vKisAnnotationSP_it beginAnnotations();
/** end of an iteration over the annotations of this image */
vKisAnnotationSP_it endAnnotations();
signals:
void sigActiveSelectionChanged(KisImageSP image);
void sigSelectionChanged(KisImageSP image);
void sigSelectionChanged(KisImageSP image, const QRect& rect);
/// Emitted after a different layer is made active.
void sigLayerActivated(KisLayerSP layer);
/// Emitted after a layer is added: you can find out where by asking it for its parent(), et al.
void sigLayerAdded(KisLayerSP layer);
/** Emitted after a layer is removed.
It's no longer in the image, but still exists, so @p layer is valid.
@param layer the removed layer
@param parent the parent of the layer, before it was removed
@param wasAboveThis the layer it was above, before it was removed.
*/
void sigLayerRemoved(KisLayerSP layer, KisGroupLayerSP wasParent, KisLayerSP wasAboveThis);
/** Emitted after a layer is moved to a different position under its parent layer, or its parent changes.
@param previousParent the parent of the layer, before it was moved
@param wasAboveThis the layer it was above, before it was moved.
*/
void sigLayerMoved(KisLayerSP layer, KisGroupLayerSP previousParent, KisLayerSP wasAboveThis);
/// Emitted after a layer's properties (visible, locked, opacity, composite op, name, ...) change
void sigLayerPropertiesChanged(KisLayerSP layer);
/** Emitted when the list of layers has changed completely.
This means e.g. when the image is flattened, but not when it is rotated,
as the layers only change internally then.
*/
void sigLayersChanged(KisGroupLayerSP rootLayer);
/**
* Emitted whenever an action has caused the image to be recomposited. This happens
* after calls to recomposite().
*
* @param rc The rect that has been recomposited.
*/
void sigImageUpdated(QRect rc);
/**
* Emitted whenever a layer is modified.
*
* @param layer The layer that has been modified.
* @param rc The rectangle that has been modified.
*/
void sigLayerUpdated(KisLayerSP layer, QRect rc);
/**
* Emitted whenever the image has been modified, so that it doesn't match with the version saved on disk.
*/
void sigImageModified();
void sigSizeChanged(Q_INT32 w, Q_INT32 h);
void sigProfileChanged(KisProfile * profile);
void sigColorSpaceChanged(KisColorSpace* cs);
/// Emitted when any layer's mask info got updated (or when the current layer changes)
void sigMaskInfoChanged();
public slots:
void slotSelectionChanged();
void slotSelectionChanged(const QRect& r);
private:
KisImage& operator=(const KisImage& rhs);
void init(KisUndoAdapter * adapter, Q_INT32 width, Q_INT32 height, KisColorSpace * colorSpace, const QString& name);
void emitSizeChanged();
private:
KURL m_uri;
QString m_name;
QString m_description;
Q_INT32 m_width;
Q_INT32 m_height;
double m_xres;
double m_yres;
KoUnit::Unit m_unit;
KisColorSpace * m_colorSpace;
bool m_dirty;
QRect m_dirtyRect;
KisBackgroundSP m_bkg;
KisGroupLayerSP m_rootLayer; // The layers are contained in here
KisLayerSP m_activeLayer;
KisNameServer *m_nserver;
KisUndoAdapter *m_adapter;
//KisGuideMgr m_guides;
DCOPObject *m_dcop;
vKisAnnotationSP m_annotations;
class KisImagePrivate;
KisImagePrivate * m_private;
};
#endif // KIS_IMAGE_H_