psd_layer_record.cpp 39.6 KB
Newer Older
Halla Rempt's avatar
Halla Rempt committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
 *  Copyright (c) 2009 Boudewijn Rempt <boud@valdyas.org>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
#include "psd_layer_record.h"

20
21
#include <netinet/in.h> // htonl

Halla Rempt's avatar
Halla Rempt committed
22
23
24
#include <QIODevice>
#include <QBuffer>
#include <QDataStream>
25
#include <QStringList>
Halla Rempt's avatar
Halla Rempt committed
26

27
#include <kis_debug.h>
28
29
30
#include <kis_node.h>
#include "kis_iterator_ng.h"
#include <kis_paint_layer.h>
31

Halla Rempt's avatar
Halla Rempt committed
32
#include "psd_utils.h"
33
#include "psd_header.h"
34
#include "compression.h"
Halla Rempt's avatar
Halla Rempt committed
35

36
37
38
#include <KoColorSpace.h>
#include <KoColorSpaceMaths.h>
#include <KoColorSpaceTraits.h>
39

40
// Just for pretty debug messages
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
QString channelIdToChannelType(int channelId, PSDColorMode colormode)
{
    switch(channelId) {
    case -2:
        return "User Supplied Layer Mask";
    case -1:
        return "Transparency mask";
    case  0:
        switch(colormode) {
        case Bitmap:
        case Indexed:
            return QString("bitmap or indexed: %1").arg(channelId);
        case Grayscale:
        case Gray16:
            return "gray";
        case RGB:
        case RGB48:
            return "red";
        case Lab:
        case Lab48:
            return "L";
        case CMYK:
        case CMYK64:
            return "cyan";
        case MultiChannel:
        case DeepMultichannel:
            return QString("multichannel channel %1").arg(channelId);
        case DuoTone:
        case Duotone16:
            return QString("duotone channel %1").arg(channelId);
        default:
            return QString("unknown: %1").arg(channelId);
        };
    case 1:
        switch(colormode) {
        case Bitmap:
        case Indexed:
            return QString("WARNING bitmap or indexed: %1").arg(channelId);
        case Grayscale:
        case Gray16:
            return QString("WARNING: %1").arg(channelId);
        case RGB:
        case RGB48:
            return "green";
        case Lab:
        case Lab48:
            return "a";
        case CMYK:
        case CMYK64:
            return "Magenta";
        case MultiChannel:
        case DeepMultichannel:
            return QString("multichannel channel %1").arg(channelId);
        case DuoTone:
        case Duotone16:
            return QString("duotone channel %1").arg(channelId);
        default:
            return QString("unknown: %1").arg(channelId);
        };
    case 2:
        switch(colormode) {
        case Bitmap:
        case Indexed:
            return QString("WARNING bitmap or indexed: %1").arg(channelId);
        case Grayscale:
        case Gray16:
            return QString("WARNING: %1").arg(channelId);
        case RGB:
        case RGB48:
            return "blue";
        case Lab:
        case Lab48:
            return "b";
        case CMYK:
        case CMYK64:
            return "yellow";
        case MultiChannel:
        case DeepMultichannel:
            return QString("multichannel channel %1").arg(channelId);
        case DuoTone:
        case Duotone16:
            return QString("duotone channel %1").arg(channelId);
        default:
            return QString("unknown: %1").arg(channelId);
        };
    case 3:
        switch(colormode) {
        case Bitmap:
        case Indexed:
            return QString("WARNING bitmap or indexed: %1").arg(channelId);
        case Grayscale:
        case Gray16:
            return QString("WARNING: %1").arg(channelId);
        case RGB:
        case RGB48:
136
            return QString("alpha: %1").arg(channelId);
137
138
        case Lab:
        case Lab48:
139
            return QString("alpha: %1").arg(channelId);
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
        case CMYK:
        case CMYK64:
            return "Key";
        case MultiChannel:
        case DeepMultichannel:
            return QString("multichannel channel %1").arg(channelId);
        case DuoTone:
        case Duotone16:
            return QString("duotone channel %1").arg(channelId);
        default:
            return QString("unknown: %1").arg(channelId);
        };
    default:
        return QString("unknown: %1").arg(channelId);
    };

}

158
PSDLayerRecord::PSDLayerRecord(const PSDHeader& header)
159
160
161
162
163
164
165
166
167
168
169
170
    : top(0)
    , left(0)
    , bottom(0)
    , right(0)
    , nChannels(0)
    , opacity(0)
    , clipping(0)
    , transparencyProtected(false)
    , visible(true)
    , irrelevant(false)
    , layerName("UNINITIALIZED")
    , m_header(header)
Halla Rempt's avatar
Halla Rempt committed
171
172
173
174
175
{
}

