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"