psd_layer_record.cpp 39.4 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
#include <netinet/in.h> // htonl
41

42
// Just for pretty debug messages
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 136 137
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:
138
            return QString("alpha: %1").arg(channelId);
139 140
        case Lab:
        case Lab48:
141
            return QString("alpha: %1").arg(channelId);
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
        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);
    };

}

160
PSDLayerRecord::PSDLayerRecord(const PSDHeader& header)
161 162 163 164 165 166 167 168 169 170 171 172
    : 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
173 174 175 176 177
{
}

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

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

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

190
    dbgFile << "\ttop" << top << "left" << left << "bottom" << bottom << "right" << right << "number of channels" << nChannels;
191

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


197
    switch(m_header.colormode) {
198 199 200 201 202
    case(Bitmap):
    case(Indexed):
    case(DuoTone):
    case(Grayscale):
    case(MultiChannel):
203
        if (nChannels < 1) {
204 205 206 207
            error = QString("Not enough channels. Got: %1").arg(nChannels);
            return false;
        }
        break;
208 209 210
    case(RGB):
    case(CMYK):
    case(Lab):
211
    default:
212
        if (nChannels < 3) {
213 214 215 216 217 218 219 220 221 222 223
            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
224 225 226 227 228 229 230
    for (int i = 0; i < nChannels; ++i) {

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

231
        ChannelInfo* info = new ChannelInfo;
232 233

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

253 254 255 256 257 258 259
//        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
260 261 262
        channelInfoRecords << info;
    }

Halla Rempt's avatar
Halla Rempt committed
263 264 265 266 267
    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
268 269
        return false;
    }
270
    dbgFile << "reading blend mode at pos" << io->pos();
Halla Rempt's avatar
Halla Rempt committed
271 272 273 274 275 276
    blendModeKey = QString(io->read(4));
    if (blendModeKey.size() != 4) {
        error = QString("Could not read blend mode key. Got: %1").arg(blendModeKey);
        return false;
    }

277
    dbgFile << "\tBlend mode" << blendModeKey << "pos" << io->pos();
278

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

284
    dbgFile << "\tOpacity" << opacity << io->pos();
285

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

291
    dbgFile << "\tclipping" << clipping << io->pos();
292

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

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

302
    dbgFile << "\ttransparency protected" << transparencyProtected;
303

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

306
    dbgFile << "\tvisible" << visible;
307

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

315
    dbgFile << "\tirrelevant" << irrelevant;
316

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

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

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

327
    quint32 extraDataLength;
Halla Rempt's avatar
Halla Rempt committed
328
    if (!psdread(io, &extraDataLength) || io->bytesAvailable() < extraDataLength) {
329 330 331
        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
332

333
    dbgFile << "\tExtra data length" << extraDataLength;
Halla Rempt's avatar
Halla Rempt committed
334

335
    if (extraDataLength > 0) {
Halla Rempt's avatar
Halla Rempt committed
336

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

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

349
        memset(&layerMask, 0, sizeof(LayerMaskData));
350

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

                error = "could not read mask record";
                return false;
            }
Halla Rempt's avatar
Halla Rempt committed
362
        }
363 364 365 366 367 368
        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
369
        }
370 371 372 373


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

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

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

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

392 393 394 395 396 397
        // 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
398

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

401 402 403 404 405
        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);
        }
        /*
406
        // XXX: reading this block correctly failed, I have more channel ranges than I'd expected.
407

408 409 410 411 412
        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)) {
413

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

        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);
        }
        */
429 430 431 432 433 434
        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
435

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

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

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

448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
        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
465
            dbgFile << "found info block with key" << key;
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488

            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
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 514 515
            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;
                }
            }

516 517

            infoBlocks[key] = infoBlock;
518 519 520
        }
    }

Halla Rempt's avatar
Halla Rempt committed
521 522 523
    return valid();
}

524
bool PSDLayerRecord::write(QIODevice* io, KisNodeSP node)
Halla Rempt's avatar
Halla Rempt committed
525
{
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
    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
546
    }