bool PSDLayerRecord::read(QIODevice* io)
{
176
177
    dbgFile << "Going to read layer record. Pos:" << io->pos();

Halla Rempt's avatar
Halla Rempt committed
178
    if (!psdread(io, &top)  ||
179
180
181
182
            !psdread(io, &left) ||
            !psdread(io, &bottom) ||
            !psdread(io, &right) ||
            !psdread(io, &nChannels)) {
Halla Rempt's avatar
Halla Rempt committed
183
184
185
186

        error = "could not read layer record";
        return false;
    }
187

188
    dbgFile << "\ttop" << top << "left" << left << "bottom" << bottom << "right" << right << "number of channels" << nChannels;
189

190
191
192
193
194
    Q_ASSERT(top <= bottom);
    Q_ASSERT(left <= right);
    Q_ASSERT(nChannels > 0);


195
    switch(m_header.colormode) {
196
197
198
199
200
    case(Bitmap):
    case(Indexed):
    case(DuoTone):
    case(Grayscale):
    case(MultiChannel):
201
        if (nChannels < 1) {
202
203
204
205
            error = QString("Not enough channels. Got: %1").arg(nChannels);
            return false;
        }
        break;
206
207
208
    case(RGB):
    case(CMYK):
    case(Lab):
209
    default:
210
        if (nChannels < 3) {
211
212
213
214
215
216
217
218
219
220
221
            error = QString("Not enough channels. Got: %1").arg(nChannels);
            return false;
        }
        break;
    };

    if (nChannels > MAX_CHANNELS) {
        error = QString("Too many channels. Got: %1").arg(nChannels);
        return false;
    }

Halla Rempt's avatar
Halla Rempt committed
222
223
224
225
226
227
228
    for (int i = 0; i < nChannels; ++i) {

        if (io->atEnd()) {
            error = "Could not read enough data for channels";
            return false;
        }

229
        ChannelInfo* info = new ChannelInfo;
230
231

        if (!psdread(io, &info->channelId)) {
Halla Rempt's avatar
Halla Rempt committed
232
            error = "could not read channel id";
233
            delete info;
Halla Rempt's avatar
Halla Rempt committed
234
235
236
            return false;
        }
        bool r;
237
        if (m_header.version == 1) {
Halla Rempt's avatar
Halla Rempt committed
238
239
            quint32 channelDataLength;
            r = psdread(io, &channelDataLength);
240
            info->channelDataLength = (quint64)channelDataLength;
Halla Rempt's avatar
Halla Rempt committed
241
242
        }
        else {
243
            r = psdread(io, &info->channelDataLength);
Halla Rempt's avatar
Halla Rempt committed
244
245
246
        }
        if (!r) {
            error = "Could not read length for channel data";
247
            delete info;
Halla Rempt's avatar
Halla Rempt committed
248
249
250
            return false;
        }

251
252
253
254
255
256
257
//        dbgFile << "\tchannel" << i << "id"
//                << channelIdToChannelType(info->channelId, m_header.colormode)
//                << "length" << info->channelDataLength
//                << "start" << info->channelDataStart
//                << "offset" << info->channelOffset
//                << "channelInfoPosition" << info->channelInfoPosition;

Halla Rempt's avatar
Halla Rempt committed
258
259
260
        channelInfoRecords << info;
    }

Halla Rempt's avatar
Halla Rempt committed
261
262
263
264
265
    QByteArray b;
    b = io->read(4);
    if(b.size() != 4 || QString(b) != "8BIM") {
        error = QString("Could not read blend mode signature for layer. Got %1.")
                .arg(QString(b));
Halla Rempt's avatar
Halla Rempt committed
266
267
        return false;
    }
268
    dbgFile << "reading blend mode at pos" << io->pos();
Halla Rempt's avatar
Halla Rempt committed
269
270
271
272
273
274
    blendModeKey = QString(io->read(4));
    if (blendModeKey.size() != 4) {
        error = QString("Could not read blend mode key. Got: %1").arg(blendModeKey);
        return false;
    }

275
    dbgFile << "\tBlend mode" << blendModeKey << "pos" << io->pos();
276

Halla Rempt's avatar
Halla Rempt committed
277
278
279
280
281
    if (!psdread(io, &opacity)) {
        error = "Could not read opacity";
        return false;
    }

282
    dbgFile << "\tOpacity" << opacity << io->pos();
283

Halla Rempt's avatar
Halla Rempt committed
284
285
286
287
288
    if (!psdread(io, &clipping)) {
        error = "Could not read clipping";
        return false;
    }

289
    dbgFile << "\tclipping" << clipping << io->pos();
290

Halla Rempt's avatar
Halla Rempt committed
291
292
293
294
295
    quint8 flags;
    if (!psdread(io, &flags)) {
        error = "Could not read flags";
        return false;
    }
296
    dbgFile << "\tflags" << flags << io->pos();
Halla Rempt's avatar
Halla Rempt committed
297

Halla Rempt's avatar
Halla Rempt committed
298
    transparencyProtected = flags & 1 ? true : false;
299

300
    dbgFile << "\ttransparency protected" << transparencyProtected;
301

Halla Rempt's avatar
Halla Rempt committed
302
    visible = flags & 2 ? false : true;
303

304
    dbgFile << "\tvisible" << visible;
305

Halla Rempt's avatar
Halla Rempt committed
306
307
308
309
310
311
312
    if (flags & 8) {
        irrelevant = flags & 16 ? true : false;
    }
    else {
        irrelevant = false;
    }

313
    dbgFile << "\tirrelevant" << irrelevant;
314

315
    dbgFile << "\tfiller at " << io->pos();
Halla Rempt's avatar
Halla Rempt committed
316
317
318

    quint8 filler;
    if (!psdread(io, &filler) || filler != 0) {
Halla Rempt's avatar
Halla Rempt committed
319
320
321
322
        error = "Could not read padding";
        return false;
    }

323
    dbgFile << "\tGoing to read extra data length" << io->pos();
Halla Rempt's avatar
Halla Rempt committed
324

325
    quint32 extraDataLength;
Halla Rempt's avatar
Halla Rempt committed
326
    if (!psdread(io, &extraDataLength) || io->bytesAvailable() < extraDataLength) {
327
328
329
        error = QString("Could not read extra layer data: %1 at pos %2").arg(extraDataLength).arg(io->pos());
        return false;
    }
Halla Rempt's avatar
Halla Rempt committed
330

331
    dbgFile << "\tExtra data length" << extraDataLength;
Halla Rempt's avatar
Halla Rempt committed
332

333
    if (extraDataLength > 0) {
Halla Rempt's avatar
Halla Rempt committed
334

335
336
337
        dbgFile << "Going to read extra data field. Bytes available: "
                << io->bytesAvailable()
                << "pos" << io->pos();
Halla Rempt's avatar
Halla Rempt committed
338

339
340
        quint32 layerMaskLength = 1; // invalid...
        if (!psdread(io, &layerMaskLength) ||
341
342
                io->bytesAvailable() < layerMaskLength ||
                !(layerMaskLength == 0 || layerMaskLength == 20 || layerMaskLength == 36)) {
343
344
345
            error = QString("Could not read layer mask length: %1").arg(layerMaskLength);
            return false;
        }
346

347
        memset(&layerMask, 0, sizeof(LayerMaskData));
348

349
350
        if (layerMaskLength == 20 || layerMaskLength == 36) {
            if (!psdread(io, &layerMask.top)  ||
351
352
353
354
355
                    !psdread(io, &layerMask.left) ||
                    !psdread(io, &layerMask.bottom) ||
                    !psdread(io, &layerMask.top) ||
                    !psdread(io, &layerMask.defaultColor) ||
                    !psdread(io, &flags)) {
356
357
358
359

                error = "could not read mask record";
                return false;
            }
Halla Rempt's avatar
Halla Rempt committed
360
        }
361
362
363
364
365
366
        if (layerMaskLength == 20) {
            quint16 padding;
            if (!psdread(io, &padding)) {
                error = "Could not read layer mask padding";
                return false;
            }
Halla Rempt's avatar
Halla Rempt committed
367
        }
368
369
370
371


        if (layerMaskLength == 36 ) {
            if (!psdread(io, &flags) ||
372
373
374
375
376
                    !psdread(io, &layerMask.defaultColor) ||
                    !psdread(io, &layerMask.top)  ||
                    !psdread(io, &layerMask.left) ||
                    !psdread(io, &layerMask.bottom) ||
                    !psdread(io, &layerMask.top)) {
377
378
379
380

                error = "could not read 'real' mask record";
                return false;
            }
Halla Rempt's avatar
Halla Rempt committed
381
382
        }

383
384
385
        layerMask.positionedRelativeToLayer = flags & 1 ? true : false;
        layerMask.disabled = flags & 2 ? true : false;
        layerMask.invertLayerMaskWhenBlending = flags & 4 ? true : false;
386

387
388
        dbgFile << "\tRead layer mask/adjustment layer data. Length of block:"
                << layerMaskLength << "pos" << io->pos();
389

390
391
392
393
394
395
        // layer blending thingies
        quint32 blendingDataLength;
        if (!psdread(io, &blendingDataLength) || io->bytesAvailable() < blendingDataLength) {
            error = "Could not read extra blending data.";
            return false;
        }
Halla Rempt's avatar
Halla Rempt committed
396

397
        //dbgFile << "blending block data length" << blendingDataLength << ", pos" << io->pos();
Halla Rempt's avatar
Halla Rempt committed
398

399
400
401
402
403
        blendingRanges.data = io->read(blendingDataLength);
        if ((quint32)blendingRanges.data.size() != blendingDataLength) {
            error = QString("Got %1 bytes for the blending range block, needed %2").arg(blendingRanges.data.size(), blendingDataLength);
        }
        /*
404
        // XXX: reading this block correctly failed, I have more channel ranges than I'd expected.
405

406
407
408
409
410
        if (!psdread(io, &blendingRanges.blackValues[0]) ||
            !psdread(io, &blendingRanges.blackValues[1]) ||
            !psdread(io, &blendingRanges.whiteValues[0]) ||
            !psdread(io, &blendingRanges.whiteValues[1]) ||
            !psdread(io, &blendingRanges.compositeGrayBlendDestinationRange)) {
411

412
            error = "Could not read blending black/white values";
Halla Rempt's avatar
Halla Rempt committed
413
414
            return false;
        }
415
416
417
418
419
420
421
422
423
424
425
426

        for (int i = 0; i < nChannels; ++i) {
            quint32 src;
            quint32 dst;
            if (!psdread(io, &src) || !psdread(io, &dst)) {
                error = QString("could not read src/dst range for channel %1").arg(i);
                return false;
            }
            dbgFile << "\tread range " << src << "to" << dst << "for channel" << i;
            blendingRanges.sourceDestinationRanges << QPair<quint32, quint32>(src, dst);
        }
        */
427
428
429
430
431
432
        dbgFile << "\tGoing to read layer name at" << io->pos();
        quint8 layerNameLength;
        if (!psdread(io, &layerNameLength)) {
            error = "Could not read layer name length";
            return false;
        }
Halla Rempt's avatar
Halla Rempt committed
433

434
435
        dbgFile << "\tlayer name length unpadded" << layerNameLength << "pos" << io->pos();
        layerNameLength = ((layerNameLength + 1 + 3) & ~0x03) - 1;
Halla Rempt's avatar
Halla Rempt committed
436

437
438
439
        dbgFile << "\tlayer name length padded" << layerNameLength << "pos" << io->pos();
        layerName = io->read(layerNameLength);
        dbgFile << "\tlayer name" << layerName << io->pos();
440

441
442
443
        QStringList longBlocks;
        if (m_header.version > 1) {
            longBlocks << "LMsk" << "Lr16" << "Layr" << "Mt16" << "Mtrn" << "Alph";
444
445
        }

446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
        while(!io->atEnd()) {

            // read all the additional layer info 8BIM blocks
            QByteArray b;
            b = io->peek(4);
            if(b.size() != 4 || QString(b) != "8BIM") {
                break;
            }
            else {
                io->seek(io->pos() + 4); // skip the 8BIM header we peeked ahead for
            }

            QString key(io->read(4));
            if (key.size() != 4) {
                error = "Could not read key for additional layer info block";
                return false;
            }
Halla Rempt's avatar
Halla Rempt committed
463
            dbgFile << "found info block with key" << key;
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486

            if (infoBlocks.contains(key)) {
                error = QString("Duplicate layer info block with key %1").arg(key);
                return false;
            }

            quint64 size;
            if (longBlocks.contains(key)) {
                psdread(io, &size);
            }
            else {
                quint32 _size;
                psdread(io, &_size);
                size = _size;
            }

            LayerInfoBlock* infoBlock = new LayerInfoBlock();
            infoBlock->data = io->read(size);
            if (infoBlock->data.size() != (qint64)size) {
                error = QString("Could not read full info block for key %1 for layer %2").arg(key).arg(layerName);
                return false;
            }

Halla Rempt's avatar
Halla Rempt committed
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
            dbgFile << "\tRead layer info block" << key << "for size" << infoBlock->data.size();

            // get the unicode layer name
            if (key == "luni") {
                QBuffer buf(&infoBlock->data);
                buf.open(QBuffer::ReadOnly);

                quint32 stringlen;
                if (!psdread(&buf, &stringlen)) {
                    error = "Could not read string length for luni block";
                    return false;
                }
                QString unicodeLayerName;

                for (uint i = 0; i < stringlen; ++i) {
                    quint16 ch;
                    psdread(&buf, &ch);
                    QChar uch(ch);
                    unicodeLayerName.append(uch);
                }

                dbgFile << "unicodeLayerName" << unicodeLayerName;
                if (!unicodeLayerName.isEmpty()) {
                    layerName = unicodeLayerName;
                }
            }

514
515

            infoBlocks[key] = infoBlock;
516
517
518
        }
    }

Halla Rempt's avatar
Halla Rempt committed
519
520
521
    return valid();
}

