Krita Source Code Documentation
Loading...
Searching...
No Matches
psd_utils.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2009 Boudewijn Rempt <boud@valdyas.org>
3 * SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8#ifndef PSD_UTILS_H
9#define PSD_UTILS_H
10
11
12#include <QtEndian>
13#include <QtGlobal>
14#include <QIODevice>
15#include <array>
16#include <psd.h>
17#include <resources/KoPattern.h>
18#include <type_traits>
19
20class QIODevice;
21class QString;
22
27inline bool psdwriteBE(QIODevice &io, const quint8 &v)
28{
29 const std::array<quint8, 2> val = {v};
30 const qint64 written = io.write(reinterpret_cast<const char *>(val.data()), 1);
31 return written == 1;
32}
33
34inline bool psdwriteLE(QIODevice &io, const quint8 &v)
35{
36 const std::array<quint8, 2> val = {v};
37 const qint64 written = io.write(reinterpret_cast<const char *>(val.data()), 1);
38 return written == 1;
39}
40
41inline bool psdwriteBE(QIODevice &io, const quint16 &v)
42{
43 const std::array<quint8, 2> val = {
44 quint8(v >> 8U),
45 quint8(v),
46 };
47 const qint64 written = io.write(reinterpret_cast<const char *>(val.data()), 2);
48 return written == 2;
49}
50
51inline bool psdwriteLE(QIODevice &io, const quint16 &v)
52{
53 const std::array<quint8, 2> val = {
54 quint8(v),
55 quint8(v >> 8U),
56 };
57 const qint64 written = io.write(reinterpret_cast<const char *>(val.data()), 2);
58 return written == 2;
59}
60
61inline bool psdwriteBE(QIODevice &io, const quint32 &v)
62{
63 const std::array<quint8, 4> val = {
64 quint8(v >> 24U),
65 quint8(v >> 16U),
66 quint8(v >> 8U),
67 quint8(v),
68 };
69 const qint64 written = io.write(reinterpret_cast<const char *>(val.data()), 4);
70 return written == 4;
71}
72
73inline bool psdwriteLE(QIODevice &io, const quint32 &v)
74{
75 const std::array<quint8, 4> val = {
76 quint8(v),
77 quint8(v >> 8U),
78 quint8(v >> 16U),
79 quint8(v >> 24U),
80 };
81 const qint64 written = io.write(reinterpret_cast<const char *>(val.data()), 4);
82 return written == 4;
83}
84
85inline bool psdwriteBE(QIODevice &io, const quint64 &v)
86{
87 const std::array<quint8, 8> val = {
88 quint8(v >> 56U),
89 quint8(v >> 48U),
90 quint8(v >> 40U),
91 quint8(v >> 32U),
92 quint8(v >> 24U),
93 quint8(v >> 16U),
94 quint8(v >> 8U),
95 quint8(v),
96 };
97 const qint64 written = io.write(reinterpret_cast<const char *>(val.data()), 8);
98 return written == 8;
99}
100
101inline bool psdwriteLE(QIODevice &io, const quint64 &v)
102{
103 const std::array<quint8, 8> val = {
104 quint8(v),
105 quint8(v >> 8U),
106 quint8(v >> 16U),
107 quint8(v >> 24U),
108 quint8(v >> 32U),
109 quint8(v >> 40U),
110 quint8(v >> 48U),
111 quint8(v >> 56U),
112 };
113 const qint64 written = io.write(reinterpret_cast<const char *>(val.data()), 8);
114 return written == 8;
115}
116
121template<typename T>
122inline bool psdwriteBE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint8), T &> v)
123{
124 return psdwriteBE(io, reinterpret_cast<quint8 &>(v));
125}
126
127template<typename T>
128inline bool psdwriteBE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint16), T &> v)
129{
130 return psdwriteBE(io, reinterpret_cast<quint16 &>(v));
131}
132
133template<typename T>
134inline bool psdwriteBE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint32), T &> v)
135{
136 return psdwriteBE(io, reinterpret_cast<quint32 &>(v));
137}
138
139template<typename T>
140inline bool psdwriteBE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint64), T &> v)
141{
142 return psdwriteBE(io, reinterpret_cast<quint64 &>(v));
143}
144
145template<typename T>
146inline bool psdwriteLE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint8), T &> v)
147{
148 return psdwriteLE(io, reinterpret_cast<quint8 &>(v));
149}
150
151template<typename T>
152inline bool psdwriteLE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint16), T &> v)
153{
154 return psdwriteLE(io, reinterpret_cast<quint16 &>(v));
155}
156
157template<typename T>
158inline bool psdwriteLE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint32), T &> v)
159{
160 return psdwriteLE(io, reinterpret_cast<quint32 &>(v));
161}
162
163template<typename T>
164inline bool psdwriteLE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint64), T &> v)
165{
166 return psdwriteLE(io, reinterpret_cast<quint64 &>(v));
167}
168
169template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian, typename T>
170inline std::enable_if_t<std::is_arithmetic<T>::value, bool> psdwrite(QIODevice &io, T v)
171{
172 if (byteOrder == psd_byte_order::psdLittleEndian) {
173 return psdwriteLE<T>(io, v);
174 } else {
175 return psdwriteBE<T>(io, v);
176 }
177}
178
179inline bool psdwrite(QIODevice &io, const QString &s)
180{
181 const QByteArray b = s.toLatin1();
182 int l = b.size();
183 const qint64 written = io.write(reinterpret_cast<const char *>(b.data()), l);
184 return written == l;
185}
186
187template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
188inline bool psdwrite_pascalstring(QIODevice &io, const QString &s)
189{
190 Q_ASSERT(s.length() < 256);
191 Q_ASSERT(s.length() >= 0);
192 if (s.length() < 0 || s.length() > 255)
193 return false;
194
195 if (s.isNull()) {
196 psdwrite<byteOrder>(io, quint8(0));
197 psdwrite<byteOrder>(io, quint8(0));
198 return true;
199 }
200
201 quint8 length = static_cast<quint8>(s.length());
202 psdwrite<byteOrder>(io, length);
203
204 const QByteArray b = s.toLatin1();
205 const qint64 written = io.write(reinterpret_cast<const char *>(b.data()), length);
206 if (written != length)
207 return false;
208
209 if ((length & 0x01) != 0) {
210 return psdwrite<byteOrder>(io, quint8(0));
211 }
212
213 return true;
214}
215
216template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
217inline bool psdwrite_pascalstring(QIODevice &io, const QString &s, int padding)
218{
219 Q_ASSERT(s.length() < 256);
220 Q_ASSERT(s.length() >= 0);
221 if (s.length() < 0 || s.length() > 255)
222 return false;
223
224 if (s.isNull()) {
225 psdwrite<byteOrder>(io, quint8(0));
226 psdwrite<byteOrder>(io, quint8(0));
227 return true;
228 }
229 quint8 length = static_cast<quint8>(s.length());
230 psdwrite<byteOrder>(io, length);
231
232 QByteArray b = s.toLatin1();
233 const qint64 written = io.write(b.data(), length);
234 if (written != length)
235 return false;
236
237 // If the total length (length byte + content) is not a multiple of padding, add zeroes to pad
238 length++;
239 if ((length % padding) != 0) {
240 for (int i = 0; i < (padding - (length % padding)); i++) {
241 psdwrite<byteOrder>(io, quint8(0));
242 }
243 }
244
245 return true;
246}
247
248inline bool psdpad(QIODevice &io, quint32 padding)
249{
250 for (quint32 i = 0; i < padding; i++) {
251 const bool written = io.putChar('\0');
252 if (!written)
253 return false;
254 }
255 return true;
256}
257
262inline bool psdreadBE(QIODevice &io, quint8 &v)
263{
264 std::array<quint8, 1> data;
265 qint64 read = io.read(reinterpret_cast<char *>(data.data()), 1);
266 if (read != 1)
267 return false;
268 v = data[0];
269 return true;
270}
271
272inline bool psdreadLE(QIODevice &io, quint8 &v)
273{
274 std::array<quint8, 1> data;
275 qint64 read = io.read(reinterpret_cast<char *>(data.data()), 1);
276 if (read != 1)
277 return false;
278 v = data[0];
279 return true;
280}
281
282inline bool psdreadBE(QIODevice &io, quint16 &v)
283{
284 std::array<quint8, 2> data;
285 qint64 read = io.read(reinterpret_cast<char *>(data.data()), 2);
286 if (read != 2)
287 return false;
288 v = quint16((quint16(data[0]) << 8U) | data[1]);
289 return true;
290}
291
292inline bool psdreadLE(QIODevice &io, quint16 &v)
293{
294 std::array<quint8, 2> data;
295 qint64 read = io.read(reinterpret_cast<char *>(data.data()), 2);
296 if (read != 2)
297 return false;
298 v = quint16((quint16(data[1]) << 8U) | data[0]);
299 return true;
300}
301
302inline bool psdreadBE(QIODevice &io, quint32 &v)
303{
304 std::array<quint8, 4> data;
305 qint64 read = io.read(reinterpret_cast<char *>(data.data()), 4);
306 if (read != 4)
307 return false;
308 v = (quint32(data[0]) << 24U) | (quint32(data[1]) << 16U) | (quint32(data[2]) << 8U) | data[3];
309 return true;
310}
311
312inline bool psdreadLE(QIODevice &io, quint32 &v)
313{
314 std::array<quint8, 4> data;
315 qint64 read = io.read(reinterpret_cast<char *>(data.data()), 4);
316 if (read != 4)
317 return false;
318 v = (quint32(data[3]) << 24U) | (quint32(data[2]) << 16U) | (quint32(data[1]) << 8U) | data[0];
319 return true;
320}
321
322inline bool psdreadBE(QIODevice &io, quint64 &v)
323{
324 std::array<quint8, 8> data;
325 qint64 read = io.read(reinterpret_cast<char *>(data.data()), 8);
326 if (read != 8)
327 return false;
328 v = (quint64(data[0]) << 56U) | (quint64(data[1]) << 48U) | (quint64(data[2]) << 40U) | (quint64(data[3]) << 32U) | (quint64(data[4]) << 24U)
329 | (quint64(data[5]) << 16U) | (quint64(data[6]) << 8U) | data[7];
330 return true;
331}
332
333inline bool psdreadLE(QIODevice &io, quint64 &v)
334{
335 std::array<quint8, 8> data;
336 qint64 read = io.read(reinterpret_cast<char *>(data.data()), 8);
337 if (read != 8)
338 return false;
339 v = (quint64(data[7]) << 56U) | (quint64(data[6]) << 48U) | (quint64(data[5]) << 40U) | (quint64(data[4]) << 32U) | (quint64(data[3]) << 24U)
340 | (quint64(data[2]) << 16U) | (quint64(data[1]) << 8U) | data[0];
341 return true;
342}
343
348template<typename T>
349inline bool psdreadBE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint8), T &> v)
350{
351 return psdreadBE(io, reinterpret_cast<quint8 &>(v));
352}
353
354template<typename T>
355inline bool psdreadBE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint16), T &> v)
356{
357 return psdreadBE(io, reinterpret_cast<quint16 &>(v));
358}
359
360template<typename T>
361inline bool psdreadBE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint32), T &> v)
362{
363 return psdreadBE(io, reinterpret_cast<quint32 &>(v));
364}
365
366template<typename T>
367inline bool psdreadBE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint64), T &> v)
368{
369 return psdreadBE(io, reinterpret_cast<quint64 &>(v));
370}
371
372template<typename T>
373inline bool psdreadLE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint8), T &> v)
374{
375 return psdreadLE(io, reinterpret_cast<quint8 &>(v));
376}
377
378template<typename T>
379inline bool psdreadLE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint16), T &> v)
380{
381 return psdreadLE(io, reinterpret_cast<quint16 &>(v));
382}
383
384template<typename T>
385inline bool psdreadLE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint32), T &> v)
386{
387 return psdreadLE(io, reinterpret_cast<quint32 &>(v));
388}
389
390template<typename T>
391inline bool psdreadLE(QIODevice &io, std::enable_if_t<sizeof(T) == sizeof(quint64), T &> v)
392{
393 return psdreadLE(io, reinterpret_cast<quint64 &>(v));
394}
395
396template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian, typename T>
397inline std::enable_if_t<std::is_arithmetic<T>::value, bool> psdread(QIODevice &io, T &v)
398{
399 if (byteOrder == psd_byte_order::psdLittleEndian) {
400 return psdreadLE<T>(io, v);
401 } else {
402 return psdreadBE<T>(io, v);
403 }
404}
405
406template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
407inline QByteArray psdreadBytes(QIODevice &io, qint64 v)
408{
409 QByteArray b = io.read(v);
410 if (byteOrder == psd_byte_order::psdLittleEndian) {
411 std::reverse(b.begin(), b.end());
412 }
413 return b;
414}
415
416template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
417inline bool psdread_pascalstring(QIODevice &io, QString &s, qint64 padding)
418{
419 quint8 length;
420 if (!psdread<byteOrder>(io, length)) {
421 return false;
422 }
423
424 if (length == 0) {
425 // read the padding
426 for (qint64 i = 0; i < padding - 1; ++i) {
427 io.seek(io.pos() + 1);
428 }
429 return true;
430 }
431
432 QByteArray chars = io.read(length);
433 if (chars.length() != length) {
434 return false;
435 }
436
437 // read padding byte
438 quint32 paddedLength = length + 1;
439 if (padding > 0) {
440 while (paddedLength % padding != 0) {
441 if (!io.seek(io.pos() + 1)) {
442 return false;
443 }
444 paddedLength++;
445 }
446 }
447
448 s.append(QString::fromLatin1(chars));
449 if (s.endsWith(QChar::Space)) {
450 s.chop(1);
451 }
452
453 return true;
454}
455
456template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
457inline bool psdread_unicodestring(QIODevice &io, QString &s)
458{
459 quint32 stringlen;
460 if (!psdread<byteOrder>(io, stringlen)) {
461 return false;
462 }
463
464 s.fill(QChar::Space, static_cast<int>(stringlen));
465
466 for (quint32 i = 0; i < stringlen; ++i) {
467 quint16 ch(0);
468 if (!psdread<byteOrder>(io, ch)) {
469 return false;
470 }
471
472 // XXX: this makes it possible to append garbage
473 if (ch != 0) {
474 s[i] = QChar(ch);
475 }
476 }
477 if (s.endsWith(QChar::Space)) {
478 s.chop(1);
479 }
480
481 return true;
482}
483
484template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
485inline bool psd_read_blendmode(QIODevice &io, QString &blendModeKey)
486{
487 QByteArray b(psdreadBytes<byteOrder>(io, 4));
488 if (b.size() != 4 || QString(b) != "8BIM") {
489 return false;
490 }
491 blendModeKey = QString(psdreadBytes<byteOrder>(io, 4));
492 if (blendModeKey.size() != 4) {
493 return false;
494 }
495 return true;
496}
497
498// Copied from Scribus decodePSDfloat in scimgdataloader.cpp by Franz Schmid
499template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
500inline double psdreadFixedPoint(QIODevice &io)
501{
502 quint32 data;
503 double ret = 0.0;
504
505 if (psdread<byteOrder>(io, data)) {
506 char man = (data & 0xFF000000) >> 24;
507 if (man >= 0)
508 {
509 ret = (data & 0x00FFFFFF) / 16777215.0;
510 ret = (ret + man);
511 }
512 else
513 {
514 ret = (~data & 0x00FFFFFF) / 16777215.0;
515 ret = (ret + ~man) * -1;
516 }
517 }
518 return ret;
519}
520
521template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
522inline void psdwriteFixedPoint(QIODevice &io, double val)
523{
524 qint32 data;
525 double max24 = 16777215.0;
526 // val is bound to -16 to +16
527
528 qint32 man = qint32(val);
529 quint32 frac= quint32(fabs(val - man) * max24);
530 data = (qAbs(man) << 24) | frac;
531 if (val < 0) {
532 data *= -1;
533 };
534
535 psdwrite<byteOrder>(io, data);
536}
537
538#endif // PSD_UTILS_H
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
qreal v
double psdreadFixedPoint(QIODevice &io)
Definition psd_utils.h:500
std::enable_if_t< std::is_arithmetic< T >::value, bool > psdread(QIODevice &io, T &v)
Definition psd_utils.h:397
void psdwriteFixedPoint(QIODevice &io, double val)
Definition psd_utils.h:522
bool psdwriteLE(QIODevice &io, const quint8 &v)
Definition psd_utils.h:34
bool psdreadBE(QIODevice &io, quint8 &v)
Definition psd_utils.h:262
bool psdwrite_pascalstring(QIODevice &io, const QString &s)
Definition psd_utils.h:188
bool psdreadLE(QIODevice &io, quint8 &v)
Definition psd_utils.h:272
QByteArray psdreadBytes(QIODevice &io, qint64 v)
Definition psd_utils.h:407
bool psdread_pascalstring(QIODevice &io, QString &s, qint64 padding)
Definition psd_utils.h:417
bool psdpad(QIODevice &io, quint32 padding)
Definition psd_utils.h:248
bool psdread_unicodestring(QIODevice &io, QString &s)
Definition psd_utils.h:457
bool psdwriteBE(QIODevice &io, const quint8 &v)
Definition psd_utils.h:27
bool psd_read_blendmode(QIODevice &io, QString &blendModeKey)
Definition psd_utils.h:485
std::enable_if_t< std::is_arithmetic< T >::value, bool > psdwrite(QIODevice &io, T v)
Definition psd_utils.h:170