uint32_t PsdImage::writeIptcData(const IptcData& iptcData, BasicIo& out) const { uint32_t resLength = 0; byte buf[8]; if (iptcData.count() > 0) { DataBuf rawIptc = IptcParser::encode(iptcData); if (rawIptc.size_ > 0) { #ifdef DEBUG std::cerr << std::hex << "write: resourceId: " << kPhotoshopResourceID_IPTC_NAA << "\n"; std::cerr << std::dec << "Writing IPTC_NAA: size: " << rawIptc.size_ << "\n"; #endif ul2Data(buf, kPhotoshopResourceType, bigEndian); if (out.write(buf, 4) != 4) throw Error(21); us2Data(buf, kPhotoshopResourceID_IPTC_NAA, bigEndian); if (out.write(buf, 2) != 2) throw Error(21); us2Data(buf, 0, bigEndian); // NULL resource name if (out.write(buf, 2) != 2) throw Error(21); ul2Data(buf, rawIptc.size_, bigEndian); if (out.write(buf, 4) != 4) throw Error(21); // Write encoded Iptc data if (out.write(rawIptc.pData_, rawIptc.size_) != rawIptc.size_) throw Error(21); resLength += rawIptc.size_ + 12; if (rawIptc.size_ & 1) // even padding { buf[0] = 0; if (out.write(buf, 1) != 1) throw Error(21); resLength++; } } } return resLength; } // PsdImage::writeIptcData
long Ifd::copy(char* buf, ByteOrder byteOrder, long offset) { if (offset != 0) offset_ = offset; // Add the number of entries to the data buffer us2Data(buf, entries_.size(), byteOrder); long o = 2; // Add all directory entries to the data buffer long dataSize = 0; const iterator b = entries_.begin(); const iterator e = entries_.end(); iterator i = b; for (; i != e; ++i) { us2Data(buf + o, i->tag(), byteOrder); us2Data(buf + o + 2, i->type(), byteOrder); ul2Data(buf + o + 4, i->count(), byteOrder); if (i->size() > 4) { // Set the offset of the entry, data immediately follows the IFD i->setOffset(size() + dataSize); ul2Data(buf + o + 8, offset_ + i->offset(), byteOrder); dataSize += i->size(); } else { // Copy data into the offset field memset(buf + o + 8, 0x0, 4); memcpy(buf + o + 8, i->data(), i->size()); } o += 12; } // Add the offset to the next IFD to the data buffer if (pNext_) { memcpy(buf + o, pNext_, 4); } else { memset(buf + o, 0x0, 4); } o += 4; // Add the data of all IFD entries to the data buffer for (i = b; i != e; ++i) { if (i->size() > 4) { memcpy(buf + o, i->data(), i->size()); o += i->size(); } } return o; } // Ifd::copy
DataBuf IptcData::copy() const { DataBuf buf(size()); byte *pWrite = buf.pData_; const_iterator iter = iptcMetadata_.begin(); const_iterator end = iptcMetadata_.end(); for ( ; iter != end; ++iter) { // marker, record Id, dataset num *pWrite++ = marker_; *pWrite++ = static_cast<byte>(iter->record()); *pWrite++ = static_cast<byte>(iter->tag()); // extended or standard dataset? long dataSize = iter->size(); if (dataSize > 32767) { // always use 4 bytes for extended length uint16_t sizeOfSize = 4 | 0x8000; us2Data(pWrite, sizeOfSize, bigEndian); pWrite += 2; ul2Data(pWrite, dataSize, bigEndian); pWrite += 4; } else { us2Data(pWrite, static_cast<uint16_t>(dataSize), bigEndian); pWrite += 2; } pWrite += iter->value().copy(pWrite, bigEndian); } return buf; } // IptcData::copy
uint32_t PsdImage::writeXmpData(const XmpData& xmpData, BasicIo& out) const { std::string xmpPacket; uint32_t resLength = 0; byte buf[8]; #ifdef DEBUG std::cerr << "writeXmpFromPacket(): " << writeXmpFromPacket() << "\n"; #endif // writeXmpFromPacket(true); if (writeXmpFromPacket() == false) { if (XmpParser::encode(xmpPacket, xmpData) > 1) { #ifndef SUPPRESS_WARNINGS std::cerr << "Error: Failed to encode XMP metadata.\n"; #endif } } if (xmpPacket.size() > 0) { #ifdef DEBUG std::cerr << std::hex << "write: resourceId: " << kPhotoshopResourceID_XMPPacket << "\n"; std::cerr << std::dec << "Writing XMPPacket: size: " << xmpPacket.size() << "\n"; #endif ul2Data(buf, kPhotoshopResourceType, bigEndian); if (out.write(buf, 4) != 4) throw Error(21); us2Data(buf, kPhotoshopResourceID_XMPPacket, bigEndian); if (out.write(buf, 2) != 2) throw Error(21); us2Data(buf, 0, bigEndian); // NULL resource name if (out.write(buf, 2) != 2) throw Error(21); ul2Data(buf, xmpPacket.size(), bigEndian); if (out.write(buf, 4) != 4) throw Error(21); // Write XMPPacket if (out.write(reinterpret_cast<const byte*>(xmpPacket.data()), static_cast<long>(xmpPacket.size())) != static_cast<long>(xmpPacket.size())) throw Error(21); if (out.error()) throw Error(21); resLength += xmpPacket.size() + 12; if (xmpPacket.size() & 1) // even padding { buf[0] = 0; if (out.write(buf, 1) != 1) throw Error(21); resLength++; } } return resLength; } // PsdImage::writeXmpData
DataBuf Photoshop::setIptcIrb(const byte* pPsData, long sizePsData, const IptcData& iptcData) { if (sizePsData > 0) assert(pPsData); #ifdef DEBUG std::cerr << "IRB block at the beginning of Photoshop::setIptcIrb\n"; if (sizePsData == 0) std::cerr << " None.\n"; else hexdump(std::cerr, pPsData, sizePsData); #endif const byte* record = pPsData; uint32_t sizeIptc = 0; uint32_t sizeHdr = 0; DataBuf rc; // Safe to call with zero psData.size_ if (0 > Photoshop::locateIptcIrb(pPsData, sizePsData, &record, &sizeHdr, &sizeIptc)) { return rc; } Blob psBlob; const uint32_t sizeFront = static_cast<uint32_t>(record - pPsData); // Write data before old record. if (sizePsData > 0 && sizeFront > 0) { append(psBlob, pPsData, sizeFront); } // Write new iptc record if we have it DataBuf rawIptc = IptcParser::encode(iptcData); if (rawIptc.size_ > 0) { byte tmpBuf[12]; std::memcpy(tmpBuf, Photoshop::bimId_, 4); us2Data(tmpBuf + 4, iptc_, bigEndian); tmpBuf[6] = 0; tmpBuf[7] = 0; ul2Data(tmpBuf + 8, rawIptc.size_, bigEndian); append(psBlob, tmpBuf, 12); append(psBlob, rawIptc.pData_, rawIptc.size_); // Data is padded to be even (but not included in size) if (rawIptc.size_ & 1) psBlob.push_back(0x00); } // Write existing stuff after record, data is rounded to be even. const uint32_t sizeOldData = sizeHdr + sizeIptc + (sizeIptc & 1); // Note: Because of the rounding, sizeFront + sizeOldData can be // _greater_ than sizePsData by 1 (not just equal), if the original // data was not padded. if (static_cast<uint32_t>(sizePsData) > sizeFront + sizeOldData) { append(psBlob, record + sizeOldData, sizePsData - sizeFront - sizeOldData); } if (psBlob.size() > 0) rc = DataBuf(&psBlob[0], static_cast<long>(psBlob.size())); #ifdef DEBUG std::cerr << "IRB block at the end of Photoshop::setIptcIrb\n"; if (rc.size_ == 0) std::cerr << " None.\n"; else hexdump(std::cerr, rc.pData_, rc.size_); #endif return rc; } // Photoshop::setIptcIrb
uint32_t PsdImage::writeExifData(const ExifData& exifData, BasicIo& out) { uint32_t resLength = 0; byte buf[8]; if (exifData.count() > 0) { Blob blob; ByteOrder bo = byteOrder(); if (bo == invalidByteOrder) { bo = littleEndian; setByteOrder(bo); } ExifParser::encode(blob, bo, exifData); if (blob.size() > 0) { #ifdef DEBUG std::cerr << std::hex << "write: resourceId: " << kPhotoshopResourceID_ExifInfo << "\n"; std::cerr << std::dec << "Writing ExifInfo: size: " << blob.size() << "\n"; #endif ul2Data(buf, kPhotoshopResourceType, bigEndian); if (out.write(buf, 4) != 4) throw Error(21); us2Data(buf, kPhotoshopResourceID_ExifInfo, bigEndian); if (out.write(buf, 2) != 2) throw Error(21); us2Data(buf, 0, bigEndian); // NULL resource name if (out.write(buf, 2) != 2) throw Error(21); ul2Data(buf, blob.size(), bigEndian); if (out.write(buf, 4) != 4) throw Error(21); // Write encoded Exif data if (out.write(&blob[0], blob.size()) != static_cast<long>(blob.size())) throw Error(21); resLength += blob.size() + 12; if (blob.size() & 1) // even padding { buf[0] = 0; if (out.write(buf, 1) != 1) throw Error(21); resLength++; } } } return resLength; } // PsdImage::writeExifData
void Entry::setValue(uint32 data, ByteOrder byteOrder) { if (pData_ == 0 || size_ < 4) { assert(alloc_); size_ = 4; delete[] pData_; pData_ = new char[size_]; } ul2Data(pData_, data, byteOrder); // do not change size_ type_ = unsignedLong; count_ = 1; }
DataBuf Cr2Header::write() const { DataBuf buf(16); switch (byteOrder()) { case littleEndian: buf.pData_[0] = 'I'; break; case bigEndian: buf.pData_[0] = 'M'; break; case invalidByteOrder: assert(false); break; } buf.pData_[1] = buf.pData_[0]; us2Data(buf.pData_ + 2, tag(), byteOrder()); ul2Data(buf.pData_ + 4, 0x00000010, byteOrder()); memcpy(buf.pData_ + 8, cr2sig_, 4); // Write a dummy value for the RAW IFD offset. The offset-writer is used to set this offset in a second pass. ul2Data(buf.pData_ + 12, 0x00000000, byteOrder()); return buf; } // Cr2Header::write
long TiffHeader::copy(byte* buf) const { switch (byteOrder_) { case littleEndian: buf[0] = 0x49; buf[1] = 0x49; break; case bigEndian: buf[0] = 0x4d; buf[1] = 0x4d; break; case invalidByteOrder: // do nothing break; } us2Data(buf+2, 0x002a, byteOrder_); ul2Data(buf+4, 0x00000008, byteOrder_); return size(); } // TiffHeader::copy
DataBuf OrfHeader::write() const { DataBuf buf(8); switch (byteOrder()) { case littleEndian: buf.pData_[0] = 0x49; buf.pData_[1] = 0x49; break; case bigEndian: buf.pData_[0] = 0x4d; buf.pData_[1] = 0x4d; break; case invalidByteOrder: assert(false); break; } us2Data(buf.pData_ + 2, sig_, byteOrder()); ul2Data(buf.pData_ + 4, 0x00000008, byteOrder()); return buf; }
uint32_t TiffHeaderBase::write(Blob& blob) const { byte buf[8]; switch (byteOrder_) { case littleEndian: buf[0] = 0x49; buf[1] = 0x49; break; case bigEndian: buf[0] = 0x4d; buf[1] = 0x4d; break; case invalidByteOrder: assert(false); break; } us2Data(buf + 2, tag_, byteOrder_); ul2Data(buf + 4, 0x00000008, byteOrder_); append(blob, buf, 8); return 8; }
DataBuf IptcParser::encode(const IptcData& iptcData) { DataBuf buf(iptcData.size()); byte *pWrite = buf.pData_; // Copy the iptc data sets and sort them by record but preserve the order of datasets IptcMetadata sortedIptcData; std::copy(iptcData.begin(), iptcData.end(), std::back_inserter(sortedIptcData)); std::stable_sort(sortedIptcData.begin(), sortedIptcData.end(), cmpIptcdataByRecord); IptcData::const_iterator iter = sortedIptcData.begin(); IptcData::const_iterator end = sortedIptcData.end(); for ( ; iter != end; ++iter) { // marker, record Id, dataset num *pWrite++ = marker_; *pWrite++ = static_cast<byte>(iter->record()); *pWrite++ = static_cast<byte>(iter->tag()); // extended or standard dataset? long dataSize = iter->size(); if (dataSize > 32767) { // always use 4 bytes for extended length uint16_t sizeOfSize = 4 | 0x8000; us2Data(pWrite, sizeOfSize, bigEndian); pWrite += 2; ul2Data(pWrite, dataSize, bigEndian); pWrite += 4; } else { us2Data(pWrite, static_cast<uint16_t>(dataSize), bigEndian); pWrite += 2; } pWrite += iter->value().copy(pWrite, bigEndian); } return buf; } // IptcParser::encode
void Jp2Image::doWriteMetadata(BasicIo& outIo) { if (!io_->isopen()) throw Error(20); if (!outIo.isopen()) throw Error(21); #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Writing JPEG-2000 file " << io_->path() << "\n"; std::cout << "Exiv2::Jp2Image::doWriteMetadata: tmp file created " << outIo.path() << "\n"; #endif // Ensure that this is the correct image type if (!isJp2Type(*io_, true)) { if (io_->error() || io_->eof()) throw Error(20); throw Error(22); } // Write JPEG2000 Signature. if (outIo.write(Jp2Signature, 12) != 12) throw Error(21); Jp2BoxHeader box = {0,0}; byte boxDataSize[4]; byte boxUUIDtype[4]; DataBuf bheaderBuf(8); // Box header : 4 bytes (data size) + 4 bytes (box type). // FIXME: Andreas, why the loop do not stop when EOF is taken from _io. The loop go out by an exception // generated by a zero size data read. while(io_->tell() < io_->size()) { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Position: " << io_->tell() << " / " << io_->size() << "\n"; #endif // Read chunk header. std::memset(bheaderBuf.pData_, 0x00, bheaderBuf.size_); long bufRead = io_->read(bheaderBuf.pData_, bheaderBuf.size_); if (io_->error()) throw Error(14); if (bufRead != bheaderBuf.size_) throw Error(20); // Decode box header. box.boxLength = getLong(bheaderBuf.pData_, bigEndian); box.boxType = getLong(bheaderBuf.pData_ + 4, bigEndian); #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Find box type: " << bheaderBuf.pData_ + 4 << " lenght: " << box.boxLength << "\n"; #endif if (box.boxLength == 0) { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Null Box size has been found. " "This is the last box of file.\n"; #endif box.boxLength = io_->size() - io_->tell() + 8; } if (box.boxLength == 1) { // FIXME. Special case. the real box size is given in another place. } // Read whole box : Box header + Box data (not fixed size - can be null). DataBuf boxBuf(box.boxLength); // Box header (8 bytes) + box data. memcpy(boxBuf.pData_, bheaderBuf.pData_, 8); // Copy header. bufRead = io_->read(boxBuf.pData_ + 8, box.boxLength - 8); // Extract box data. if (io_->error()) { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Error reading source file\n"; #endif throw Error(14); } if (bufRead != (long)(box.boxLength - 8)) { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Cannot read source file data\n"; #endif throw Error(20); } switch(box.boxType) { case kJp2BoxTypeJp2Header: { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Write JP2Header box (lenght: " << box.boxLength << ")\n"; #endif if (outIo.write(boxBuf.pData_, boxBuf.size_) != boxBuf.size_) throw Error(21); // Write all updated metadata here, just after JP2Header. if (exifData_.count() > 0) { // Update Exif data to a new UUID box Blob blob; ExifParser::encode(blob, littleEndian, exifData_); if (blob.size()) { const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; DataBuf rawExif(static_cast<long>(sizeof(ExifHeader) + blob.size())); memcpy(rawExif.pData_, ExifHeader, sizeof(ExifHeader)); memcpy(rawExif.pData_ + sizeof(ExifHeader), &blob[0], blob.size()); DataBuf boxData(8 + 16 + rawExif.size_); ul2Data(boxDataSize, boxData.size_, Exiv2::bigEndian); ul2Data(boxUUIDtype, kJp2BoxTypeUuid, Exiv2::bigEndian); memcpy(boxData.pData_, boxDataSize, 4); memcpy(boxData.pData_ + 4, boxUUIDtype, 4); memcpy(boxData.pData_ + 8, kJp2UuidExif, 16); memcpy(boxData.pData_ + 8 + 16, rawExif.pData_, rawExif.size_); #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Write box with Exif metadata (lenght: " << boxData.size_ << ")\n"; #endif if (outIo.write(boxData.pData_, boxData.size_) != boxData.size_) throw Error(21); } } if (iptcData_.count() > 0) { // Update Iptc data to a new UUID box DataBuf rawIptc = IptcParser::encode(iptcData_); if (rawIptc.size_ > 0) { DataBuf boxData(8 + 16 + rawIptc.size_); ul2Data(boxDataSize, boxData.size_, Exiv2::bigEndian); ul2Data(boxUUIDtype, kJp2BoxTypeUuid, Exiv2::bigEndian); memcpy(boxData.pData_, boxDataSize, 4); memcpy(boxData.pData_ + 4, boxUUIDtype, 4); memcpy(boxData.pData_ + 8, kJp2UuidIptc, 16); memcpy(boxData.pData_ + 8 + 16, rawIptc.pData_, rawIptc.size_); #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Write box with Iptc metadata (lenght: " << boxData.size_ << ")\n"; #endif if (outIo.write(boxData.pData_, boxData.size_) != boxData.size_) throw Error(21); } } if (writeXmpFromPacket() == false) { if (XmpParser::encode(xmpPacket_, xmpData_) > 1) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Failed to encode XMP metadata.\n"; #endif } } if (xmpPacket_.size() > 0) { // Update Xmp data to a new UUID box DataBuf xmp(reinterpret_cast<const byte*>(xmpPacket_.data()), static_cast<long>(xmpPacket_.size())); DataBuf boxData(8 + 16 + xmp.size_); ul2Data(boxDataSize, boxData.size_, Exiv2::bigEndian); ul2Data(boxUUIDtype, kJp2BoxTypeUuid, Exiv2::bigEndian); memcpy(boxData.pData_, boxDataSize, 4); memcpy(boxData.pData_ + 4, boxUUIDtype, 4); memcpy(boxData.pData_ + 8, kJp2UuidXmp, 16); memcpy(boxData.pData_ + 8 + 16, xmp.pData_, xmp.size_); #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Write box with XMP metadata (lenght: " << boxData.size_ << ")\n"; #endif if (outIo.write(boxData.pData_, boxData.size_) != boxData.size_) throw Error(21); } break; } case kJp2BoxTypeUuid: { if(memcmp(boxBuf.pData_ + 8, kJp2UuidExif, sizeof(16)) == 0) { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: strip Exif Uuid box\n"; #endif } else if(memcmp(boxBuf.pData_ + 8, kJp2UuidIptc, sizeof(16)) == 0) { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: strip Iptc Uuid box\n"; #endif } else if(memcmp(boxBuf.pData_ + 8, kJp2UuidXmp, sizeof(16)) == 0) { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: strip Xmp Uuid box\n"; #endif } else { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: write Uuid box (lenght: " << box.boxLength << ")\n"; #endif if (outIo.write(boxBuf.pData_, boxBuf.size_) != boxBuf.size_) throw Error(21); } break; } default: { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: write box (lenght: " << box.boxLength << ")\n"; #endif if (outIo.write(boxBuf.pData_, boxBuf.size_) != boxBuf.size_) throw Error(21); break; } } } #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: EOF\n"; #endif } // Jp2Image::doWriteMetadata
inline long toData(byte* buf, uint32_t t, ByteOrder byteOrder) { return ul2Data(buf, t, byteOrder); }
void PsdImage::doWriteMetadata(BasicIo& outIo) { if (!io_->isopen()) throw Error(20); if (!outIo.isopen()) throw Error(21); #ifdef DEBUG std::cout << "Exiv2::PsdImage::doWriteMetadata: Writing PSD file " << io_->path() << "\n"; std::cout << "Exiv2::PsdImage::doWriteMetadata: tmp file created " << outIo.path() << "\n"; #endif // Ensure that this is the correct image type if (!isPsdType(*io_, true)) { if (io_->error() || io_->eof()) throw Error(20); throw Error(22); } io_->seek(0, BasicIo::beg); // rewind DataBuf lbuf(4096); byte buf[8]; // Get Photoshop header from original file byte psd_head[26]; if (io_->read(psd_head, 26) != 26) throw Error(3, "Photoshop"); // Write Photoshop header data out to new PSD file if (outIo.write(psd_head, 26) != 26) throw Error(21); // Read colorDataLength from original PSD if (io_->read(buf, 4) != 4) throw Error(3, "Photoshop"); uint32_t colorDataLength = getULong(buf, bigEndian); // Write colorDataLength ul2Data(buf, colorDataLength, bigEndian); if (outIo.write(buf, 4) != 4) throw Error(21); #ifdef DEBUG std::cerr << std::dec << "colorDataLength: " << colorDataLength << "\n"; #endif // Copy colorData uint32_t readTotal = 0; long toRead = 0; while (readTotal < colorDataLength) { toRead = static_cast<long>(colorDataLength - readTotal) < lbuf.size_ ? colorDataLength - readTotal : lbuf.size_; if (io_->read(lbuf.pData_, toRead) != toRead) throw Error(3, "Photoshop"); readTotal += toRead; if (outIo.write(lbuf.pData_, toRead) != toRead) throw Error(21); } if (outIo.error()) throw Error(21); uint32_t resLenOffset = io_->tell(); // remember for later update // Read length of all resource blocks from original PSD if (io_->read(buf, 4) != 4) throw Error(3, "Photoshop"); uint32_t oldResLength = getULong(buf, bigEndian); uint32_t newResLength = 0; // Write oldResLength (will be updated later) ul2Data(buf, oldResLength, bigEndian); if (outIo.write(buf, 4) != 4) throw Error(21); #ifdef DEBUG std::cerr << std::dec << "oldResLength: " << oldResLength << "\n"; #endif // Iterate over original resource blocks. // Replace or insert IPTC, EXIF and XMP // Original resource blocks assumed to be sorted ASC bool iptcDone = false; bool exifDone = false; bool xmpDone = false; while (oldResLength > 0) { if (io_->read(buf, 8) != 8) throw Error(3, "Photoshop"); // read resource type and ID uint32_t resourceType = getULong(buf, bigEndian); if (resourceType != kPhotoshopResourceType) { break; // bad resource type } uint16_t resourceId = getUShort(buf + 4, bigEndian); uint32_t resourceNameLength = buf[6]; uint32_t adjResourceNameLen = resourceNameLength & ~1; unsigned char resourceNameFirstChar = buf[7]; // read rest of resource name, plus any padding DataBuf resName(256); if ( io_->read(resName.pData_, adjResourceNameLen) != static_cast<long>(adjResourceNameLen)) throw Error(3, "Photoshop"); // read resource size (actual length w/o padding!) if (io_->read(buf, 4) != 4) throw Error(3, "Photoshop"); uint32_t resourceSize = getULong(buf, bigEndian); uint32_t curOffset = io_->tell(); // Write IPTC_NAA resource block if ( resourceId == kPhotoshopResourceID_IPTC_NAA || (resourceId > kPhotoshopResourceID_IPTC_NAA && iptcDone == false)) { newResLength += writeIptcData(iptcData_, outIo); resourceSize = (resourceSize + 1) & ~1; // adjust for padding iptcDone = true; } // Write ExifInfo resource block else if ( resourceId == kPhotoshopResourceID_ExifInfo || (resourceId > kPhotoshopResourceID_ExifInfo && exifDone == false)) { newResLength += writeExifData(exifData_, outIo); resourceSize = (resourceSize + 1) & ~1; // adjust for padding exifDone = true; } // Write XMPpacket resource block else if ( resourceId == kPhotoshopResourceID_XMPPacket || (resourceId > kPhotoshopResourceID_XMPPacket && xmpDone == false)) { newResLength += writeXmpData(xmpData_, outIo); resourceSize = (resourceSize + 1) & ~1; // adjust for padding xmpDone = true; } // Copy all other resource blocks if ( resourceId != kPhotoshopResourceID_IPTC_NAA && resourceId != kPhotoshopResourceID_ExifInfo && resourceId != kPhotoshopResourceID_XMPPacket) { #ifdef DEBUG std::cerr << std::hex << "copy : resourceId: " << resourceId << "\n"; std::cerr << std::dec; #endif // Copy resource block to new PSD file ul2Data(buf, kPhotoshopResourceType, bigEndian); if (outIo.write(buf, 4) != 4) throw Error(21); us2Data(buf, resourceId, bigEndian); if (outIo.write(buf, 2) != 2) throw Error(21); // Write resource name as Pascal string buf[0] = resourceNameLength & 0x000f; if (outIo.write(buf, 1) != 1) throw Error(21); buf[0] = resourceNameFirstChar; if (outIo.write(buf, 1) != 1) throw Error(21); if ( outIo.write(resName.pData_, adjResourceNameLen) != static_cast<long>(adjResourceNameLen)) throw Error(21); ul2Data(buf, resourceSize, bigEndian); if (outIo.write(buf, 4) != 4) throw Error(21); readTotal = 0; toRead = 0; resourceSize = (resourceSize + 1) & ~1; // pad to even while (readTotal < resourceSize) { toRead = static_cast<long>(resourceSize - readTotal) < lbuf.size_ ? resourceSize - readTotal : lbuf.size_; if (io_->read(lbuf.pData_, toRead) != toRead) { throw Error(3, "Photoshop"); } readTotal += toRead; if (outIo.write(lbuf.pData_, toRead) != toRead) throw Error(21); } if (outIo.error()) throw Error(21); newResLength += resourceSize + adjResourceNameLen + 12; } io_->seek(curOffset + resourceSize, BasicIo::beg); oldResLength -= (12 + adjResourceNameLen + resourceSize); } // Append IPTC_NAA resource block, if not yet written if (iptcDone == false) { newResLength += writeIptcData(iptcData_, outIo); iptcDone = true; } // Append ExifInfo resource block, if not yet written if (exifDone == false) { newResLength += writeExifData(exifData_, outIo); exifDone = true; } // Append XmpPacket resource block, if not yet written if (xmpDone == false) { newResLength += writeXmpData(xmpData_, outIo); xmpDone = true; } // Copy remaining data long readSize = 0; while ((readSize=io_->read(lbuf.pData_, lbuf.size_))) { if (outIo.write(lbuf.pData_, readSize) != readSize) throw Error(21); } if (outIo.error()) throw Error(21); // Update length of resources #ifdef DEBUG std::cerr << "newResLength: " << newResLength << "\n"; #endif outIo.seek(resLenOffset, BasicIo::beg); ul2Data(buf, newResLength, bigEndian); if (outIo.write(buf, 4) != 4) throw Error(21); } // PsdImage::doWriteMetadata
void Ifd::setNext(uint32 next, ByteOrder byteOrder) { assert(pNext_); ul2Data(pNext_, next, byteOrder); next_ = next; }