Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_xcf_import.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2009 Cyrille Berger <cberger@cberger.net>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6
7#include "kis_xcf_import.h"
8
9#include <ctype.h>
10
11#include <QApplication>
12#include <QFile>
13#include <qendian.h>
14
15#include <kpluginfactory.h>
16
17#include <KoColorSpace.h>
19#include <KoColorSpaceTraits.h>
21#include <kis_debug.h>
22#include <KisDocument.h>
23#include <kis_group_layer.h>
24#include <kis_image.h>
25#include <kis_paint_device.h>
26#include <kis_transaction.h>
27#include <kis_paint_layer.h>
29#include "kis_iterator_ng.h"
30#include "kis_types.h"
32extern "C" {
33
34#include "xcftools.h"
35#include "pixels.h"
36
37#define GET_RED(x) (x >> RED_SHIFT)
38#define GET_GREEN(x) (x >> GREEN_SHIFT)
39#define GET_BLUE(x) (x >> BLUE_SHIFT)
40#define GET_ALPHA(x) (x >> ALPHA_SHIFT)
41}
42
44{
45 switch (mode) {
47 return COMPOSITE_OVER;
49 return COMPOSITE_DISSOLVE;
51 return COMPOSITE_MULT;
53 return COMPOSITE_SCREEN;
56 return COMPOSITE_OVERLAY;
58 return COMPOSITE_DIFF;
60 return COMPOSITE_ADD;
62 return COMPOSITE_SUBTRACT;
64 return COMPOSITE_DARKEN;
66 return COMPOSITE_LIGHTEN;
67 case GIMP_HUE_MODE:
68 return COMPOSITE_HUE_HSL;
71 case GIMP_COLOR_MODE:
73 case GIMP_VALUE_MODE:
74 return COMPOSITE_VALUE;
76 return COMPOSITE_DIVIDE;
77 case GIMP_DODGE_MODE:
78 return COMPOSITE_DODGE;
79 case GIMP_BURN_MODE:
80 return COMPOSITE_BURN;
81 case GIMP_ERASE_MODE:
82 return COMPOSITE_ERASE;
84 return COMPOSITE_COPY;
95 break;
96 }
97 dbgFile << "Unknown mode: " << mode;
98 return COMPOSITE_OVER;
99}
100
101struct Layer {
103 int depth;
105};
106
107KisGroupLayerSP findGroup(const QVector<Layer> &layers, const Layer& layer, int i)
108{
109 for (; i < layers.size(); ++i) {
110 KisGroupLayerSP group = dynamic_cast<KisGroupLayer*>(const_cast<KisLayer*>(layers[i].layer.data()));
111 if (group && (layers[i].depth == layer.depth -1)) {
112 return group;
113 }
114 }
115 return 0;
116}
117
118void addLayers(const QVector<Layer> &layers, KisImageSP image, int depth)
119{
120 for(int i = 0; i < layers.size(); i++) {
121 const Layer &layer = layers[i];
122 if (layer.depth == depth) {
123 KisGroupLayerSP group = (depth == 0 ? image->rootLayer() : findGroup(layers, layer, i));
124 image->addNode(layer.layer, group);
125 if (layer.mask) {
126 image->addNode(layer.mask, layer.layer);
127 }
128 }
129 }
130}
131
132K_PLUGIN_FACTORY_WITH_JSON(XCFImportFactory, "krita_xcf_import.json", registerPlugin<KisXCFImport>();)
133
134KisXCFImport::KisXCFImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent)
135{
136}
137
141
143{
144 int errorStatus;
145
146 dbgFile << "Start decoding file";
147 QByteArray data = io->readAll();
148 xcf_file = (uint8_t*)data.data();
149 xcf_length = data.size();
150 io->close();
151
152 // Decode the data
153 if (getBasicXcfInfo() != XCF_OK) {
154 if (XCF.version < 0 || XCF.version > 2) {
155 document->setErrorMessage(i18n("This XCF file is too new; Krita cannot support XCF files written by GIMP 2.9 or newer."));
157 }
159 }
160
161 if(initColormap() != XCF_OK) {
163 }
164
165 dbgFile << XCF.version << "width = " << XCF.width << "height = " << XCF.height << "layers = " << XCF.numLayers;
166
167 // Create the image
168 KisImageSP image = new KisImage(document->createUndoStore(), XCF.width, XCF.height, KoColorSpaceRegistry::instance()->rgb8(), "built image");
169
170 QVector<Layer> layers;
171 uint maxDepth = 0;
172
173 // Read layers
174 for (int i = 0; i < XCF.numLayers; ++i) {
175
176 Layer layer;
177
178 xcfLayer& xcflayer = XCF.layers[i];
179 dbgFile << i << " name = " << xcflayer.name << " opacity = " << xcflayer.opacity << "group:" << xcflayer.isGroup << xcflayer.pathLength;
180 dbgFile << ppVar(xcflayer.dim.width) << ppVar(xcflayer.dim.height) << ppVar(xcflayer.dim.tilesx) << ppVar(xcflayer.dim.tilesy) << ppVar(xcflayer.dim.ntiles) << ppVar(xcflayer.dim.c.t) << ppVar(xcflayer.dim.c.l) << ppVar(xcflayer.dim.c.r) << ppVar(xcflayer.dim.c.b);
181
182 maxDepth = qMax(maxDepth, xcflayer.pathLength);
183
184 bool isRgbA = false;
185 // Select the color space
186 const KoColorSpace* colorSpace = 0;
187 switch (xcflayer.type) {
190 case GIMP_RGB_IMAGE:
191 case GIMP_RGBA_IMAGE:
192 colorSpace = KoColorSpaceRegistry::instance()->rgb8();
193 isRgbA = true;
194 break;
195 case GIMP_GRAY_IMAGE:
196 case GIMP_GRAYA_IMAGE:
198 isRgbA = false;
199 break;
200 }
201
202 // Create the layer
203 KisLayerSP kisLayer;
204 if (xcflayer.isGroup) {
205 kisLayer = new KisGroupLayer(image, QString::fromUtf8(xcflayer.name), xcflayer.opacity);
206 }
207 else {
208 kisLayer = new KisPaintLayer(image, QString::fromUtf8(xcflayer.name), xcflayer.opacity, colorSpace);
209 }
210
211 // Set some properties
212 kisLayer->setCompositeOpId(layerModeG2K(xcflayer.mode));
213 kisLayer->setVisible(xcflayer.isVisible);
214 kisLayer->disableAlphaChannel(xcflayer.mode != GIMP_NORMAL_MODE);
215
216 layer.layer = kisLayer;
217 layer.depth = xcflayer.pathLength;
218
219 // Copy the data in the image
220 if ((errorStatus = initLayer(&xcflayer)) != XCF_OK) {
222 }
223
224 int left = xcflayer.dim.c.l;
225 int top = xcflayer.dim.c.t;
226
227 if (!xcflayer.isGroup) {
228
229 // Copy the data;
230 for (unsigned int x = 0; x < xcflayer.dim.width; x += TILE_WIDTH) {
231 for (unsigned int y = 0; y < xcflayer.dim.height; y += TILE_HEIGHT) {
232 rect want;
233 want.l = x + left;
234 want.t = y + top;
235 want.b = want.t + TILE_HEIGHT;
236 want.r = want.l + TILE_WIDTH;
237 Tile* tile = getMaskOrLayerTile(&xcflayer.dim, &xcflayer.pixels, want);
238 if (tile == XCF_PTR_EMPTY) {
240 }
242 rgba* data = tile->pixels;
243 for (int v = 0; v < TILE_HEIGHT; ++v) {
244 if (isRgbA) {
245 // RGB image
246 do {
247 KoBgrTraits<quint8>::setRed(it->rawData(), GET_RED(*data));
248 KoBgrTraits<quint8>::setGreen(it->rawData(), GET_GREEN(*data));
249 KoBgrTraits<quint8>::setBlue(it->rawData(), GET_BLUE(*data));
250 KoBgrTraits<quint8>::setOpacity(it->rawData(), quint8(GET_ALPHA(*data)), 1);
251 ++data;
252 } while (it->nextPixel());
253 } else {
254 // Grayscale image
255 do {
256 it->rawData()[0] = GET_RED(*data);
257 it->rawData()[1] = GET_ALPHA(*data);
258 ++data;
259 } while (it->nextPixel());
260 }
261 it->nextRow();
262 }
263 freeTile(tile);
264 }
265 }
266
267 // Move the layer to its position
268 kisLayer->paintDevice()->setX(left);
269 kisLayer->paintDevice()->setY(top);
270 }
271 // Create the mask
272 if (xcflayer.hasMask) {
273 KisTransparencyMaskSP mask = new KisTransparencyMask(image, i18n("Transparency Mask"));
274 layer.mask = mask;
275
276 mask->initSelection(kisLayer);
277 for (unsigned int x = 0; x < xcflayer.dim.width; x += TILE_WIDTH) {
278 for (unsigned int y = 0; y < xcflayer.dim.height; y += TILE_HEIGHT) {
279 rect want;
280 want.l = x + left;
281 want.t = y + top;
282 want.b = want.t + TILE_HEIGHT;
283 want.r = want.l + TILE_WIDTH;
284 Tile* tile = getMaskOrLayerTile(&xcflayer.dim, &xcflayer.mask, want);
285 if (tile == XCF_PTR_EMPTY) {
286 free(tile);
288 }
290 rgba* data = tile->pixels;
291 for (int v = 0; v < TILE_HEIGHT; ++v) {
292 do {
293 it->rawData()[0] = GET_ALPHA(*data);
294 ++data;
295 } while (it->nextPixel());
296 it->nextRow();
297 }
298 freeTile(tile);
299 }
300 }
301 mask->paintDevice()->setX(left);
302 mask->paintDevice()->setY(top);
303 }
304
305 dbgFile << xcflayer.pixels.tileptrs;
306 layers.append(layer);
307 }
308
309 for (uint i = 0; i <= maxDepth; ++i) {
310 addLayers(layers, image, i);
311 }
312
313 document->setCurrentImage(image);
315
316}
317
318#include "kis_xcf_import.moc"
qreal v
const KoID GrayAColorModelID("GRAYA", ki18n("Grayscale/Alpha"))
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const QString COMPOSITE_OVER
const QString COMPOSITE_COPY
const QString COMPOSITE_DARKEN
const QString COMPOSITE_OVERLAY
const QString COMPOSITE_DIVIDE
const QString COMPOSITE_DODGE
const QString COMPOSITE_ADD
const QString COMPOSITE_LIGHTEN
const QString COMPOSITE_VALUE
const QString COMPOSITE_GRAIN_MERGE
const QString COMPOSITE_MULT
const QString COMPOSITE_HUE_HSL
const QString COMPOSITE_HARD_LIGHT
const QString COMPOSITE_SCREEN
const QString COMPOSITE_DIFF
const QString COMPOSITE_ERASE
const QString COMPOSITE_SUBTRACT
const QString COMPOSITE_DISSOLVE
const QString COMPOSITE_BURN
const QString COMPOSITE_COLOR_HSL
const QString COMPOSITE_GRAIN_EXTRACT
const QString COMPOSITE_SATURATION_HSV
unsigned int uint
KisGroupLayerSP rootLayer() const
The base class for import and export filters.
void setX(qint32 x)
KisHLineIteratorSP createHLineIteratorNG(qint32 x, qint32 y, qint32 w)
void setY(qint32 y)
KisImportExportErrorCode convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP configuration=0) override
KisXCFImport(QObject *parent, const QVariantList &)
~KisXCFImport() override
QString id() const
Definition KoID.cpp:63
GimpLayerModeEffects
Definition enums.h:8
@ GIMP_REPLACE_MODE
Definition enums.h:33
@ GIMP_NORMAL_MODE
Definition enums.h:9
@ GIMP_DODGE_MODE
Definition enums.h:25
@ GIMP_COLOR_ERASE_MODE
Definition enums.h:31
@ GIMP_HARDLIGHT_MODE
Definition enums.h:27
@ GIMP_MULTIPLY_MODE
Definition enums.h:12
@ GIMP_DIVIDE_MODE
Definition enums.h:24
@ GIMP_DISSOLVE_MODE
Definition enums.h:10
@ GIMP_SCREEN_MODE
Definition enums.h:13
@ GIMP_GRAIN_MERGE_MODE
Definition enums.h:30
@ GIMP_SUBTRACT_MODE
Definition enums.h:17
@ GIMP_ANTI_ERASE_MODE
Definition enums.h:34
@ GIMP_VALUE_MODE
Definition enums.h:23
@ GIMP_DARKEN_ONLY_MODE
Definition enums.h:18
@ GIMP_COLOR_MODE
Definition enums.h:22
@ GIMP_NORMAL_NOPARTIAL_MODE
Definition enums.h:35
@ GIMP_ERASE_MODE
Definition enums.h:32
@ GIMP_LIGHTEN_ONLY_MODE
Definition enums.h:19
@ GIMP_SOFTLIGHT_MODE
Definition enums.h:28
@ GIMP_ADDITION_MODE
Definition enums.h:16
@ GIMP_OVERLAY_MODE
Definition enums.h:14
@ GIMP_BEHIND_MODE
Definition enums.h:11
@ GIMP_HUE_MODE
Definition enums.h:20
@ GIMP_SATURATION_MODE
Definition enums.h:21
@ GIMP_DIFFERENCE_MODE
Definition enums.h:15
@ GIMP_BURN_MODE
Definition enums.h:26
@ GIMP_GRAIN_EXTRACT_MODE
Definition enums.h:29
@ GIMP_RGB_IMAGE
Definition enums.h:49
@ GIMP_INDEXED_IMAGE
Definition enums.h:53
@ GIMP_GRAYA_IMAGE
Definition enums.h:52
@ GIMP_INDEXEDA_IMAGE
Definition enums.h:54
@ GIMP_GRAY_IMAGE
Definition enums.h:51
@ GIMP_RGBA_IMAGE
Definition enums.h:50
K_PLUGIN_FACTORY_WITH_JSON(KritaASCCDLFactory, "kritaasccdl.json", registerPlugin< KritaASCCDL >();) KritaASCCDL
#define ppVar(var)
Definition kis_debug.h:155
#define dbgFile
Definition kis_debug.h:53
#define GET_RED(x)
#define GET_GREEN(x)
void addLayers(const QVector< Layer > &layers, KisImageSP image, int depth)
KisGroupLayerSP findGroup(const QVector< Layer > &layers, const Layer &layer, int i)
#define GET_BLUE(x)
QString layerModeG2K(GimpLayerModeEffects mode)
#define GET_ALPHA(x)
int initColormap(void)
Definition pixels.c:199
int initLayer(struct xcfLayer *layer)
Definition pixels.c:167
void freeTile(struct Tile *tile)
Definition pixels.c:255
struct Tile * getMaskOrLayerTile(struct tileDimensions *dim, struct xcfTiles *tiles, struct rect want)
Definition pixels.c:427
uint32_t rgba
Definition pixels.h:44
virtual void setVisible(bool visible, bool loading=false)
virtual KisPaintDeviceSP paintDevice() const =0
void setCompositeOpId(const QString &compositeOpId)
void disableAlphaChannel(bool disable)
Definition kis_layer.cc:319
void initSelection(KisSelectionSP copyFrom, KisLayerSP parentLayer)
initSelection initializes the selection for the mask from the given selection's projection.
Definition kis_mask.cc:157
KisPaintDeviceSP paintDevice() const override
Definition kis_mask.cc:223
bool addNode(KisNodeSP node, KisNodeSP parent=KisNodeSP(), KisNodeAdditionFlags flags=KisNodeAdditionFlag::None)
static void setRed(quint8 *data, channels_type nv)
Set the red component.
static void setGreen(quint8 *data, channels_type nv)
Set the green component.
static void setBlue(quint8 *data, channels_type nv)
Set the blue component.
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()
const KoColorSpace * rgb8(const QString &profileName=QString())
static void setOpacity(quint8 *pixels, quint8 alpha, qint32 nPixels)
KisMaskSP mask
KisLayerSP layer
Definition pixels.h:97
rgba pixels[TILE_WIDTH *TILE_HEIGHT]
Definition pixels.h:101
int l
Definition xcftools.h:130
int r
Definition xcftools.h:130
int t
Definition xcftools.h:130
int b
Definition xcftools.h:130
struct rect c
Definition xcftools.h:166
unsigned tilesx
Definition xcftools.h:168
unsigned height
Definition xcftools.h:167
unsigned tilesy
Definition xcftools.h:168
unsigned width
Definition xcftools.h:167
unsigned ntiles
Definition xcftools.h:169
unsigned height
Definition xcftools.h:197
unsigned width
Definition xcftools.h:197
int numLayers
Definition xcftools.h:200
struct xcfLayer * layers
Definition xcftools.h:201
int version
Definition xcftools.h:196
unsigned int opacity
Definition xcftools.h:185
unsigned pathLength
Definition xcftools.h:191
int isVisible
Definition xcftools.h:186
GimpLayerModeEffects mode
Definition xcftools.h:183
struct xcfTiles pixels
Definition xcftools.h:188
int isGroup
Definition xcftools.h:190
int hasMask
Definition xcftools.h:186
struct tileDimensions dim
Definition xcftools.h:181
const char * name
Definition xcftools.h:182
GimpImageType type
Definition xcftools.h:184
struct xcfTiles mask
Definition xcftools.h:189
uint32_t * tileptrs
Definition xcftools.h:176
int getBasicXcfInfo(void)
struct xcfImage XCF
size_t xcf_length
Definition xcf-general.c:30
uint8_t * xcf_file
Definition xcf-general.c:29
#define TILE_HEIGHT
Definition xcftools.h:155
#define TILE_WIDTH
Definition xcftools.h:154
#define XCF_OK
Definition xcftools.h:106
#define XCF_PTR_EMPTY
Definition xcftools.h:107