522
bool PSDLayerRecord::write(QIODevice* io, KisNodeSP node)
Halla Rempt's avatar
Halla Rempt committed
523
{
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
    dbgFile << "writing layer info record" << node->name() << "at" << io->pos();

    m_node = node;

    dbgFile << "saving layer record for " << layerName << "at pos" << io->pos();
    dbgFile << "\ttop" << top << "left" << left << "bottom" << bottom << "right" << right << "number of channels" << nChannels;
    Q_ASSERT(left <= right);
    Q_ASSERT(top <= bottom);
    Q_ASSERT(nChannels > 0);
    psdwrite(io, (quint32)top);
    psdwrite(io, (quint32)left);
    psdwrite(io, (quint32)bottom);
    psdwrite(io, (quint32)right);
    psdwrite(io, (quint16)nChannels);

    foreach(ChannelInfo *channel, channelInfoRecords) {
        psdwrite(io, (quint16)channel->channelId);
        channel->channelInfoPosition = io->pos();
        dbgFile << "ChannelInfo record position:" << channel->channelInfoPosition << "channel id" << channel->channelId;
        psdwrite(io, (quint32)0); // to be filled in when we know how big each channel block is going to be
Halla Rempt's avatar
Halla Rempt committed
544
    }
545
546
547
548

    // blend mode
    io->write("8BIM", 4);
    dbgFile << "blendModeKey" << blendModeKey << "pos" << io->pos();
549
    io->write(blendModeKey.toLatin1());
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579

    // opacity
    psdwrite(io, opacity);

    // clipping - unused
    psdwrite(io, clipping);

    // visibility and protection
    quint8 flags = 0;
    if (transparencyProtected) flags |= 1;
    if (!visible) flags |= 2;
    psdwrite(io, flags);


    // padding byte to make the length even
    psdwrite(io, (quint8)0);

    // position of the extra data size
    quint64 extraDataPos = io->pos();
    psdwrite(io, (quint32)0); // length of the extra data fields

    // layer mask data: not implemented for now, so zero
    psdwrite(io, quint32(0));

    // Layer blending ranges: not implemented for now, so zero
    psdwrite(io, quint32(0));

    // layer name: Pascal string, padded to a multiple of 4 bytes.
    psdwrite_pascalstring(io, layerName, 4);

580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
    // write luni data block
    {
        quint32 len = qMin(layerName.length(), 255);
        quint32 xdBlockSize = len;

        if (len % 2) {
            xdBlockSize = len + 1;
        }
        xdBlockSize = (xdBlockSize * 2) + 4;

        io->write("8BIMluni", 8);
        psdwrite(io, xdBlockSize);
        psdwrite(io, len);

        const ushort *chars = layerName.utf16();
        for (uint i = 0; i < len; i++) {
            psdwrite(io, (quint16)chars[i]);
        }

        if (len % 2) {
            psdwrite(io, (quint16)0); // padding
        }
    }
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
    // write real length for extra data

    quint64 eofPos = io->pos();
    io->seek(extraDataPos);
    psdwrite(io, (quint32)(eofPos - extraDataPos - sizeof(quint32)));
    dbgFile << "ExtraData size" << (eofPos - extraDataPos - sizeof(quint32))
            << "extra data pos" << extraDataPos
            << "eofpos" << eofPos;

    // retor to eof to continue writing
    io->seek(eofPos);

    return true;
}

