Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_tga_import.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include "kis_tga_import.h"
8
9#include <QCheckBox>
10#include <QBuffer>
11#include <QSlider>
12#include <QApplication>
13
14#include <kpluginfactory.h>
15
16#include <KoColorSpace.h>
18
19#include <kis_transaction.h>
20#include <kis_paint_device.h>
21#include <KisDocument.h>
22#include <kis_image.h>
23#include <kis_paint_layer.h>
24#include <kis_node.h>
25#include <kis_group_layer.h>
26
27#include <tga.h>
28
29K_PLUGIN_FACTORY_WITH_JSON(KisTGAImportFactory, "krita_tga_import.json", registerPlugin<KisTGAImport>();)
30
31KisTGAImport::KisTGAImport(QObject *parent, const QVariantList &)
32 : KisImportExportFilter(parent)
33{
34}
35
39
40static QDataStream & operator>> (QDataStream & s, TgaHeader & head)
41{
42 s >> head.id_length;
43 s >> head.colormap_type;
44 s >> head.image_type;
45 s >> head.colormap_index;
46 s >> head.colormap_length;
47 s >> head.colormap_size;
48 s >> head.x_origin;
49 s >> head.y_origin;
50 s >> head.width;
51 s >> head.height;
52 s >> head.pixel_size;
53 s >> head.flags;
54
55 /*dbgKrita << "id_length: " << head.id_length << " - colormap_type: " << head.colormap_type << " - image_type: " << head.image_type;
56 dbgKrita << "colormap_index: " << head.colormap_index << " - colormap_length: " << head.colormap_length << " - colormap_size: " << head.colormap_size;
57 dbgKrita << "x_origin: " << head.x_origin << " - y_origin: " << head.y_origin << " - width:" << head.width << " - height:" << head.height << " - pixelsize: " << head.pixel_size << " - flags: " << head.flags;*/
58
59 return s;
60}
61
62
63static bool isSupported(const TgaHeader & head)
64{
65 if (head.image_type != TGA_TYPE_INDEXED &&
66 head.image_type != TGA_TYPE_RGB &&
67 head.image_type != TGA_TYPE_GREY &&
71 return false;
72 }
73
74 if (head.image_type == TGA_TYPE_INDEXED ||
76 if (head.colormap_length > 256 || head.colormap_size != 24 || head.colormap_type != 1) {
77 return false;
78 }
79 }
80
81 if (head.image_type == TGA_TYPE_RGB ||
82 head.image_type == TGA_TYPE_GREY ||
85 if (head.colormap_type != 0) {
86 return false;
87 }
88 }
89
90 if (head.width == 0 || head.height == 0) {
91 return false;
92 }
93
94 if (head.pixel_size != 8 && head.pixel_size != 16 &&
95 head.pixel_size != 24 && head.pixel_size != 32) {
96 return false;
97 }
98
99 return true;
100}
101
102static bool loadTGA(QDataStream & s, const TgaHeader & tga, QImage &img)
103{
104 // Create image.
105 img = QImage(tga.width, tga.height, QImage::Format_RGB32);
106
107 TgaHeaderInfo info(tga);
108
115 const bool alphaFlag = tga.flags & 0xf;
116 if (tga.pixel_size == 32 && !alphaFlag) {
117 qWarning() << "WARNING: TGA image with 32-bit pixel size reports absence of alpha channel. It is not possible, fixing...";
118 }
119
120 if (tga.pixel_size == 32 || tga.pixel_size == 16) {
121 img = QImage(tga.width, tga.height, QImage::Format_ARGB32);
122 }
123
124 uint pixel_size = (tga.pixel_size / 8);
125 uint size = tga.width * tga.height * pixel_size;
126
127 if (size < 1) {
128 dbgFile << "This TGA file is broken with size " << size;
129 return false;
130 }
131
132 // Read palette.
133 char palette[768];
134 if (info.pal) {
135 // @todo Support palettes in other formats!
136 s.readRawData(palette, 3 * tga.colormap_length);
137 }
138
139 // Allocate image.
140 uchar * const image = new uchar[size];
141
142 if (info.rle) {
143 // Decode image.
144 char * dst = (char *)image;
145 int num = size;
146
147 while (num > 0) {
148 // Get packet header.
149 uchar c;
150 s >> c;
151
152 uint count = (c & 0x7f) + 1;
153 num -= count * pixel_size;
154
155 if (num < 0) {
156 dbgFile << "This TGA file is broken: the number of pixels left to read and the number of RLE pixels do not agree" << ppVar(num) << ppVar(count) << ppVar(pixel_size);
157 return false;
158 }
159
160 if (c & 0x80) {
161 // RLE pixels.
162 Q_ASSERT(pixel_size <= 8);
163 char pixel[8];
164 s.readRawData(pixel, pixel_size);
165 do {
166 memcpy(dst, pixel, pixel_size);
167 dst += pixel_size;
168 } while (--count);
169 } else {
170 // Raw pixels.
171 count *= pixel_size;
172 s.readRawData(dst, count);
173 dst += count;
174 }
175 }
176 } else {
177 // Read raw image.
178 s.readRawData((char *)image, size);
179 }
180
181 // Convert image to internal format.
182 int y_start, y_step, y_end;
183 if (tga.flags & TGA_ORIGIN_UPPER) {
184 y_start = 0;
185 y_step = 1;
186 y_end = tga.height;
187 } else {
188 y_start = tga.height - 1;
189 y_step = -1;
190 y_end = -1;
191 }
192
193 uchar* src = image;
194
195 bool hasAlpha = false;
196 for (int y = y_start; y != y_end; y += y_step) {
197 QRgb * scanline = (QRgb *) (void*) img.scanLine(y);
198
199 if (info.pal) {
200 // Paletted.
201 for (int x = 0; x < tga.width; x++) {
202 uchar idx = *src++;
203 scanline[x] = qRgb(palette[3 * idx + 2], palette[3 * idx + 1], palette[3 * idx + 0]);
204 }
205 } else if (info.grey) {
206 // Greyscale.
207 for (int x = 0; x < tga.width; x++) {
208 scanline[x] = qRgb(*src, *src, *src);
209 src++;
210 }
211 } else {
212 // True Color.
213 if (tga.pixel_size == 16) {
214 for (int x = 0; x < tga.width; x++) {
215 Color555 c = *reinterpret_cast<Color555 *>(src);
216 scanline[x] = qRgb((c.r << 3) | (c.r >> 2), (c.g << 3) | (c.g >> 2), (c.b << 3) | (c.b >> 2));
217 src += 2;
218 }
219 } else if (tga.pixel_size == 24) {
220 for (int x = 0; x < tga.width; x++) {
221 scanline[x] = qRgb(src[2], src[1], src[0]);
222 src += 3;
223 }
224 } else if (tga.pixel_size == 32) {
225 for (int x = 0; x < tga.width; x++) {
226 const uchar alpha = src[3];
227 scanline[x] = qRgba(src[2], src[1], src[0], alpha);
228 src += 4;
229 hasAlpha |= (alpha > 0);
230 }
231 }
232 }
233 }
234 /* According to http://www.paulbourke.net/dataformats/tga/
235 * Targa 24 images are sometimes stored as Targa 32 images.
236 *
237 * In case all alpha information is transparent, we convert
238 * image to 24 bits.
239 */
240 if (!hasAlpha && tga.pixel_size == 32) {
241 img.convertTo(QImage::Format_RGB32);
242 qWarning() << "WARNING: TGA image with 32-bit has all pixels transparent, removing alpha information.";
243 }
244
245 // Free image.
246 delete []image;
247
248 return true;
249}
250
251
252
254{
255 Q_UNUSED(configuration);
256 QDataStream s(io);
257 s.setByteOrder(QDataStream::LittleEndian);
258
259 TgaHeader tga;
260 s >> tga;
261 s.device()->seek(TgaHeader::SIZE + tga.id_length);
262
263
264 // Check image file format.
265 if (s.atEnd()) {
267 }
268
269 // Check supported file types.
270 if (!isSupported(tga)) {
272 }
273
274 QImage img;
275 bool result = loadTGA(s, tga, img);
276
277 if (result == false) {
279 }
280
281 const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->rgb8();
282 KisImageSP image = new KisImage(document->createUndoStore(), img.width(), img.height(), colorSpace, "imported from tga");
283
284 KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255);
285 layer->paintDevice()->convertFromQImage(img, 0, 0, 0);
286 image->addNode(layer.data(), image->rootLayer().data());
287
288 document->setCurrentImage(image);
290
291}
292
293#include "kis_tga_import.moc"
294
unsigned int uint
KisGroupLayerSP rootLayer() const
QString nextLayerName(const QString &baseName="") const
Definition kis_image.cc:715
The base class for import and export filters.
void convertFromQImage(const QImage &image, const KoColorProfile *profile, qint32 offsetX=0, qint32 offsetY=0)
~KisTGAImport() override
KisImportExportErrorCode convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP configuration=0) override
KisTGAImport(QObject *parent, const QVariantList &)
K_PLUGIN_FACTORY_WITH_JSON(KritaASCCDLFactory, "kritaasccdl.json", registerPlugin< KritaASCCDL >();) KritaASCCDL
unsigned int QRgb
#define ppVar(var)
Definition kis_debug.h:155
#define dbgFile
Definition kis_debug.h:53
static QDataStream & operator>>(QDataStream &s, TgaHeader &head)
static bool loadTGA(QDataStream &s, const TgaHeader &tga, QImage &img)
static bool isSupported(const TgaHeader &head)
rgba palette[MAX_PALETTE]
Definition palette.c:35
Definition tga.h:65
ushort b
Definition tga.h:66
ushort r
Definition tga.h:68
ushort g
Definition tga.h:67
bool addNode(KisNodeSP node, KisNodeSP parent=KisNodeSP(), KisNodeAdditionFlags flags=KisNodeAdditionFlag::None)
KisPaintDeviceSP paintDevice
static KoColorSpaceRegistry * instance()
const KoColorSpace * rgb8(const QString &profileName=QString())
bool pal
Definition tga.h:73
bool rle
Definition tga.h:72
bool grey
Definition tga.h:75
ushort colormap_length
Definition tga.h:52
uchar id_length
Definition tga.h:48
uchar colormap_size
Definition tga.h:53
@ SIZE
Definition tga.h:61
ushort height
Definition tga.h:57
uchar pixel_size
Definition tga.h:58
ushort colormap_index
Definition tga.h:51
ushort y_origin
Definition tga.h:55
ushort width
Definition tga.h:56
uchar colormap_type
Definition tga.h:49
uchar image_type
Definition tga.h:50
uchar flags
Definition tga.h:59
ushort x_origin
Definition tga.h:54
#define TGA_ORIGIN_UPPER
Definition tga.h:44
@ TGA_TYPE_GREY
Definition tga.h:29
@ TGA_TYPE_INDEXED
Definition tga.h:27
@ TGA_TYPE_RGB
Definition tga.h:28
@ TGA_TYPE_RLE_RGB
Definition tga.h:31
@ TGA_TYPE_RLE_GREY
Definition tga.h:32
@ TGA_TYPE_RLE_INDEXED
Definition tga.h:30