File indexing completed on 2024-12-22 04:16:01
0001 /* 0002 * SPDX-FileCopyrightText: 2009 Cyrille Berger <cberger@cberger.net> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include "kis_xcf_import.h" 0008 0009 #include <ctype.h> 0010 0011 #include <QApplication> 0012 #include <QFile> 0013 #include <qendian.h> 0014 0015 #include <kpluginfactory.h> 0016 #include <QFileInfo> 0017 0018 #include <KoColorSpace.h> 0019 #include <KoColorSpaceRegistry.h> 0020 #include <KoColorSpaceTraits.h> 0021 #include <KoCompositeOpRegistry.h> 0022 #include <kis_debug.h> 0023 #include <KisDocument.h> 0024 #include <kis_group_layer.h> 0025 #include <kis_image.h> 0026 #include <kis_paint_device.h> 0027 #include <kis_transaction.h> 0028 #include <kis_paint_layer.h> 0029 #include <kis_transparency_mask.h> 0030 #include "kis_iterator_ng.h" 0031 #include "kis_types.h" 0032 #include <KoColorModelStandardIds.h> 0033 extern "C" { 0034 0035 #include "xcftools.h" 0036 #include "pixels.h" 0037 0038 #define GET_RED(x) (x >> RED_SHIFT) 0039 #define GET_GREEN(x) (x >> GREEN_SHIFT) 0040 #define GET_BLUE(x) (x >> BLUE_SHIFT) 0041 #define GET_ALPHA(x) (x >> ALPHA_SHIFT) 0042 } 0043 0044 QString layerModeG2K(GimpLayerModeEffects mode) 0045 { 0046 switch (mode) { 0047 case GIMP_NORMAL_MODE: 0048 return COMPOSITE_OVER; 0049 case GIMP_DISSOLVE_MODE: 0050 return COMPOSITE_DISSOLVE; 0051 case GIMP_MULTIPLY_MODE: 0052 return COMPOSITE_MULT; 0053 case GIMP_SCREEN_MODE: 0054 return COMPOSITE_SCREEN; 0055 case GIMP_OVERLAY_MODE: 0056 case GIMP_SOFTLIGHT_MODE: 0057 return COMPOSITE_OVERLAY; 0058 case GIMP_DIFFERENCE_MODE: 0059 return COMPOSITE_DIFF; 0060 case GIMP_ADDITION_MODE: 0061 return COMPOSITE_ADD; 0062 case GIMP_SUBTRACT_MODE: 0063 return COMPOSITE_SUBTRACT; 0064 case GIMP_DARKEN_ONLY_MODE: 0065 return COMPOSITE_DARKEN; 0066 case GIMP_LIGHTEN_ONLY_MODE: 0067 return COMPOSITE_LIGHTEN; 0068 case GIMP_HUE_MODE: 0069 return COMPOSITE_HUE_HSL; 0070 case GIMP_SATURATION_MODE: 0071 return COMPOSITE_SATURATION_HSV; 0072 case GIMP_COLOR_MODE: 0073 return COMPOSITE_COLOR_HSL; 0074 case GIMP_VALUE_MODE: 0075 return COMPOSITE_VALUE; 0076 case GIMP_DIVIDE_MODE: 0077 return COMPOSITE_DIVIDE; 0078 case GIMP_DODGE_MODE: 0079 return COMPOSITE_DODGE; 0080 case GIMP_BURN_MODE: 0081 return COMPOSITE_BURN; 0082 case GIMP_ERASE_MODE: 0083 return COMPOSITE_ERASE; 0084 case GIMP_REPLACE_MODE: 0085 return COMPOSITE_COPY; 0086 case GIMP_HARDLIGHT_MODE: 0087 return COMPOSITE_HARD_LIGHT; 0088 case GIMP_COLOR_ERASE_MODE: 0089 case GIMP_NORMAL_NOPARTIAL_MODE: 0090 case GIMP_ANTI_ERASE_MODE: 0091 case GIMP_GRAIN_EXTRACT_MODE: 0092 return COMPOSITE_GRAIN_EXTRACT; 0093 case GIMP_GRAIN_MERGE_MODE: 0094 return COMPOSITE_GRAIN_MERGE; 0095 case GIMP_BEHIND_MODE: 0096 break; 0097 } 0098 dbgFile << "Unknown mode: " << mode; 0099 return COMPOSITE_OVER; 0100 } 0101 0102 struct Layer { 0103 KisLayerSP layer; 0104 int depth; 0105 KisMaskSP mask; 0106 }; 0107 0108 KisGroupLayerSP findGroup(const QVector<Layer> &layers, const Layer& layer, int i) 0109 { 0110 for (; i < layers.size(); ++i) { 0111 KisGroupLayerSP group = dynamic_cast<KisGroupLayer*>(const_cast<KisLayer*>(layers[i].layer.data())); 0112 if (group && (layers[i].depth == layer.depth -1)) { 0113 return group; 0114 } 0115 } 0116 return 0; 0117 } 0118 0119 void addLayers(const QVector<Layer> &layers, KisImageSP image, int depth) 0120 { 0121 for(int i = 0; i < layers.size(); i++) { 0122 const Layer &layer = layers[i]; 0123 if (layer.depth == depth) { 0124 KisGroupLayerSP group = (depth == 0 ? image->rootLayer() : findGroup(layers, layer, i)); 0125 image->addNode(layer.layer, group); 0126 if (layer.mask) { 0127 image->addNode(layer.mask, layer.layer); 0128 } 0129 } 0130 } 0131 } 0132 0133 K_PLUGIN_FACTORY_WITH_JSON(XCFImportFactory, "krita_xcf_import.json", registerPlugin<KisXCFImport>();) 0134 0135 KisXCFImport::KisXCFImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) 0136 { 0137 } 0138 0139 KisXCFImport::~KisXCFImport() 0140 { 0141 } 0142 0143 KisImportExportErrorCode KisXCFImport::convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP /*configuration*/) 0144 { 0145 int errorStatus; 0146 0147 dbgFile << "Start decoding file"; 0148 QByteArray data = io->readAll(); 0149 xcf_file = (uint8_t*)data.data(); 0150 xcf_length = data.size(); 0151 io->close(); 0152 0153 // Decode the data 0154 if (getBasicXcfInfo() != XCF_OK) { 0155 if (XCF.version < 0 || XCF.version > 3) { 0156 document->setErrorMessage(i18n("This XCF file is too new; Krita cannot support XCF files written by GIMP 2.9 or newer.")); 0157 return ImportExportCodes::FormatFeaturesUnsupported; 0158 } 0159 return ImportExportCodes::FileFormatIncorrect; 0160 } 0161 0162 if(initColormap() != XCF_OK) { 0163 return ImportExportCodes::FileFormatIncorrect; 0164 } 0165 0166 dbgFile << XCF.version << "width = " << XCF.width << "height = " << XCF.height << "layers = " << XCF.numLayers; 0167 0168 // Create the image 0169 KisImageSP image = new KisImage(document->createUndoStore(), XCF.width, XCF.height, KoColorSpaceRegistry::instance()->rgb8(), "built image"); 0170 0171 QVector<Layer> layers; 0172 uint maxDepth = 0; 0173 0174 // Read layers 0175 for (int i = 0; i < XCF.numLayers; ++i) { 0176 0177 Layer layer; 0178 0179 xcfLayer& xcflayer = XCF.layers[i]; 0180 dbgFile << i << " name = " << xcflayer.name << " opacity = " << xcflayer.opacity << "group:" << xcflayer.isGroup << xcflayer.pathLength; 0181 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); 0182 0183 maxDepth = qMax(maxDepth, xcflayer.pathLength); 0184 0185 bool isRgbA = false; 0186 // Select the color space 0187 const KoColorSpace* colorSpace = 0; 0188 switch (xcflayer.type) { 0189 case GIMP_INDEXED_IMAGE: 0190 case GIMP_INDEXEDA_IMAGE: 0191 case GIMP_RGB_IMAGE: 0192 case GIMP_RGBA_IMAGE: 0193 colorSpace = KoColorSpaceRegistry::instance()->rgb8(); 0194 isRgbA = true; 0195 break; 0196 case GIMP_GRAY_IMAGE: 0197 case GIMP_GRAYA_IMAGE: 0198 colorSpace = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer8BitsColorDepthID.id(), ""); 0199 isRgbA = false; 0200 break; 0201 } 0202 0203 // Create the layer 0204 KisLayerSP kisLayer; 0205 if (xcflayer.isGroup) { 0206 kisLayer = new KisGroupLayer(image, QString::fromUtf8(xcflayer.name), xcflayer.opacity); 0207 } 0208 else { 0209 kisLayer = new KisPaintLayer(image, QString::fromUtf8(xcflayer.name), xcflayer.opacity, colorSpace); 0210 } 0211 0212 // Set some properties 0213 kisLayer->setCompositeOpId(layerModeG2K(xcflayer.mode)); 0214 kisLayer->setVisible(xcflayer.isVisible); 0215 kisLayer->disableAlphaChannel(xcflayer.mode != GIMP_NORMAL_MODE); 0216 0217 layer.layer = kisLayer; 0218 layer.depth = xcflayer.pathLength; 0219 0220 // Copy the data in the image 0221 if ((errorStatus = initLayer(&xcflayer)) != XCF_OK) { 0222 return ImportExportCodes::FileFormatIncorrect; 0223 } 0224 0225 int left = xcflayer.dim.c.l; 0226 int top = xcflayer.dim.c.t; 0227 0228 if (!xcflayer.isGroup) { 0229 0230 // Copy the data; 0231 for (unsigned int x = 0; x < xcflayer.dim.width; x += TILE_WIDTH) { 0232 for (unsigned int y = 0; y < xcflayer.dim.height; y += TILE_HEIGHT) { 0233 rect want; 0234 want.l = x + left; 0235 want.t = y + top; 0236 want.b = want.t + TILE_HEIGHT; 0237 want.r = want.l + TILE_WIDTH; 0238 Tile* tile = getMaskOrLayerTile(&xcflayer.dim, &xcflayer.pixels, want); 0239 if (tile == XCF_PTR_EMPTY) { 0240 return ImportExportCodes::FileFormatIncorrect; 0241 } 0242 KisHLineIteratorSP it = kisLayer->paintDevice()->createHLineIteratorNG(x, y, TILE_WIDTH); 0243 rgba* data = tile->pixels; 0244 for (int v = 0; v < TILE_HEIGHT; ++v) { 0245 if (isRgbA) { 0246 // RGB image 0247 do { 0248 KoBgrTraits<quint8>::setRed(it->rawData(), GET_RED(*data)); 0249 KoBgrTraits<quint8>::setGreen(it->rawData(), GET_GREEN(*data)); 0250 KoBgrTraits<quint8>::setBlue(it->rawData(), GET_BLUE(*data)); 0251 KoBgrTraits<quint8>::setOpacity(it->rawData(), quint8(GET_ALPHA(*data)), 1); 0252 ++data; 0253 } while (it->nextPixel()); 0254 } else { 0255 // Grayscale image 0256 do { 0257 it->rawData()[0] = GET_RED(*data); 0258 it->rawData()[1] = GET_ALPHA(*data); 0259 ++data; 0260 } while (it->nextPixel()); 0261 } 0262 it->nextRow(); 0263 } 0264 freeTile(tile); 0265 } 0266 } 0267 0268 // Move the layer to its position 0269 kisLayer->paintDevice()->setX(left); 0270 kisLayer->paintDevice()->setY(top); 0271 } 0272 // Create the mask 0273 if (xcflayer.hasMask) { 0274 KisTransparencyMaskSP mask = new KisTransparencyMask(image, i18n("Transparency Mask")); 0275 layer.mask = mask; 0276 0277 mask->initSelection(kisLayer); 0278 for (unsigned int x = 0; x < xcflayer.dim.width; x += TILE_WIDTH) { 0279 for (unsigned int y = 0; y < xcflayer.dim.height; y += TILE_HEIGHT) { 0280 rect want; 0281 want.l = x + left; 0282 want.t = y + top; 0283 want.b = want.t + TILE_HEIGHT; 0284 want.r = want.l + TILE_WIDTH; 0285 Tile* tile = getMaskOrLayerTile(&xcflayer.dim, &xcflayer.mask, want); 0286 if (tile == XCF_PTR_EMPTY) { 0287 free(tile); 0288 return ImportExportCodes::FileFormatIncorrect; 0289 } 0290 KisHLineIteratorSP it = mask->paintDevice()->createHLineIteratorNG(x, y, TILE_WIDTH); 0291 rgba* data = tile->pixels; 0292 for (int v = 0; v < TILE_HEIGHT; ++v) { 0293 do { 0294 it->rawData()[0] = GET_ALPHA(*data); 0295 ++data; 0296 } while (it->nextPixel()); 0297 it->nextRow(); 0298 } 0299 freeTile(tile); 0300 } 0301 } 0302 mask->paintDevice()->setX(left); 0303 mask->paintDevice()->setY(top); 0304 } 0305 0306 dbgFile << xcflayer.pixels.tileptrs; 0307 layers.append(layer); 0308 } 0309 0310 for (uint i = 0; i <= maxDepth; ++i) { 0311 addLayers(layers, image, i); 0312 } 0313 0314 document->setCurrentImage(image); 0315 return ImportExportCodes::OK; 0316 0317 } 0318 0319 #include "kis_xcf_import.moc"