bool PSDLayerRecord::writePixelData(QIODevice *io)
{
    dbgFile << "writing pixel data for layer" << layerName << "at" << io->pos();

    KisPaintDeviceSP dev = m_node->projection();

    // now write all the channels in display order
Halla Rempt's avatar
Halla Rempt committed
625
    QRect rc = dev->extent();
626
627

    // yeah... we read the entire layer into a vector of quint8 arrays
Halla Rempt's avatar
Halla Rempt committed
628
629
630
631
632
    dbgFile << "layer" << layerName;
    dbgFile << "\tnode x" << m_node->x() << "paint device x" << dev->x() << "extent x" << rc.x();
    dbgFile << "\tnode y" << m_node->y() << "paint device x" << dev->y() << "extent y" << rc.y();
    QVector<quint8* > tmp = dev->readPlanarBytes(rc.x() - m_node->x(), rc.y() -m_node->y(), rc.width(), rc.height());

633
634
635
//    KisPaintDeviceSP dev2 = new KisPaintDevice(dev->colorSpace());
//    dev2->writePlanarBytes(tmp, 0, 0, rc.width(), rc.height());
//    dev2->convertToQImage(0).save(layerName + ".png");
636
637
638
639

    // then reorder the planes to fit the psd model -- alpha first, then display order
    QVector<quint8* > planes;
    foreach(KoChannelInfo *ch, KoChannelInfo::displayOrderSorted(dev->colorSpace()->channels())) {
640
        qDebug() << ">>>\t" << ch->name() << ch->displayPosition() << ch->channelType();
641
        if (ch->channelType() == KoChannelInfo::ALPHA) {
642
            planes.insert(0, tmp[ch->displayPosition()]);
643
644
        }
        else {
645
            planes.append(tmp[ch->displayPosition()]);
646
647
648
        }
    }

649
650
    // now planes are holding pointers to quint8 arrays
    tmp.clear();
651

652
653
654
    // here's where we save the total size of the channel data
    for (int channelInfoIndex = 0; channelInfoIndex  < nChannels; ++channelInfoIndex) {

655
656
657
658
659
        dbgFile << "\tWriting channel" << channelInfoIndex << "psd channel id" << channelInfoRecords[channelInfoIndex]->channelId;

        // if the bitdepth > 8, place the bytes in the right order
        // if cmyk, invert the pixel value
        if (m_header.channelDepth == 8) {
Halla Rempt's avatar
Halla Rempt committed
660
            if (channelInfoRecords[channelInfoIndex]->channelId >= 0 && (m_header.colormode == CMYK || m_header.colormode == CMYK64)) {
661
662
663
664
665
666
667
668
669
670
                for (int i = 0; i < rc.width() * rc.height(); ++i) {
                    planes[channelInfoIndex][i] = 255 - planes[channelInfoIndex][i];
                }
            }
        }
        else if (m_header.channelDepth == 16) {
            quint16 val;
            for (int i = 0; i < rc.width() * rc.height(); ++i) {
                val = reinterpret_cast<quint16*>(planes[channelInfoIndex])[i];
                val = ntohs(val);
Halla Rempt's avatar
Halla Rempt committed
671
                if (channelInfoRecords[channelInfoIndex]->channelId >= 0 && (m_header.colormode == CMYK || m_header.colormode == CMYK64)) {
672
673
674
675
676
                     val = quint16_MAX - val;
                }
                reinterpret_cast<quint16*>(planes[channelInfoIndex])[i] = val;
            }
        }
677
678
        quint32 len = 0;

679

680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742

        // where this block starts, for the total size calculation
        quint64 startChannelBlockPos = io->pos();

        // XXX: make the compression settting configurable. For now, always use RLE.
        psdwrite(io, (quint16)Compression::RLE);
        len += sizeof(quint16);

        // where this block starts, for the total size calculation
        quint64 channelRLESizePos = io->pos();

        // write zero's for the channel lengths section
        for(int i = 0; i < rc.height(); ++i) {
            psdwrite(io, (quint16)0);
        }
        len += rc.height() * sizeof(quint16);

        // here the actual channel data starts; that's where we return after writing
        // the size of the current row
        quint64 channelStartPos = io->pos();

        quint8 *plane = planes[channelInfoIndex];
        quint32 stride = (m_header.channelDepth / 8) * rc.width();
        for (qint32 row = 0; row < rc.height(); ++row) {

            QByteArray uncompressed = QByteArray::fromRawData((const char*)plane + row * stride, stride);
            QByteArray compressed = Compression::compress(uncompressed, Compression::RLE);
            quint16 size = compressed.size();

            io->seek(channelRLESizePos);
            psdwrite(io, size);
            channelRLESizePos +=2;
            io->seek(channelStartPos);

            if (!io->write(compressed) == size) {
                error = "Could not write image data";
                return false;
            }
            len += size;

            // dbgFile << "\t\tUncompressed:" << uncompressed.size() << "compressed" << compressed.size();
            // QByteArray control = Compression::uncompress(rc.width(), compressed, Compression::RLE);
            // Q_ASSERT(qstrcmp(control, uncompressed) == 0);


            // If the layer's size, and therefore the data, is odd, a pad byte will be inserted
            // at the end of the row. (weirdly enough, that's not true for the image data)
//            if ((size & 0x01) != 0) {
//                psdwrite(io, (quint8)0);
//                size++;
//            }

            channelStartPos += size;
        }
        // write the size of the channel image data block in the channel info block
        quint64 currentPos = io->pos();
        io->seek(channelInfoRecords[channelInfoIndex]->channelInfoPosition);
        Q_ASSERT(len == currentPos - startChannelBlockPos);
        dbgFile << "\t\ttotal length" << len << "calculated length" << currentPos - startChannelBlockPos << "writing at" << channelInfoRecords[channelInfoIndex]->channelInfoPosition;
        psdwrite(io, (quint32)(currentPos - startChannelBlockPos));
        io->seek(currentPos);
    }

743
744
745
    qDeleteAll(planes);
    planes.clear();

746
747
748
    return true;


Halla Rempt's avatar
Halla Rempt committed
749
750
751
752
}

