bool PSDResourceSection::read(QIODevice* io) { quint32 resourceBlockLength = 0; if (!psdread(io, &resourceBlockLength)) { error = "Could not read resource block length"; return false; } dbgFile << "Resource block length" << resourceBlockLength << "starts at" << io->pos(); QByteArray ba = io->read(resourceBlockLength); if ((quint32)ba.size() != resourceBlockLength) { error = "Could not read all resources"; return false; } QBuffer buf; buf.setBuffer(&ba); buf.open(QBuffer::ReadOnly); while (!buf.atEnd()) { PSDResourceBlock* block = new PSDResourceBlock(); if (!block->read(&buf)) { error = "Error reading block: " + block->error; return false; } dbgFile << "resource block created. Type:" << block->identifier << "size" << block->dataSize << "," << buf.bytesAvailable() << "bytes to go"; resources[(PSDResourceID)block->identifier] = block; } return valid(); }
bool psdread_pascalstring(QIODevice* io, QString& s, int padding) { quint8 length; if (!psdread(io, &length)) { return false; } if (length == 0) { // read the padding for (int i = 0; i < padding -1; ++i) { io->seek(io->pos() + 1); } return (length == 0); } QByteArray chars = io->read(length); if (chars.length() != length) { return false; } // read padding byte quint32 paddedLength = length + 1; if (padding > 0) { while (paddedLength % padding != 0) { if (!io->seek(io->pos() + 1)) { return false; } paddedLength++; } } s.append(QString::fromLatin1(chars)); return true; }
void PSDUtilsTest::test_psdread_quint32() { QBuffer buf; QVERIFY(buf.open(QBuffer::ReadWrite)); quint32 s = 300000; psdwrite(&buf, s); buf.close(); buf.open(QBuffer::ReadOnly); quint32 r; QVERIFY(psdread(&buf, &r)); QCOMPARE(r, s); }
void PSDUtilsTest::test_psdread_quint16() { QBuffer buf; buf.open(QBuffer::ReadWrite); quint16 s = 1024; QVERIFY(psdwrite(&buf, s)); buf.close(); buf.open(QBuffer::ReadOnly); quint16 r; QVERIFY(psdread(&buf, &r)); QCOMPARE(r, s); }
bool psdread_unicodestring(QIODevice *io, QString &s) { quint32 stringlen; if (!psdread(io, &stringlen)) { return false; } for (uint i = 0; i < stringlen; ++i) { quint16 ch; if (!psdread(io, &ch)) { return false; } if (ch != 0) { QChar uch(ch); s.append(uch); } } return true; }
static int sdreadblk(PSDunit *unit, SDpart *part, void *a, vlong off, int mbr) { uchar *b; assert(a); /* sdreadblk */ if(psdread(unit, part, a, unit->secsize, off) != unit->secsize){ if(Trace) print("%s: read %lud at %lld failed\n", unit->name, unit->secsize, (vlong)part->start*unit->secsize+off); return -1; } b = a; if(mbr && (b[0x1FE] != 0x55 || b[0x1FF] != 0xAA)){ if(Trace) print("%s: bad magic %.2ux %.2ux at %lld\n", unit->name, b[0x1FE], b[0x1FF], (vlong)part->start*unit->secsize+off); return -1; } return 0; }
bool PSDLayerRecord::read(QIODevice* io) { dbgFile << "Going to read layer record. Pos:" << io->pos(); if (!psdread(io, &top) || !psdread(io, &left) || !psdread(io, &bottom) || !psdread(io, &right) || !psdread(io, &nChannels)) { error = "could not read layer record"; return false; } dbgFile << "\ttop" << top << "left" << left << "bottom" << bottom << "right" << right << "number of channels" << nChannels; Q_ASSERT(top <= bottom); Q_ASSERT(left <= right); Q_ASSERT(nChannels > 0); switch(m_header.colormode) { case(Bitmap): case(Indexed): case(DuoTone): case(Grayscale): case(MultiChannel): if (nChannels < 1) { error = QString("Not enough channels. Got: %1").arg(nChannels); return false; } break; case(RGB): case(CMYK): case(Lab): default: if (nChannels < 3) { 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; } for (int i = 0; i < nChannels; ++i) { if (io->atEnd()) { error = "Could not read enough data for channels"; return false; } ChannelInfo* info = new ChannelInfo; if (!psdread(io, &info->channelId)) { error = "could not read channel id"; delete info; return false; } bool r; if (m_header.version == 1) { quint32 channelDataLength; r = psdread(io, &channelDataLength); info->channelDataLength = (quint64)channelDataLength; } else { r = psdread(io, &info->channelDataLength); } if (!r) { error = "Could not read length for channel data"; delete info; return false; } dbgFile << "\tchannel" << i << "id" << channelIdToChannelType(info->channelId, m_header.colormode) << "length" << info->channelDataLength << "start" << info->channelDataStart << "offset" << info->channelOffset << "channelInfoPosition" << info->channelInfoPosition; channelInfoRecords << info; } if (!psd_read_blendmode(io, blendModeKey)) { error = QString("Could not read blend mode key. Got: %1").arg(blendModeKey); return false; } dbgFile << "\tBlend mode" << blendModeKey << "pos" << io->pos(); if (!psdread(io, &opacity)) { error = "Could not read opacity"; return false; } dbgFile << "\tOpacity" << opacity << io->pos(); if (!psdread(io, &clipping)) { error = "Could not read clipping"; return false; } dbgFile << "\tclipping" << clipping << io->pos(); quint8 flags; if (!psdread(io, &flags)) { error = "Could not read flags"; return false; } dbgFile << "\tflags" << flags << io->pos(); transparencyProtected = flags & 1 ? true : false; dbgFile << "\ttransparency protected" << transparencyProtected; visible = flags & 2 ? false : true; dbgFile << "\tvisible" << visible; if (flags & 8) { irrelevant = flags & 16 ? true : false; } else { irrelevant = false; } dbgFile << "\tirrelevant" << irrelevant; dbgFile << "\tfiller at " << io->pos(); quint8 filler; if (!psdread(io, &filler) || filler != 0) { error = "Could not read padding"; return false; } dbgFile << "\tGoing to read extra data length" << io->pos(); quint32 extraDataLength; if (!psdread(io, &extraDataLength) || io->bytesAvailable() < extraDataLength) { error = QString("Could not read extra layer data: %1 at pos %2").arg(extraDataLength).arg(io->pos()); return false; } dbgFile << "\tExtra data length" << extraDataLength; if (extraDataLength > 0) { dbgFile << "Going to read extra data field. Bytes available: " << io->bytesAvailable() << "pos" << io->pos(); quint32 layerMaskLength = 1; // invalid... if (!psdread(io, &layerMaskLength) || io->bytesAvailable() < layerMaskLength || !(layerMaskLength == 0 || layerMaskLength == 20 || layerMaskLength == 36)) { error = QString("Could not read layer mask length: %1").arg(layerMaskLength); return false; } memset(&layerMask, 0, sizeof(LayerMaskData)); if (layerMaskLength == 20 || layerMaskLength == 36) { if (!psdread(io, &layerMask.top) || !psdread(io, &layerMask.left) || !psdread(io, &layerMask.bottom) || !psdread(io, &layerMask.right) || !psdread(io, &layerMask.defaultColor) || !psdread(io, &flags)) { error = "could not read mask record"; return false; } } if (layerMaskLength == 20) { quint16 padding; if (!psdread(io, &padding)) { error = "Could not read layer mask padding"; return false; } } if (layerMaskLength == 36 ) { if (!psdread(io, &flags) || !psdread(io, &layerMask.defaultColor) || !psdread(io, &layerMask.top) || !psdread(io, &layerMask.left) || !psdread(io, &layerMask.bottom) || !psdread(io, &layerMask.top)) { error = "could not read 'real' mask record"; return false; } } layerMask.positionedRelativeToLayer = flags & 1 ? true : false; layerMask.disabled = flags & 2 ? true : false; layerMask.invertLayerMaskWhenBlending = flags & 4 ? true : false; dbgFile << "\tRead layer mask/adjustment layer data. Length of block:" << layerMaskLength << "pos" << io->pos(); // layer blending thingies quint32 blendingDataLength; if (!psdread(io, &blendingDataLength) || io->bytesAvailable() < blendingDataLength) { error = "Could not read extra blending data."; return false; } //dbgFile << "blending block data length" << blendingDataLength << ", pos" << io->pos(); 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); } /* // XXX: reading this block correctly failed, I have more channel ranges than I'd expected. 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)) { error = "Could not read blending black/white values"; return false; } 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); } */ dbgFile << "\tGoing to read layer name at" << io->pos(); quint8 layerNameLength; if (!psdread(io, &layerNameLength)) { error = "Could not read layer name length"; return false; } dbgFile << "\tlayer name length unpadded" << layerNameLength << "pos" << io->pos(); layerNameLength = ((layerNameLength + 1 + 3) & ~0x03) - 1; dbgFile << "\tlayer name length padded" << layerNameLength << "pos" << io->pos(); layerName = io->read(layerNameLength); dbgFile << "\tlayer name" << layerName << io->pos(); if (!infoBlocks.read(io)) { error = infoBlocks.error; return false; } if (infoBlocks.keys.contains("luni") && !infoBlocks.unicodeLayerName.isEmpty()) { layerName = infoBlocks.unicodeLayerName; } } return valid(); }
/* * To facilitate booting from CDs, we create a partition for * the FAT filesystem image embedded in a bootable CD. */ static int part9660(PSDunit *unit) { ulong a, n, i, j; uchar drecsz; uchar *p; uchar buf[Maxsec]; Drec *rootdrec, *drec; Voldesc *v; static char stdid[] = "CD001\x01"; if(unit->secsize == 0) unit->secsize = Cdsec; if(unit->secsize != Cdsec) return -1; if(psdread(unit, &unit->part[0], buf, Cdsec, VOLDESC*Cdsec) < 0) return -1; if(buf[0] != PrimaryIso || memcmp((char*)buf+1, stdid, sizeof stdid - 1) != 0) return -1; v = (Voldesc *)buf; rootdrec = (Drec *)v->z.desc.rootdir; assert(rootdrec); p = rootdrec->addr; a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); p = rootdrec->size; n = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); // print("part9660: read %uld %uld\n", n, a); /* debugging */ if(n < Cdsec){ print("warning: bad boot file size %ld in iso directory", n); n = Cdsec; } drec = nil; for(j = 0; j*Cdsec < n; j++){ if(psdread(unit, &unit->part[0], buf, Cdsec, (a + j)*Cdsec) < 0) return -1; for(i = 0; i + j*Cdsec <= n && i < Cdsec; i += drecsz){ drec = (Drec *)&buf[i]; drecsz = drec->reclen; if(drecsz == 0 || drecsz + i > Cdsec) break; if(cistrncmp("bootdisk.img", (char *)drec->name, 12) == 0) goto Found; } } Found: if(j*Cdsec >= n || drec == nil) return -1; p = drec->addr; a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); p = drec->size; n = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); print("found partition %s!9fat; %lud+%lud\n", unit->name, a, n); n /= Cdsec; psdaddpart(unit, "9fat", a, a+n); return 0; }
bool PSDResourceBlock::read(QIODevice* io) { dbgFile << "Reading resource block"; if (io->atEnd()) { error = "Could not read resource block: no bytes left."; return false; } QByteArray b; b = io->read(4); if(b.size() != 4 || QString(b) != "8BIM") { error = QString("Could not read resource block signature. Got %1.") .arg(QString(b)); return false; } if (!psdread(io, &identifier)) { error = "Could not read resource block identifier"; return false; } dbgFile << "\tresource block identifier" << PSDImageResourceSection::idToString((PSDImageResourceSection::PSDResourceID)identifier) << identifier; m_type = QString("PSD Resource Block: %1").arg(identifier); if (!psdread_pascalstring(io, name, 2)) { error = "Could not read name of resource block"; return false; } dbgFile << "\tresource block name" << name; if (!psdread(io, &dataSize)) { error = QString("Could not read datasize for resource block with name %1 of type %2").arg(name).arg(identifier); return false; } if ((dataSize & 0x01) != 0) { dataSize++; } dbgFile << "\tresource block size" << dataSize; m_description = PSDImageResourceSection::idToString((PSDImageResourceSection::PSDResourceID)identifier); data = io->read(dataSize); if (data.size() != (int)dataSize) { error = QString("Could not read data for resource block with name %1 of type %2").arg(name).arg(identifier); return false; } m_annotation = data; switch (identifier) { // case PSDImageResourceSection::MAC_PRINT_INFO: // resource = new MAC_PRINT_INFO_1001; // break; case PSDImageResourceSection::RESN_INFO: resource = new RESN_INFO_1005; break; // case PSDImageResourceSection::ALPHA_NAMES: // resource = new ALPHA_NAMES_1006; // break; // case PSDImageResourceSection::DISPLAY_INFO: // resource = new DISPLAY_INFO_1007; // break; // case PSDImageResourceSection::CAPTION: // resource = new CAPTION_1008; // break; // case PSDImageResourceSection::BORDER_INFO: // resource = new BORDER_INFO_1009; // break; // case PSDImageResourceSection::BACKGROUND_COL: // resource = new BACKGROUND_COL_1010; // break; // case PSDImageResourceSection::PRINT_FLAGS: // resource = new PRINT_FLAGS_1011; // break; // case PSDImageResourceSection::GREY_HALFTONE: // resource = new GREY_HALFTONE_1012; // break; // case PSDImageResourceSection::COLOR_HALFTONE: // resource = new COLOR_HALFTONE_1013; // break; // case PSDImageResourceSection::DUOTONE_HALFTONE: // resource = new DUOTONE_HALFTONE_1014; // break; // case PSDImageResourceSection::GREY_XFER: // resource = new GREY_XFER_1015; // break; // case PSDImageResourceSection::COLOR_XFER: // resource = new COLOR_XFER_1016; // break; // case PSDImageResourceSection::DUOTONE_XFER: // resource = new DUOTONE_XFER_1017; // break; // case PSDImageResourceSection::DUOTONE_INFO: // resource = new DUOTONE_INFO_1018; // break; // case PSDImageResourceSection::EFFECTIVE_BW: // resource = new EFFECTIVE_BW_1019; // break; // case PSDImageResourceSection::EPS_OPT: // resource = new EPS_OPT_1021; // break; // case PSDImageResourceSection::QUICK_MASK: // resource = new QUICK_MASK_1022; // break; // case PSDImageResourceSection::LAYER_STATE: // resource = new LAYER_STATE_1024; // break; // case PSDImageResourceSection::WORKING_PATH: // resource = new WORKING_PATH_1025; // break; // case PSDImageResourceSection::LAYER_GROUP: // resource = new LAYER_GROUP_1026; // break; // case PSDImageResourceSection::IPTC_NAA_DATA: // resource = new IPTC_NAA_DATA_1028; // break; // case PSDImageResourceSection::IMAGE_MODE_RAW: // resource = new IMAGE_MODE_RAW_1029; // break; // case PSDImageResourceSection::JPEG_QUAL: // resource = new JPEG_QUAL_1030; // break; // case PSDImageResourceSection::GRID_GUIDE: // resource = new GRID_GUIDE_1032; // break; // case PSDImageResourceSection::THUMB_RES: // resource = new THUMB_RES_1033; // break; // case PSDImageResourceSection::COPYRIGHT_FLG: // resource = new COPYRIGHT_FLG_1034; // break; // case PSDImageResourceSection::URL: // resource = new URL_1035; // break; // case PSDImageResourceSection::THUMB_RES2: // resource = new THUMB_RES2_1036; // break; case PSDImageResourceSection::GLOBAL_ANGLE: resource = new GLOBAL_ANGLE_1037; break; // case PSDImageResourceSection::COLOR_SAMPLER: // resource = new COLOR_SAMPLER_1038; // break; case PSDImageResourceSection::ICC_PROFILE: resource = new ICC_PROFILE_1039; break; // case PSDImageResourceSection::WATERMARK: // resource = new WATERMARK_1040; // break; // case PSDImageResourceSection::ICC_UNTAGGED: // resource = new ICC_UNTAGGED_1041; // break; // case PSDImageResourceSection::EFFECTS_VISIBLE: // resource = new EFFECTS_VISIBLE_1042; // break; // case PSDImageResourceSection::SPOT_HALFTONE: // resource = new SPOT_HALFTONE_1043; // break; // case PSDImageResourceSection::DOC_IDS: // resource = new DOC_IDS_1044; // break; // case PSDImageResourceSection::ALPHA_NAMES_UNI: // resource = new ALPHA_NAMES_UNI_1045; // break; // case PSDImageResourceSection::IDX_COL_TAB_CNT: // resource = new IDX_COL_TAB_CNT_1046; // break; // case PSDImageResourceSection::IDX_TRANSPARENT: // resource = new IDX_TRANSPARENT_1047; // break; case PSDImageResourceSection::GLOBAL_ALT: resource = new GLOBAL_ALT_1049; break; // case PSDImageResourceSection::SLICES: // resource = new SLICES_1050; // break; // case PSDImageResourceSection::WORKFLOW_URL_UNI: // resource = new WORKFLOW_URL_UNI_1051; // break; // case PSDImageResourceSection::JUMP_TO_XPEP: // resource = new JUMP_TO_XPEP_1052; // break; // case PSDImageResourceSection::ALPHA_ID: // resource = new ALPHA_ID_1053; // break; // case PSDImageResourceSection::URL_LIST_UNI: // resource = new URL_LIST_UNI_1054; // break; // case PSDImageResourceSection::VERSION_INFO: // resource = new VERSION_INFO_1057; // break; // case PSDImageResourceSection::EXIF_DATA: // resource = new EXIF_DATA_1058; // break; // case PSDImageResourceSection::XMP_DATA: // resource = new XMP_DATA_1060; // break; // case PSDImageResourceSection::PATH_INFO_FIRST: // resource = new PATH_INFO_FIRST_2000; // break; // case PSDImageResourceSection::PATH_INFO_LAST: // resource = new PATH_INFO_LAST_2998; // break; // case PSDImageResourceSection::CLIPPING_PATH: // resource = new CLIPPING_PATH_2999; // break; // case PSDImageResourceSection::PRINT_FLAGS_2: // resource = new PRINT_FLAGS_2_10000; // break; default: ; } if (resource) { resource->interpretBlock(data); } return valid(); }
bool PSDLayerSection::read(QIODevice* io) { dbgFile << "reading layer section. Pos:" << io->pos() << "bytes left:" << io->bytesAvailable(); layerMaskBlockSize = 0; if (m_header.version == 1) { quint32 _layerMaskBlockSize = 0; if (!psdread(io, &_layerMaskBlockSize) || _layerMaskBlockSize > (quint64)io->bytesAvailable()) { error = QString("Could not read layer + mask block size. Got %1. Bytes left %2") .arg(_layerMaskBlockSize).arg(io->bytesAvailable()); return false; } layerMaskBlockSize = _layerMaskBlockSize; } else if (m_header.version == 2) { if (!psdread(io, &layerMaskBlockSize) || layerMaskBlockSize > (quint64)io->bytesAvailable()) { error = QString("Could not read layer + mask block size. Got %1. Bytes left %2") .arg(layerMaskBlockSize).arg(io->bytesAvailable()); return false; } } dbgFile << "layer + mask section size" << layerMaskBlockSize; if (layerMaskBlockSize == 0) { dbgFile << "No layer + mask info, so no layers, only a background layer"; return true; } dbgFile << "reading layer info block. Bytes left" << io->bytesAvailable() << "position" << io->pos(); if (m_header.version == 1) { quint32 _layerInfoSize; if (!psdread(io, &_layerInfoSize) || _layerInfoSize > (quint64)io->bytesAvailable()) { error = "Could not read layer section size"; return false; } layerInfoSize = _layerInfoSize; } else if (m_header.version == 2) { if (!psdread(io, &layerInfoSize) || layerInfoSize > (quint64)io->bytesAvailable()) { error = "Could not read layer section size"; return false; } } dbgFile << "Layer info block size" << layerInfoSize; if (layerInfoSize > 0 ) { // rounded to a multiple of 2 if ((layerInfoSize & 0x01) != 0) { layerInfoSize++; } dbgFile << "Layer info block size after rounding" << layerInfoSize; if (!psdread(io, &nLayers) || nLayers == 0) { error = QString("Could not read read number of layers or no layers in image. %1").arg(nLayers); return false; } if (nLayers < 0) { hasTransparency = true; // first alpha channel is the alpha channel of the projection. nLayers = -nLayers; } else { hasTransparency = false; } dbgFile << "transparency" << hasTransparency; dbgFile << "Number of layers" << nLayers << "transparency" << hasTransparency; for (int i = 0; i < nLayers; ++i) { dbgFile << "Going to read layer " << i << "pos" << io->pos(); PSDLayerRecord *layerRecord = new PSDLayerRecord(m_header); if (!layerRecord->read(io)) { error = QString("Could not load layer %1: %2").arg(i).arg(layerRecord->error); return false; } dbgFile << "Read layer" << i << layerRecord->layerName << "blending mode" << layerRecord->blendModeKey << io->pos(); layers << layerRecord; } } // get the positions for the channels belonging to each layer for (int i = 0; i < nLayers; ++i) { dbgFile << "Going to seek channel positions for layer" << i << "pos" << io->pos(); Q_ASSERT(i < layers.size()); if (i > layers.size()) { error = QString("Expected layer %1, but only have %2 layers").arg(i).arg(layers.size()); return false; } PSDLayerRecord *layerRecord = layers.at(i); for (int j = 0; j < layerRecord->nChannels; ++j) { // save the current location so we can jump beyond this block later on. quint64 channelStartPos = io->pos(); dbgFile << "\tReading channel image data for" << j << "from pos" << io->pos(); Q_ASSERT(j < layerRecord->channelInfoRecords.size()); if (j > layerRecord->channelInfoRecords.size()) { error = QString("Expected channel %1, but only have %2 channels for layer %3") .arg(j) .arg(layerRecord->channelInfoRecords.size()) .arg(i); return false; } PSDLayerRecord::ChannelInfo* channelInfo = layerRecord->channelInfoRecords.at(j); quint16 compressionType; if (!psdread(io, &compressionType)) { error = "Could not read compression type for channel"; return false; } channelInfo->compressionType = (Compression::CompressionType)compressionType; dbgFile << "\t\tChannel" << j << "has compression type" << compressionType; // read the rle row lengths; if (channelInfo->compressionType == Compression::RLE) { for(quint64 row = 0; row < (layerRecord->bottom - layerRecord->top); ++row) { //dbgFile << "Reading the RLE bytecount position of row" << row << "at pos" << io->pos(); quint32 byteCount; if (m_header.version == 1) { quint16 _byteCount; if (!psdread(io, &_byteCount)) { error = QString("Could not read byteCount for rle-encoded channel"); return 0; } byteCount = _byteCount; } else { if (!psdread(io, &byteCount)) { error = QString("Could not read byteCount for rle-encoded channel"); return 0; } } //qDebug() << "rle byte count" << byteCount; channelInfo->rleRowLengths << byteCount; } } // we're beyond all the length bytes, rle bytes and whatever, this is the // location of the real pixel data channelInfo->channelDataStart = io->pos(); dbgFile << "\t\tstart" << channelStartPos << "data start" << channelInfo->channelDataStart << "data length" << channelInfo->channelDataLength << "pos" << io->pos(); // make sure we are at the start of the next channel data block io->seek(channelStartPos + channelInfo->channelDataLength); // this is the length of the actual channel data bytes channelInfo->channelDataLength = channelInfo->channelDataLength - (channelInfo->channelDataStart - channelStartPos); dbgFile << "\t\tchannel record" << j << "for layer" << i << "with id" << channelInfo->channelId << "starting postion" << channelInfo->channelDataStart << "with length" << channelInfo->channelDataLength << "and has compression type" << channelInfo->compressionType; } } quint32 globalMaskBlockLength; if (!psdread(io, &globalMaskBlockLength) || globalMaskBlockLength > (quint64)io->bytesAvailable()) { error = "Could not read global mask info block"; return false; } if (globalMaskBlockLength > 0) { if (!psdread(io, &overlayColorSpace)) { error = "Could not read global mask info overlay colorspace"; return false; } for (int i = 0; i < 4; ++i) { if (!psdread(io, &colorComponents[i])) { error = QString("Could not read mask info visualizaion color component %1").arg(i); return false; } } if (!psdread(io, &opacity)) { error = "Could not read global mask info visualization opacity"; return false; } if (!psdread(io, &kind)) { error = "Could not read global mask info visualization type"; return false; } } return valid(); }
bool PSDImageData::read(QIODevice *io, KisPaintDeviceSP dev ) { psdread(io, &m_compression); quint64 start = io->pos(); m_channelSize = m_header->channelDepth/8; m_channelDataLength = m_header->height * m_header->width * m_channelSize; dbgFile << "Reading Image Data Block: compression" << m_compression << "channelsize" << m_channelSize << "number of channels" << m_header->nChannels; switch (m_compression) { case 0: // Uncompressed for (int channel = 0; channel < m_header->nChannels; channel++) { m_channelOffsets << 0; ChannelInfo channelInfo; channelInfo.channelId = channel; channelInfo.compressionType = Compression::Uncompressed; channelInfo.channelDataStart = start; channelInfo.channelDataLength = m_header->width * m_header->height * m_channelSize; start += channelInfo.channelDataLength; m_channelInfoRecords.append(channelInfo); } break; case 1: // RLE { quint32 rlelength = 0; // The start of the actual channel data is _after_ the RLE rowlengths block if (m_header->version == 1) { start += m_header->nChannels * m_header->height * 2; } else if (m_header->version == 2) { start += m_header->nChannels * m_header->height * 4; } for (int channel = 0; channel < m_header->nChannels; channel++) { m_channelOffsets << 0; quint32 sumrlelength = 0; ChannelInfo channelInfo; channelInfo.channelId = channel; channelInfo.channelDataStart = start; channelInfo.compressionType = Compression::RLE; for (quint32 row = 0; row < m_header->height; row++ ) { if (m_header->version == 1) { psdread(io,(quint16*)&rlelength); } else if (m_header->version == 2) { psdread(io,&rlelength); } channelInfo.rleRowLengths.append(rlelength); sumrlelength += rlelength; } channelInfo.channelDataLength = sumrlelength; start += channelInfo.channelDataLength; m_channelInfoRecords.append(channelInfo); } break; } case 2: // ZIP without prediction case 3: // ZIP with prediction default: break; } if (!m_channelInfoRecords.isEmpty()) { QVector<ChannelInfo*> infoRecords; QVector<ChannelInfo>::iterator it = m_channelInfoRecords.begin(); QVector<ChannelInfo>::iterator end = m_channelInfoRecords.end(); for (; it != end; ++it) { infoRecords << &(*it); } const QRect imageRect(0, 0, m_header->width, m_header->height); try { PsdPixelUtils::readChannels(io, dev, m_header->colormode, m_channelSize, imageRect, infoRecords); } catch (KisAslReaderUtils::ASLParseException &e) { dev->clear(); return true; } } return true; }
bool PSDImageData::read(QIODevice *io, KisPaintDeviceSP dev ) { psdread(io, &m_compression); quint64 start = io->pos(); m_channelSize = m_header->channelDepth/8; m_channelDataLength = m_header->height * m_header->width * m_channelSize; switch (m_compression) { case 0: // Uncompressed for (int channel = 0; channel < m_header->nChannels; channel++) { m_channelOffsets << 0; ChannelInfo channelInfo; channelInfo.channelId = channel; channelInfo.compressionType = Compression::Uncompressed; channelInfo.channelDataStart = start; channelInfo.channelDataLength = m_header->width * m_header->height * m_channelSize; start += channelInfo.channelDataLength; m_channelInfoRecords.append(channelInfo); } switch (m_header->colormode) { case Bitmap: break; case Grayscale: readGrayscale(io,dev); break; case Indexed: break; case RGB: readRGB(io, dev); break; case CMYK: readCMYK(io, dev); break; case MultiChannel: break; case DuoTone: break; case Lab: readLAB(io, dev); break; case UNKNOWN: break; default: break; } break; case 1: // RLE { quint32 rlelength = 0; // The start of the actual channel data is _after_ the RLE rowlengths block if (m_header->version == 1) { start += m_header->nChannels * m_header->height * 2; } else if (m_header->version == 2) { start += m_header->nChannels * m_header->height * 4; } for (int channel = 0; channel < m_header->nChannels; channel++) { m_channelOffsets << 0; quint32 sumrlelength = 0; ChannelInfo channelInfo; channelInfo.channelId = channel; channelInfo.channelDataStart = start; channelInfo.compressionType = Compression::RLE; for (quint32 row = 0; row < m_header->height; row++ ) { if (m_header->version == 1) { psdread(io,(quint16*)&rlelength); } else if (m_header->version == 2) { psdread(io,&rlelength); } channelInfo.rleRowLengths.append(rlelength); sumrlelength += rlelength; } channelInfo.channelDataLength = sumrlelength; start += channelInfo.channelDataLength; m_channelInfoRecords.append(channelInfo); } switch (m_header->colormode) { case Bitmap: break; case Grayscale: readGrayscale(io,dev); break; case Indexed: break; case RGB: readRGB(io, dev); break; case CMYK: readCMYK(io, dev); break; case MultiChannel: break; case DuoTone: break; case Lab: readLAB(io, dev); break; case UNKNOWN: break; default: break; } break; } case 2: // ZIP without prediction switch (m_header->colormode) { case Bitmap: break; case Grayscale: break; case Indexed: break; case RGB: break; case CMYK: break; case MultiChannel: break; case DuoTone: break; case Lab: break; case UNKNOWN: break; default: break; } break; case 3: // ZIP with prediction switch (m_header->colormode) { case Bitmap: break; case Grayscale: break; case Indexed: break; case RGB: break; case CMYK: break; case MultiChannel: break; case DuoTone: break; case Lab: break; case UNKNOWN: break; default: break; } break; default: break; } return true; }