547 548 549 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 580 581

    // blend mode
    io->write("8BIM", 4);
    dbgFile << "blendModeKey" << blendModeKey << "pos" << io->pos();
    io->write(blendModeKey.toAscii());

    // 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);

582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604
    // 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
        }
    }
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
    // 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
627
    QRect rc = dev->extent();
628 629

    // yeah... we read the entire layer into a vector of quint8 arrays
Halla Rempt's avatar
Halla Rempt committed
630 631 632 633 634
    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());

635 636 637
//    KisPaintDeviceSP dev2 = new KisPaintDevice(dev->colorSpace());
//    dev2->writePlanarBytes(tmp, 0, 0, rc.width(), rc.height());
//    dev2->convertToQImage(0).save(layerName + ".png");
638 639 640 641 642 643 644 645 646 647 648 649

    // 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())) {
        if (ch->channelType() == KoChannelInfo::ALPHA) {
            planes.insert(0, tmp[ch->pos()]);
        }
        else {
            planes.append(tmp[ch->pos()]);
        }
    }

650

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

654 655 656 657 658
        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
659
            if (channelInfoRecords[channelInfoIndex]->channelId >= 0 && (m_header.colormode == CMYK || m_header.colormode == CMYK64)) {
660 661 662 663 664 665 666 667 668 669
                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
670
                if (channelInfoRecords[channelInfoIndex]->channelId >= 0 && (m_header.colormode == CMYK || m_header.colormode == CMYK64)) {
671 672 673 674 675
                     val = quint16_MAX - val;
                }
                reinterpret_cast<quint16*>(planes[channelInfoIndex])[i] = val;
            }
        }
676 677
        quint32 len = 0;

678

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 743 744

        // 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);
    }

    return true;


Halla Rempt's avatar
Halla Rempt committed
745 746 747 748
}

bool PSDLayerRecord::valid()
{
749 750 751 752
    // XXX: check validity!
    return true;
}

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

782
    return false;
783 784
}

Halla Rempt's avatar
Halla Rempt committed
785
bool PSDLayerRecord::doGrayscale(KisPaintDeviceSP /*dev*/, QIODevice */*io*/)
786 787 788
{
    return false;
}
789