bool PSDLayerRecord::valid()
{
753
754
755
756
    // XXX: check validity!
    return true;
}

757
bool PSDLayerRecord::readPixelData(QIODevice *io, KisPaintDeviceSP device)
758
{
759
    dbgFile << "Reading pixel data for layer" << layerName << "pos" << io->pos();
760
761
    switch (m_header.colormode) {
    case Bitmap:
762
        error = "Unsupported color mode: bitmap";
763
        return false; // Not supported;
764
    case Indexed:
765
766
        error = "Unsupported color mode: indexed";
        return false; // Not supported;
767
    case MultiChannel:
768
        error = "Unsupported color mode: indexed";
769
        return false; // Not supported
770
    case DuoTone:
771
        error = "Unsupported color mode: Duotone";
772
        return false; // Not supported
773
774
775
776
777
778
    case Grayscale:
        return doGrayscale(device, io);
    case RGB:
        return doRGB(device, io);
    case CMYK:
        return doCMYK(device, io);
779
    case Lab:
780
        return doLAB(device, io);
781
782
    case UNKNOWN:
    default:
783
        return false;
784
785
    }

786
    return false;
787
788
}

Halla Rempt's avatar
Halla Rempt committed
789
bool PSDLayerRecord::doGrayscale(KisPaintDeviceSP /*dev*/, QIODevice */*io*/)
790
791
792
{
    return false;
}
793

