Exemplo n.º 1
0
void PSDHeaderTest::testRoundTripping()
{
    QString filename = "test.psd";
    QFile f(filename);
    f.open(QIODevice::ReadWrite);
    PSDHeader header;
    Q_ASSERT(!header.valid());
    header.signature = "8BPS";
    header.version = 1;
    header.nChannels = 3;
    header.width = 1000;
    header.height = 1000;
    header.channelDepth = 8;
    header.colormode = RGB;
    Q_ASSERT(header.valid());
    bool retval = header.write(&f);
    Q_ASSERT(retval);

    f.close();
    f.open(QIODevice::ReadOnly);
    PSDHeader header2;
    retval = header2.read(&f);
    Q_ASSERT(retval);

    QCOMPARE(header.signature, header2.signature);
    QVERIFY(header.version == header2.version);
    QVERIFY(header.nChannels == header2.nChannels);
    QVERIFY(header.width == header2.width);
    QVERIFY(header.height == header2.height);
    QVERIFY(header.channelDepth == header2.channelDepth);
    QVERIFY(header.colormode == header2.colormode);
}
Exemplo n.º 2
0
m/*
 * Copyright (C) 2009 Boudewijn Rempt <*****@*****.**>
 *
 *  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_header_test.h"

#include <QTest>
#include <QCoreApplication>
#include <klocale.h>
#include <qtest_kde.h>
#include "../psd_header.h"
#ifndef FILES_DATA_DIR
#error "FILES_DATA_DIR not set. A directory with the data used for testing the importing of files in krita"
#endif

void PSDHeaderTest::testCreation()
{
    PSDHeader header;
    Q_ASSERT(!header.valid());
}
Exemplo n.º 3
0
void PSDColorModeBlockTest::testLoadingIndexed()
{
    QString filename = QString(FILES_DATA_DIR) + "/sources/100x100indexed.psd";
    QFile f(filename);
    f.open(QIODevice::ReadOnly);
    PSDHeader header;
    header.read(&f);

    QVERIFY(header.colormode == Indexed);

    PSDColorModeBlock colorModeBlock(header.colormode);
    bool retval = colorModeBlock.read(&f);
    Q_ASSERT(retval); Q_UNUSED(retval);
    Q_ASSERT(colorModeBlock.valid());

}
Exemplo n.º 4
0
void PSDHeaderTest::testLoading()
{
    QString filename = QString(FILES_DATA_DIR) + "/sources/1.psd";
    QFile f(filename);
    f.open(QIODevice::ReadOnly);
    PSDHeader header;
    header.read(&f);

    QVERIFY(header.signature == QString("8BPS"));
    QVERIFY(header.version == 1);
    QVERIFY(header.nChannels == 3);
    QVERIFY(header.width == 100 );
    QVERIFY(header.height == 100);
    QVERIFY(header.channelDepth == 16);
    QVERIFY(header.colormode == RGB);

}
Exemplo n.º 5
0
KisImageBuilder_Result PSDSaver::buildFile(QIODevice *io)
{
    if (!m_image)
        return KisImageBuilder_RESULT_EMPTY;

    const bool haveLayers = m_image->rootLayer()->childCount() > 1 ||
        checkIfHasTransparency(m_image->rootLayer()->firstChild()->projection());

    // HEADER
    PSDHeader header;
    header.signature = "8BPS";
    header.version = 1;
    header.nChannels = haveLayers ?
        m_image->colorSpace()->channelCount() :
        m_image->colorSpace()->colorChannelCount();

    header.width = m_image->width();
    header.height = m_image->height();

    QPair<psd_color_mode, quint16> colordef = colormodelid_to_psd_colormode(m_image->colorSpace()->colorModelId().id(),
                                                                          m_image->colorSpace()->colorDepthId().id());

    if (colordef.first == COLORMODE_UNKNOWN || colordef.second == 0 || colordef.second == 32) {
        return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
    }
    header.colormode = colordef.first;
    header.channelDepth = colordef.second;

    dbgFile << "header" << header << io->pos();

    if (!header.write(io)) {
        dbgFile << "Failed to write header. Error:" << header.error << io->pos();
        return KisImageBuilder_RESULT_FAILURE;
    }

    // COLORMODE BlOCK
    PSDColorModeBlock colorModeBlock(header.colormode);
    // XXX: check for annotations that contain the duotone spec

    KisAnnotationSP annotation = m_image->annotation("DuotoneColormodeBlock");
    if (annotation) {
        colorModeBlock.duotoneSpecification = annotation->annotation();
    }

    dbgFile << "colormode block" << io->pos();
    if (!colorModeBlock.write(io)) {
        dbgFile << "Failed to write colormode block. Error:" << colorModeBlock.error << io->pos();
        return KisImageBuilder_RESULT_FAILURE;
    }

    // IMAGE RESOURCES SECTION
    PSDImageResourceSection resourceSection;

    vKisAnnotationSP_it it = m_image->beginAnnotations();
    vKisAnnotationSP_it endIt = m_image->endAnnotations();
    while (it != endIt) {
        KisAnnotationSP annotation = (*it);
        if (!annotation || annotation->type().isEmpty()) {
            dbgFile << "Warning: empty annotation";
            it++;
            continue;
        }

        dbgFile << "Annotation:" << annotation->type() << annotation->description();

        if (annotation->type().startsWith(QString("PSD Resource Block:"))) { //
            PSDResourceBlock *resourceBlock = dynamic_cast<PSDResourceBlock*>(annotation.data());
            if (resourceBlock) {
                dbgFile << "Adding PSD Resource Block" << resourceBlock->identifier;
                resourceSection.resources[(PSDImageResourceSection::PSDResourceID)resourceBlock->identifier] = resourceBlock;
            }
        }

        it++;
    }

    // Add resolution block
    {
        RESN_INFO_1005 *resInfo = new RESN_INFO_1005;
        resInfo->hRes = INCH_TO_POINT(m_image->xRes());
        resInfo->vRes = INCH_TO_POINT(m_image->yRes());
        PSDResourceBlock *block = new PSDResourceBlock;
        block->identifier = PSDImageResourceSection::RESN_INFO;
        block->resource = resInfo;
        resourceSection.resources[PSDImageResourceSection::RESN_INFO] = block;
    }

    // Add icc block
    {
        ICC_PROFILE_1039 *profileInfo = new ICC_PROFILE_1039;
        profileInfo->icc = m_image->profile()->rawData();
        PSDResourceBlock *block = new PSDResourceBlock;
        block->identifier = PSDImageResourceSection::ICC_PROFILE;
        block->resource = profileInfo;
        resourceSection.resources[PSDImageResourceSection::ICC_PROFILE] = block;

    }


    dbgFile << "resource section" << io->pos();
    if (!resourceSection.write(io)) {
        dbgFile << "Failed to write resource section. Error:" << resourceSection.error << io->pos();
        return KisImageBuilder_RESULT_FAILURE;
    }

    // LAYER AND MASK DATA
    // Only save layers and masks if there is more than one layer
    dbgFile << "m_image->rootLayer->childCount" << m_image->rootLayer()->childCount() << io->pos();

    if (haveLayers) {

        PSDLayerMaskSection layerSection(header);
        layerSection.hasTransparency = true;

        if (!layerSection.write(io, m_image->rootLayer())) {
            dbgFile << "failed to write layer section. Error:" << layerSection.error << io->pos();
            return KisImageBuilder_RESULT_FAILURE;
        }
    }
    else {
        // else write a zero length block
        dbgFile << "No layers, saving empty layers/mask block" << io->pos();
        psdwrite(io, (quint32)0);
    }

    // IMAGE DATA
    dbgFile << "Saving composited image" << io->pos();
    PSDImageData imagedata(&header);
    if (!imagedata.write(io, m_image->projection(), haveLayers)) {
        dbgFile << "Failed to write image data. Error:"  << imagedata.error;
        return KisImageBuilder_RESULT_FAILURE;
    }

    return KisImageBuilder_RESULT_OK;
}
Exemplo n.º 6
0
KisImageBuilder_Result PSDSaver::buildFile(const KUrl& uri)
{
    if (!m_image)
        return KisImageBuilder_RESULT_EMPTY;

    if (uri.isEmpty())
        return KisImageBuilder_RESULT_NO_URI;

    if (!uri.isLocalFile())
        return KisImageBuilder_RESULT_NOT_LOCAL;

    // Open file for writing
    QFile f(uri.toLocalFile());
    if (!f.open(QIODevice::WriteOnly)) {
        return KisImageBuilder_RESULT_NOT_LOCAL;
    }

    // HEADER
    PSDHeader header;
    header.signature = "8BPS";
    header.version = 1;
    header.nChannels = m_image->colorSpace()->channelCount();
    header.width = m_image->width();
    header.height = m_image->height();

    QPair<PSDColorMode, quint16> colordef = colormodelid_to_psd_colormode(m_image->colorSpace()->colorModelId().id(),
                                                                          m_image->colorSpace()->colorDepthId().id());

    if (colordef.first == UNKNOWN || colordef.second == 0 || colordef.second == 32) {
        return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
    }
    header.colormode = colordef.first;
    header.channelDepth = colordef.second;

    dbgFile << "header" << header << f.pos();

    if (!header.write(&f)) {
        dbgFile << "Failed to write header. Error:" << header.error << f.pos();
        return KisImageBuilder_RESULT_FAILURE;
    }

    // COLORMODE BlOCK
    PSDColorModeBlock colorModeBlock(header.colormode);
    // XXX: check for annotations that contain the duotone spec
    dbgFile << "colormode block" << f.pos();
    if (!colorModeBlock.write(&f)) {
        dbgFile << "Failed to write colormode block. Error:" << colorModeBlock.error << f.pos();
        return KisImageBuilder_RESULT_FAILURE;
    }

    // IMAGE RESOURCES SECTION
    PSDResourceSection resourceSection;

    // Add resolution block
    {
        RESN_INFO_1005 *resInfo = new RESN_INFO_1005;
        resInfo->hRes = INCH_TO_POINT(m_image->xRes());
        resInfo->vRes = INCH_TO_POINT(m_image->yRes());
        PSDResourceBlock *block = new PSDResourceBlock;
        block->resource = resInfo;
        resourceSection.resources[PSDResourceSection::RESN_INFO] = block;
    }

    // Add icc block
    {
        ICC_PROFILE_1039 *profileInfo = new ICC_PROFILE_1039;
        profileInfo->icc = m_image->profile()->rawData();
        PSDResourceBlock *block = new PSDResourceBlock;
        block->resource = profileInfo;
        resourceSection.resources[PSDResourceSection::ICC_PROFILE] = block;

    }

    // XXX: Add other blocks...

    dbgFile << "resource section" << f.pos();
    if (!resourceSection.write(&f)) {
        dbgFile << "Failed to write resource section. Error:" << resourceSection.error << f.pos();
        return KisImageBuilder_RESULT_FAILURE;
    }

    // LAYER AND MASK DATA
    // Only save layers and masks if there is more than one layer
    dbgFile << "m_image->rootLayer->childCount" << m_image->rootLayer()->childCount() << f.pos();
    if (m_image->rootLayer()->childCount() > 1) {

        PSDLayerSection layerSection(header);
        layerSection.hasTransparency = true;

        if (!layerSection.write(&f, m_image->rootLayer())) {
            dbgFile << "failed to write layer section. Error:" << layerSection.error << f.pos();
            return KisImageBuilder_RESULT_FAILURE;
        }
    }
    else {
        // else write a zero length block
        dbgFile << "No layers, saving empty layers/mask block" << f.pos();
        psdwrite(&f, (quint32)0);
    }

    // IMAGE DATA
    dbgFile << "Saving composited image" << f.pos();
    PSDImageData imagedata(&header);
    if (!imagedata.write(&f, m_image->projection())) {
        dbgFile << "Failed to write image data. Error:"  << imagedata.error;
        return KisImageBuilder_RESULT_FAILURE;
    }

    f.close();

    return KisImageBuilder_RESULT_OK;
}
Exemplo n.º 7
0
KisImageBuilder_Result PSDLoader::decode(const KUrl& uri)
{
    // open the file
    QFile f(uri.toLocalFile());
    if (!f.exists()) {
        return KisImageBuilder_RESULT_NOT_EXIST;
    }
    if (!f.open(QIODevice::ReadOnly)) {
        return KisImageBuilder_RESULT_FAILURE;
    }

    dbgFile << "pos:" << f.pos();

    PSDHeader header;
    if (!header.read(&f)) {
        dbgFile << "failed reading header: " << header.error;
        return KisImageBuilder_RESULT_FAILURE;
    }

    dbgFile << header;
    dbgFile << "Read header. pos:" << f.pos();

    PSDColorModeBlock colorModeBlock(header.colormode);
    if (!colorModeBlock.read(&f)) {
        dbgFile << "failed reading colormode block: " << colorModeBlock.error;
        return KisImageBuilder_RESULT_FAILURE;
    }

    dbgFile << "Read color mode block. pos:" << f.pos();

    PSDResourceSection resourceSection;
    if (!resourceSection.read(&f)) {
        dbgFile << "failed reading resource section: " << resourceSection.error;
        return KisImageBuilder_RESULT_FAILURE;
    }

    dbgFile << "Read resource section. pos:" << f.pos();

    PSDLayerSection layerSection(header);
    if (!layerSection.read(&f)) {
        dbgFile << "failed reading layer section: " << layerSection.error;
        return KisImageBuilder_RESULT_FAILURE;
    }
    // XXX: add all the image resource blocks as annotations to the image

    dbgFile << "Read layer section. " << layerSection.nLayers << "layers. pos:" << f.pos();

    // Get the right colorspace
    QPair<QString, QString> colorSpaceId = psd_colormode_to_colormodelid(header.colormode,
                                                                         header.channelDepth);
    if (colorSpaceId.first.isNull()) return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;

    // Get the icc profile!
    const KoColorProfile* profile = 0;
    if (resourceSection.resources.contains(PSDResourceSection::ICC_PROFILE)) {
        ICC_PROFILE_1039 *iccProfileData = dynamic_cast<ICC_PROFILE_1039*>(resourceSection.resources[PSDResourceSection::ICC_PROFILE]->resource);
        if (iccProfileData ) {
            profile = KoColorSpaceRegistry::instance()->createColorProfile(colorSpaceId.first,
                                                                       colorSpaceId.second,
                                                                       iccProfileData->icc);
            dbgFile  << "Loaded ICC profile" << profile->name();
        }

    }

    // Create the colorspace
    const KoColorSpace* cs = KoColorSpaceRegistry::instance()->colorSpace(colorSpaceId.first, colorSpaceId.second, profile);
    if (!cs) {
        return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
    }

    // Creating the KisImageWSP
    m_image = new KisImage(m_doc->createUndoStore(),  header.width, header.height, cs, "built image");
    Q_CHECK_PTR(m_image);
    m_image->lock();

    // set the correct resolution
    if (resourceSection.resources.contains(PSDResourceSection::RESN_INFO)) {
        RESN_INFO_1005 *resInfo = dynamic_cast<RESN_INFO_1005*>(resourceSection.resources[PSDResourceSection::RESN_INFO]->resource);
        if (resInfo) {
            m_image->setResolution(POINT_TO_INCH(resInfo->hRes), POINT_TO_INCH(resInfo->vRes));
            // let's skip the unit for now; we can only set that on the KoDocument, and krita doesn't use it.
        }
    }
    // Preserve the duotone colormode block for saving back to psd
    if (header.colormode == DuoTone) {
        KisAnnotationSP annotation = new KisAnnotation("DuotoneColormodeBlock",
                                                       i18n("Duotone Colormode Block"),
                                                       colorModeBlock.data);
        m_image->addAnnotation(annotation);
    }

    // read the projection into our single layer
    if (layerSection.nLayers == 0) {
        dbgFile << "Position" << f.pos() << "Going to read the projection into the first layer, which Photoshop calls 'Background'";

        KisPaintLayerSP layer = new KisPaintLayer(m_image, i18n("Background"), OPACITY_OPAQUE_U8);
        KisTransaction("", layer -> paintDevice());

        PSDImageData imageData(&header);
        imageData.read(&f, layer->paintDevice());

        //readLayerData(&f, layer->paintDevice(), f.pos(), QRect(0, 0, header.width, header.height));
        m_image->addNode(layer, m_image->rootLayer());

    }
    else {

        // read the channels for the various layers
        for(int i = 0; i < layerSection.nLayers; ++i) {

            // XXX: work out the group layer structure in Photoshop, as well as the adjustment layers

            PSDLayerRecord* layerRecord = layerSection.layers.at(i);
            dbgFile << "Going to read channels for layer" << i << layerRecord->layerName;

            KisPaintLayerSP layer = new KisPaintLayer(m_image, layerRecord->layerName, layerRecord->opacity);
            layer->setCompositeOp(psd_blendmode_to_composite_op(layerRecord->blendModeKey));
            if (!layerRecord->readPixelData(&f, layer->paintDevice())) {
                dbgFile << "failed reading channels for layer: " << layerRecord->layerName << layerRecord->error;
                return KisImageBuilder_RESULT_FAILURE;
            }

            m_image->addNode(layer, m_image->rootLayer());
            layer->setVisible(layerRecord->visible);
        }
    }

    m_image->unlock();
    return KisImageBuilder_RESULT_OK;
}
Exemplo n.º 8
0
void PSDHeaderTest::testCreation()
{
    PSDHeader header;
    Q_ASSERT(!header.valid());
}