790 791 792
bool PSDLayerRecord::doRGB(KisPaintDeviceSP dev, QIODevice *io)
{
    quint64 oldPosition = io->pos();
793 794 795 796 797 798
    qint64 width = right - left;

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

800 801
    int channelSize = m_header.channelDepth / 8;
    int uncompressedLength = width * channelSize;
802

803 804
    if (channelInfoRecords.first()->compressionType == Compression::ZIP
            || channelInfoRecords.first()->compressionType == Compression::ZIPWithPrediction) {
805

806
        error = "Unsupported Compression mode: zip";
807 808
        return false;
    }
809

810
    KisHLineIteratorSP it = dev->createHLineIteratorNG(left, top, width);
811 812 813
    for (int row = top ; row < bottom; row++)
    {
        QMap<quint16, QByteArray> channelBytes;
814

815 816
        foreach(ChannelInfo *channelInfo, channelInfoRecords) {
            io->seek(channelInfo->channelDataStart + channelInfo->channelOffset);
817

818 819 820 821 822 823 824 825 826 827
            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;
828

829
            }
830 831 832 833
            else {
                error = "Unsupported Compression mode: " + channelInfo->compressionType;
                return false;
            }
834
        }
835

836
        for (qint64 col = 0; col < width; col++){
837

838 839
            if (channelSize == 1) {
                quint8 opacity = OPACITY_OPAQUE_U8;
840
                if (channelBytes.contains(-1)) {
841
                    opacity = channelBytes[-1].constData()[col];
842
                }
843
                KoBgrU8Traits::setOpacity(it->rawData(), opacity, 1);
844

845
                quint8 red = channelBytes[0].constData()[col];
846
                KoBgrU8Traits::setRed(it->rawData(), red);
847 848

                quint8 green = channelBytes[1].constData()[col];
849
                KoBgrU8Traits::setGreen(it->rawData(), green);
850 851

                quint8 blue = channelBytes[2].constData()[col];
852
                KoBgrU8Traits::setBlue(it->rawData(), blue);
853 854 855

            }

856
            else if (channelSize == 2) {
857

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

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

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

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

874 875 876 877 878
            }
            else {
                // Unsupported channel sizes for now
                return false;
            }
879
            /*
880 881
            // XXX see implementation Openexr
            else if (channelSize == 4) {
882

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

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

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

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

Halla Rempt's avatar
Halla Rempt committed
908
    quint64 width = right - left;
909 910 911
    int channelSize = m_header.channelDepth / 8;
    int uncompressedLength = width * channelSize;

912

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

920
    KisHLineIteratorSP it = dev->createHLineIteratorNG(left, top, width);
921 922
    for (int row = top ; row < bottom; row++)
    {
923

924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946
        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) {
947

948 949 950 951 952
                quint8 opacity = OPACITY_OPAQUE_U8;
                if (channelBytes.contains(-1)) {
                    opacity = channelBytes[-1].constData()[col];

                }
953 954 955 956 957 958 959 960
                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);
961
                //dbgFile << "C" << pixel[0] << "M" << pixel[1] << "Y" << pixel[2] << "K" << pixel[3] << "A" << pixel[4];
962
                memcpy(it->rawData(), pixel, 5);
963 964 965 966 967 968 969 970
            }

            else if (channelSize == 2) {

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

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

975
                quint16 C = ntohs(reinterpret_cast<const quint16 *>(channelBytes[0].constData())[col]);
976
                KoCmykTraits<quint16>::setC(it->rawData(),C);
977 978

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

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

                quint16 K = ntohs(reinterpret_cast<const quint16 *>(channelBytes[3].constData())[col]);
985
                KoCmykTraits<quint16>::setK(it->rawData(),K);
986 987 988 989 990 991 992 993

            }


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

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

                quint32 M = ntohs(reinterpret_cast<const quint32 *>(channelBytes[1].constData())[col]);
997
                KoCmykTraits<quint32>::setM(it->rawData(),M);
998 999

                quint32 Y = ntohs(reinterpret_cast<const quint32 *>(channelBytes[2].constData())[col]);
1000
                KoCmykTraits<quint32>::setY(it->rawData(),Y);
1001 1002

                quint32 K = ntohs(reinterpret_cast<const quint32 *>(channelBytes[3].constData())[col]);
1003
                KoCmykTraits<quint32>::setK(it->rawData(),K);
1004 1005 1006 1007 1008 1009
            }

            else {
                // Unsupported channel sizes for now
                return false;
            }
1010
            it->nextPixel();
1011
        }
1012
        it->nextRow();
1013 1014 1015 1016
    }
    // go back to the old position, because we've been seeking all over the place
    io->seek(oldPosition);
    return true;
1017 1018 1019
}

bool PSDLayerRecord::doLAB(KisPaintDeviceSP dev, QIODevice *io)
1020 1021
{    quint64 oldPosition = io->pos();

Halla Rempt's avatar
Halla Rempt committed
1022
     quint64 width = right - left;
1023 1024
      int channelSize = m_header.channelDepth / 8;
       int uncompressedLength = width * channelSize;
1025

1026 1027
        if (channelInfoRecords.first()->compressionType == Compression::ZIP
                || channelInfoRecords.first()->compressionType == Compression::ZIPWithPrediction) {
1028

1029 1030 1031
            // Zip needs to be implemented here.
            return false;
        }
1032

1033 1034 1035
        KisHLineIteratorSP it = dev->createHLineIteratorNG(left, top, width);
         for (int row = top ; row < bottom; row++)
         {
1036

1037
             QMap<quint16, QByteArray> channelBytes;
1038

1039
             foreach(ChannelInfo *channelInfo, channelInfoRecords) {
1040

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

<