794
795
796
bool PSDLayerRecord::doRGB(KisPaintDeviceSP dev, QIODevice *io)
{
    quint64 oldPosition = io->pos();
797
798
799
800
801
802
    qint64 width = right - left;

    if (width <= 0) {
        dbgFile << "Empty layer";
        return true;
    }
803

804
805
    int channelSize = m_header.channelDepth / 8;
    int uncompressedLength = width * channelSize;
806

807
808
    if (channelInfoRecords.first()->compressionType == Compression::ZIP
            || channelInfoRecords.first()->compressionType == Compression::ZIPWithPrediction) {
809

810
        error = "Unsupported Compression mode: zip";
811
812
        return false;
    }
813

814
    KisHLineIteratorSP it = dev->createHLineIteratorNG(left, top, width);
815
816
817
    for (int row = top ; row < bottom; row++)
    {
        QMap<quint16, QByteArray> channelBytes;
818

819
820
        foreach(ChannelInfo *channelInfo, channelInfoRecords) {
            io->seek(channelInfo->channelDataStart + channelInfo->channelOffset);
821

822
823
824
825
826
827
828
829
830
831
            if (channelInfo->compressionType == Compression::Uncompressed) {
                channelBytes[channelInfo->channelId] = io->read(uncompressedLength);
                channelInfo->channelOffset += uncompressedLength;
            }
            else if (channelInfo->compressionType == Compression::RLE) {
                int rleLength = channelInfo->rleRowLengths[row - top];
                QByteArray compressedBytes = io->read(rleLength);
                QByteArray uncompressedBytes = Compression::uncompress(uncompressedLength, compressedBytes, channelInfo->compressionType);
                channelBytes.insert(channelInfo->channelId, uncompressedBytes);
                channelInfo->channelOffset += rleLength;
832

833
            }
834
835
836
837
            else {
                error = "Unsupported Compression mode: " + channelInfo->compressionType;
                return false;
            }
838
        }
839

840
        for (qint64 col = 0; col < width; col++){
841

842
843
            if (channelSize == 1) {
                quint8 opacity = OPACITY_OPAQUE_U8;
844
                if (channelBytes.contains(-1)) {
845
                    opacity = channelBytes[-1].constData()[col];
846
                }
847
                KoBgrU8Traits::setOpacity(it->rawData(), opacity, 1);
848

849
                quint8 red = channelBytes[0].constData()[col];
850
                KoBgrU8Traits::setRed(it->rawData(), red);
851
852

                quint8 green = channelBytes[1].constData()[col];
853
                KoBgrU8Traits::setGreen(it->rawData(), green);
854
855

                quint8 blue = channelBytes[2].constData()[col];
856
                KoBgrU8Traits::setBlue(it->rawData(), blue);
857
858
859

            }

860
            else if (channelSize == 2) {
861

862
                quint16 opacity = quint16_MAX;
863
                if (channelBytes.contains(-1)) {
864
865
866
                    opacity = channelBytes[-1].constData()[col];
                }
                // We don't have a convenient setOpacity function :-(
867
                memcpy(it->rawData() + KoBgrU16Traits::alpha_pos, &opacity, sizeof(quint16));
868

869
                quint16 red = ntohs(reinterpret_cast<const quint16 *>(channelBytes[0].constData())[col]);
870
                KoBgrU16Traits::setRed(it->rawData(), red);
871

872
                quint16 green = ntohs(reinterpret_cast<const quint16 *>(channelBytes[1].constData())[col]);
873
                KoBgrU16Traits::setGreen(it->rawData(), green);
874

875
                quint16 blue = ntohs(reinterpret_cast<const quint16 *>(channelBytes[2].constData())[col]);
876
                KoBgrU16Traits::setBlue(it->rawData(), blue);
877

878
879
880
881
882
            }
            else {
                // Unsupported channel sizes for now
                return false;
            }
883
            /*
884
885
            // XXX see implementation Openexr
            else if (channelSize == 4) {
886

887
                quint16 red = ntohs(reinterpret_cast<const quint16 *>(channelBytes.constData())[col]);
888
                KoBgrU16Traits::setRed(it->rawData(), red);
889

890
                quint16 green = ntohs(reinterpret_cast<const quint16 *>(channelBytes.constData())[col]);
891
                KoBgrU16Traits::setGreen(it->rawData(), green);
892

893
                quint16 blue = ntohs(reinterpret_cast<const quint16 *>(channelBytes.constData())[col]);
894
                KoBgrU16Traits::setBlue(it->rawData(), blue);
895
896
            }
*/
897
            it->nextPixel();
898
        }
899
        it->nextRow();
900
    }
901
902
    // go back to the old position, because we've been seeking all over the place
    io->seek(oldPosition);
903
904
905
    return true;
}

