File indexing completed on 2024-06-09 04:27:49

0001 /*
0002  *  SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_tga_import.h"
0008 
0009 #include <QCheckBox>
0010 #include <QBuffer>
0011 #include <QSlider>
0012 #include <QApplication>
0013 
0014 #include <kpluginfactory.h>
0015 #include <QFileInfo>
0016 
0017 #include <KoColorSpace.h>
0018 #include <KoColorSpaceRegistry.h>
0019 
0020 #include <kis_transaction.h>
0021 #include <kis_paint_device.h>
0022 #include <KisDocument.h>
0023 #include <kis_image.h>
0024 #include <kis_paint_layer.h>
0025 #include <kis_node.h>
0026 #include <kis_group_layer.h>
0027 
0028 #include <tga.h>
0029 
0030 K_PLUGIN_FACTORY_WITH_JSON(KisTGAImportFactory, "krita_tga_import.json", registerPlugin<KisTGAImport>();)
0031 
0032 KisTGAImport::KisTGAImport(QObject *parent, const QVariantList &)
0033     : KisImportExportFilter(parent)
0034 {
0035 }
0036 
0037 KisTGAImport::~KisTGAImport()
0038 {
0039 }
0040 
0041 static QDataStream & operator>> (QDataStream & s, TgaHeader & head)
0042 {
0043     s >> head.id_length;
0044     s >> head.colormap_type;
0045     s >> head.image_type;
0046     s >> head.colormap_index;
0047     s >> head.colormap_length;
0048     s >> head.colormap_size;
0049     s >> head.x_origin;
0050     s >> head.y_origin;
0051     s >> head.width;
0052     s >> head.height;
0053     s >> head.pixel_size;
0054     s >> head.flags;
0055 
0056     /*dbgKrita << "id_length: " << head.id_length << " - colormap_type: " << head.colormap_type << " - image_type: " << head.image_type;
0057     dbgKrita << "colormap_index: " << head.colormap_index << " - colormap_length: " << head.colormap_length << " - colormap_size: " << head.colormap_size;
0058     dbgKrita << "x_origin: " << head.x_origin << " - y_origin: " << head.y_origin << " - width:" << head.width << " - height:" << head.height << " - pixelsize: " << head.pixel_size << " - flags: " << head.flags;*/
0059 
0060     return s;
0061 }
0062 
0063 
0064 static bool isSupported(const TgaHeader & head)
0065 {
0066     if (head.image_type != TGA_TYPE_INDEXED &&
0067             head.image_type != TGA_TYPE_RGB &&
0068             head.image_type != TGA_TYPE_GREY &&
0069             head.image_type != TGA_TYPE_RLE_INDEXED &&
0070             head.image_type != TGA_TYPE_RLE_RGB &&
0071             head.image_type != TGA_TYPE_RLE_GREY) {
0072         return false;
0073     }
0074 
0075     if (head.image_type == TGA_TYPE_INDEXED ||
0076             head.image_type == TGA_TYPE_RLE_INDEXED) {
0077         if (head.colormap_length > 256 || head.colormap_size != 24 || head.colormap_type != 1) {
0078             return false;
0079         }
0080     }
0081 
0082     if (head.image_type == TGA_TYPE_RGB ||
0083             head.image_type == TGA_TYPE_GREY ||
0084             head.image_type == TGA_TYPE_RLE_RGB ||
0085             head.image_type == TGA_TYPE_RLE_GREY) {
0086         if (head.colormap_type != 0) {
0087             return false;
0088         }
0089     }
0090 
0091     if (head.width == 0 || head.height == 0) {
0092         return false;
0093     }
0094 
0095     if (head.pixel_size != 8 && head.pixel_size != 16 &&
0096             head.pixel_size != 24 && head.pixel_size != 32) {
0097         return false;
0098     }
0099 
0100     return true;
0101 }
0102 
0103 static bool loadTGA(QDataStream & s, const TgaHeader & tga, QImage &img)
0104 {
0105     // Create image.
0106     img = QImage(tga.width, tga.height, QImage::Format_RGB32);
0107 
0108     TgaHeaderInfo info(tga);
0109 
0110     /**
0111      * Theoretically, we should check alpha presence via the bits
0112      * in flags, but there are a lot of files in the wild that
0113      * have this flag unset. It contradicts TGA specification,
0114      * but we cannot do anything about it.
0115      */
0116     const bool alphaFlag = tga.flags & 0xf;
0117     if (tga.pixel_size == 32 && !alphaFlag) {
0118         qWarning() << "WARNING: TGA image with 32-bit pixel size reports absence of alpha channel. It is not possible, fixing...";
0119     }
0120 
0121     if (tga.pixel_size == 32 || tga.pixel_size == 16) {
0122         img = QImage(tga.width, tga.height, QImage::Format_ARGB32);
0123     }
0124 
0125     uint pixel_size = (tga.pixel_size / 8);
0126     uint size = tga.width * tga.height * pixel_size;
0127 
0128     if (size < 1) {
0129         dbgFile << "This TGA file is broken with size " << size;
0130         return false;
0131     }
0132 
0133     // Read palette.
0134     char palette[768];
0135     if (info.pal) {
0136         // @todo Support palettes in other formats!
0137         s.readRawData(palette, 3 * tga.colormap_length);
0138     }
0139 
0140     // Allocate image.
0141     uchar * const image = new uchar[size];
0142 
0143     if (info.rle) {
0144         // Decode image.
0145         char * dst = (char *)image;
0146         int num = size;
0147 
0148         while (num > 0) {
0149             // Get packet header.
0150             uchar c;
0151             s >> c;
0152 
0153             uint count = (c & 0x7f) + 1;
0154             num -= count * pixel_size;
0155 
0156             if (c & 0x80) {
0157                 // RLE pixels.
0158                 Q_ASSERT(pixel_size <= 8);
0159                 char pixel[8];
0160                 s.readRawData(pixel, pixel_size);
0161                 do {
0162                     memcpy(dst, pixel, pixel_size);
0163                     dst += pixel_size;
0164                 } while (--count);
0165             } else {
0166                 // Raw pixels.
0167                 count *= pixel_size;
0168                 s.readRawData(dst, count);
0169                 dst += count;
0170             }
0171         }
0172     } else {
0173         // Read raw image.
0174         s.readRawData((char *)image, size);
0175     }
0176 
0177     // Convert image to internal format.
0178     int y_start, y_step, y_end;
0179     if (tga.flags & TGA_ORIGIN_UPPER) {
0180         y_start = 0;
0181         y_step = 1;
0182         y_end = tga.height;
0183     } else {
0184         y_start = tga.height - 1;
0185         y_step = -1;
0186         y_end = -1;
0187     }
0188 
0189     uchar* src = image;
0190 
0191     bool hasAlpha = false;
0192     for (int y = y_start; y != y_end; y += y_step) {
0193         QRgb * scanline = (QRgb *) (void*) img.scanLine(y);
0194 
0195         if (info.pal) {
0196             // Paletted.
0197             for (int x = 0; x < tga.width; x++) {
0198                 uchar idx = *src++;
0199                 scanline[x] = qRgb(palette[3 * idx + 2], palette[3 * idx + 1], palette[3 * idx + 0]);
0200             }
0201         } else if (info.grey) {
0202             // Greyscale.
0203             for (int x = 0; x < tga.width; x++) {
0204                 scanline[x] = qRgb(*src, *src, *src);
0205                 src++;
0206             }
0207         } else {
0208             // True Color.
0209             if (tga.pixel_size == 16) {
0210                 for (int x = 0; x < tga.width; x++) {
0211                     Color555 c = *reinterpret_cast<Color555 *>(src);
0212                     scanline[x] = qRgb((c.r << 3) | (c.r >> 2), (c.g << 3) | (c.g >> 2), (c.b << 3) | (c.b >> 2));
0213                     src += 2;
0214                 }
0215             } else if (tga.pixel_size == 24) {
0216                 for (int x = 0; x < tga.width; x++) {
0217                     scanline[x] = qRgb(src[2], src[1], src[0]);
0218                     src += 3;
0219                 }
0220             } else if (tga.pixel_size == 32) {
0221                 for (int x = 0; x < tga.width; x++) {
0222                     const uchar alpha = src[3];
0223                     scanline[x] = qRgba(src[2], src[1], src[0], alpha);
0224                     src += 4;
0225                     hasAlpha |= (alpha > 0);
0226                 }
0227             }
0228         }
0229     }
0230     /* According to http://www.paulbourke.net/dataformats/tga/
0231      * Targa 24 images are sometimes stored as Targa 32 images.
0232      *
0233      * In case all alpha information is transparent, we convert
0234      * image to 24 bits.
0235      */
0236     if (!hasAlpha && tga.pixel_size == 32) {
0237         img.convertTo(QImage::Format_RGB32);
0238         qWarning() << "WARNING: TGA image with 32-bit has all pixels transparent, removing alpha information.";
0239     }
0240 
0241     // Free image.
0242     delete []image;
0243 
0244     return true;
0245 }
0246 
0247 
0248 
0249 KisImportExportErrorCode KisTGAImport::convert(KisDocument *document, QIODevice *io,  KisPropertiesConfigurationSP configuration)
0250 {
0251     Q_UNUSED(configuration);
0252     QDataStream s(io);
0253     s.setByteOrder(QDataStream::LittleEndian);
0254 
0255     TgaHeader tga;
0256     s >> tga;
0257     s.device()->seek(TgaHeader::SIZE + tga.id_length);
0258 
0259 
0260     // Check image file format.
0261     if (s.atEnd()) {
0262         return ImportExportCodes::FileFormatIncorrect;
0263     }
0264 
0265     // Check supported file types.
0266     if (!isSupported(tga)) {
0267         return ImportExportCodes::FormatFeaturesUnsupported;
0268     }
0269 
0270     QImage img;
0271     bool result = loadTGA(s, tga, img);
0272 
0273     if (result == false) {
0274         return ImportExportCodes::FileFormatIncorrect;
0275     }
0276 
0277     const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->rgb8();
0278     KisImageSP image = new KisImage(document->createUndoStore(), img.width(), img.height(), colorSpace, "imported from tga");
0279 
0280     KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255);
0281     layer->paintDevice()->convertFromQImage(img, 0, 0, 0);
0282     image->addNode(layer.data(), image->rootLayer().data());
0283 
0284     document->setCurrentImage(image);
0285     return ImportExportCodes::OK;
0286 
0287 }
0288 
0289 #include "kis_tga_import.moc"
0290