906
907
bool PSDLayerRecord::doCMYK(KisPaintDeviceSP dev, QIODevice *io)
{
908
909
    dbgFile << "doCMYK for" << layerName << "channels:" << channelInfoRecords.size() << "compression" << channelInfoRecords.first()->compressionType;
    dbgFile << "top" << top << "bottom" << bottom << "left" << left << "right" << right;
910
911
    quint64 oldPosition = io->pos();

Halla Rempt's avatar
Halla Rempt committed
912
    quint64 width = right - left;
913
914
915
    int channelSize = m_header.channelDepth / 8;
    int uncompressedLength = width * channelSize;

916

917
918
    if (channelInfoRecords.first()->compressionType == Compression::ZIP
            || channelInfoRecords.first()->compressionType == Compression::ZIPWithPrediction) {
919
        dbgFile << "zippedy-do-da!";
920
921
922
923
        // Zip needs to be implemented here.
        return false;
    }

924
    KisHLineIteratorSP it = dev->createHLineIteratorNG(left, top, width);
925
926
    for (int row = top ; row < bottom; row++)
    {
927

928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
        QMap<quint16, QByteArray> channelBytes;

        foreach(ChannelInfo *channelInfo, channelInfoRecords) {

            io->seek(channelInfo->channelDataStart + channelInfo->channelOffset);

            if (channelInfo->compressionType == Compression::Uncompressed) {
                channelBytes[channelInfo->channelId] = io->read(uncompressedLength);
                channelInfo->channelOffset += uncompressedLength;
            }
            else if (channelInfo->compressionType == Compression::RLE) {
                int rleLength = channelInfo->rleRowLengths[row - top];
                QByteArray compressedBytes = io->read(rleLength);
                QByteArray uncompressedBytes = Compression::uncompress(uncompressedLength, compressedBytes, channelInfo->compressionType);
                channelBytes.insert(channelInfo->channelId, uncompressedBytes);
                channelInfo->channelOffset += rleLength;

            }
        }

        for (quint64 col = 0; col < width; col++){

            if (channelSize == 1) {
951

952
953
954
955
956
                quint8 opacity = OPACITY_OPAQUE_U8;
                if (channelBytes.contains(-1)) {
                    opacity = channelBytes[-1].constData()[col];

                }
957
958
959
960
961
962
963
964
                quint8 *pixel = new quint8[5];
                memset(pixel, 0, 5);
                dev->colorSpace()->setOpacity(pixel, opacity, 1);

                memset(pixel, 255 - channelBytes[0].constData()[col], 1);
                memset(pixel + 1, 255 - channelBytes[1].constData()[col], 1);
                memset(pixel + 2, 255 - channelBytes[2].constData()[col], 1);
                memset(pixel + 3, 255 - channelBytes[3].constData()[col], 1);
965
                //dbgFile << "C" << pixel[0] << "M" << pixel[1] << "Y" << pixel[2] << "K" << pixel[3] << "A" << pixel[4];
966
                memcpy(it->rawData(), pixel, 5);
967
968
969
970
971
972
973
974
            }

            else if (channelSize == 2) {

                quint16 opacity = quint16_MAX;
                if (channelBytes.contains(-1)) {
                    opacity = channelBytes[-1].constData()[col];
                }
975

976
                // We don't have a convenient setOpacity function :-(
977
                memcpy(it->rawData() + KoCmykTraits<quint16>::alpha_pos, &opacity, sizeof(quint16));
978

979
                quint16 C = ntohs(reinterpret_cast<const quint16 *>(channelBytes[0].constData())[col]);
980
                KoCmykTraits<quint16>::setC(it->rawData(),C);
981
982

                quint16 M = ntohs(reinterpret_cast<const quint16 *>(channelBytes[1].constData())[col]);
983
                KoCmykTraits<quint16>::setM(it->rawData(),M);
984
985

                quint16 Y = ntohs(reinterpret_cast<const quint16 *>(channelBytes[2].constData())[col]);
986
                KoCmykTraits<quint16>::setY(it->rawData(),Y);
987
988

                quint16 K = ntohs(reinterpret_cast<const quint16 *>(channelBytes[3].constData())[col]);
989
                KoCmykTraits<quint16>::setK(it->rawData(),K);
990
991
992
993
994
995
996
997

            }


            // XXX see implementation Openexr
            else if (channelSize == 4) {

                quint32 C = ntohs(reinterpret_cast<const quint32 *>(channelBytes[0].constData())[col]);
998
                KoCmykTraits<quint32>::setC(it->rawData(),C);
999
1000

                quint32 M = ntohs(reinterpret_cast<const quint32 *>(channelBytes[1].constData())[col]);