File indexing completed on 2024-05-12 15:59:40

0001 /*
0002  *  SPDX-FileCopyrightText: 2009 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 #include "psd_resource_block.h"
0007 
0008 #include <QBuffer>
0009 #include <QDataStream>
0010 #include <QIODevice>
0011 
0012 #include <kis_debug.h>
0013 
0014 #include "psd.h"
0015 #include "psd_resource_section.h"
0016 #include "psd_utils.h"
0017 
0018 PSDResourceBlock::PSDResourceBlock()
0019     : KisAnnotation("PSD Resource Block", "", QByteArray())
0020     , identifier(PSDImageResourceSection::UNKNOWN)
0021     , dataSize(0)
0022     , resource(0)
0023 {
0024 }
0025 
0026 bool PSDResourceBlock::read(QIODevice &io)
0027 {
0028     dbgFile << "Reading resource block";
0029     if (io.atEnd()) {
0030         error = "Could not read resource block: no bytes left.";
0031         return false;
0032     }
0033 
0034     QByteArray b;
0035     b = io.read(4);
0036     if (b.size() != 4 || QString(b) != "8BIM") {
0037         error = QString("Could not read resource block signature. Got %1.").arg(QString(b));
0038         return false;
0039     }
0040 
0041     if (!psdread(io, identifier)) {
0042         error = "Could not read resource block identifier";
0043         return false;
0044     }
0045 
0046     dbgFile << "\tresource block identifier" << PSDImageResourceSection::idToString((PSDImageResourceSection::PSDResourceID)identifier) << identifier;
0047 
0048     m_type = QString("PSD Resource Block: %1").arg(identifier);
0049 
0050     if (!psdread_pascalstring(io, name, 2)) {
0051         error = "Could not read name of resource block";
0052         return false;
0053     }
0054 
0055     dbgFile << "\tresource block name" << name;
0056 
0057     if (!psdread(io, dataSize)) {
0058         error = QString("Could not read datasize for resource block with name %1 of type %2").arg(name).arg(identifier);
0059         return false;
0060     }
0061 
0062     if ((dataSize & 0x01) != 0) {
0063         dataSize++;
0064     }
0065 
0066     dbgFile << "\tresource block size" << dataSize;
0067 
0068     m_description = PSDImageResourceSection::idToString((PSDImageResourceSection::PSDResourceID)identifier);
0069 
0070     data = io.read(dataSize);
0071     if (data.size() != (int)dataSize) {
0072         error = QString("Could not read data for resource block with name %1 of type %2").arg(name).arg(identifier);
0073         return false;
0074     }
0075 
0076     m_annotation = data;
0077 
0078     switch (identifier) {
0079         //    case PSDImageResourceSection::MAC_PRINT_INFO:
0080         //        resource = new MAC_PRINT_INFO_1001;
0081         //        break;
0082     case PSDImageResourceSection::RESN_INFO:
0083         resource = new RESN_INFO_1005;
0084         break;
0085         //    case PSDImageResourceSection::ALPHA_NAMES:
0086         //        resource = new ALPHA_NAMES_1006;
0087         //        break;
0088         //    case PSDImageResourceSection::DISPLAY_INFO:
0089         //        resource = new DISPLAY_INFO_1007;
0090         //        break;
0091         //    case PSDImageResourceSection::CAPTION:
0092         //        resource = new CAPTION_1008;
0093         //        break;
0094         //    case PSDImageResourceSection::BORDER_INFO:
0095         //        resource = new BORDER_INFO_1009;
0096         //        break;
0097         //    case PSDImageResourceSection::BACKGROUND_COL:
0098         //        resource = new BACKGROUND_COL_1010;
0099         //        break;
0100         //    case PSDImageResourceSection::PRINT_FLAGS:
0101         //        resource = new PRINT_FLAGS_1011;
0102         //        break;
0103         //    case PSDImageResourceSection::GREY_HALFTONE:
0104         //        resource = new GREY_HALFTONE_1012;
0105         //        break;
0106         //    case PSDImageResourceSection::COLOR_HALFTONE:
0107         //        resource = new COLOR_HALFTONE_1013;
0108         //        break;
0109         //    case PSDImageResourceSection::DUOTONE_HALFTONE:
0110         //        resource = new DUOTONE_HALFTONE_1014;
0111         //        break;
0112         //    case PSDImageResourceSection::GREY_XFER:
0113         //        resource = new GREY_XFER_1015;
0114         //        break;
0115         //    case PSDImageResourceSection::COLOR_XFER:
0116         //        resource = new COLOR_XFER_1016;
0117         //        break;
0118         //    case PSDImageResourceSection::DUOTONE_XFER:
0119         //        resource = new DUOTONE_XFER_1017;
0120         //        break;
0121         //    case PSDImageResourceSection::DUOTONE_INFO:
0122         //        resource = new DUOTONE_INFO_1018;
0123         //        break;
0124         //    case PSDImageResourceSection::EFFECTIVE_BW:
0125         //        resource = new EFFECTIVE_BW_1019;
0126         //        break;
0127         //    case PSDImageResourceSection::EPS_OPT:
0128         //        resource = new  EPS_OPT_1021;
0129         //        break;
0130         //    case PSDImageResourceSection::QUICK_MASK:
0131         //        resource = new QUICK_MASK_1022;
0132         //        break;
0133         //    case PSDImageResourceSection::LAYER_STATE:
0134         //        resource = new  LAYER_STATE_1024;
0135         //        break;
0136         //    case PSDImageResourceSection::WORKING_PATH:
0137         //        resource = new WORKING_PATH_1025;
0138         //        break;
0139         //    case PSDImageResourceSection::LAYER_GROUP:
0140         //        resource = new LAYER_GROUP_1026;
0141         //        break;
0142         //    case PSDImageResourceSection::IPTC_NAA_DATA:
0143         //        resource = new IPTC_NAA_DATA_1028;
0144         //        break;
0145         //    case PSDImageResourceSection::IMAGE_MODE_RAW:
0146         //        resource = new IMAGE_MODE_RAW_1029;
0147         //        break;
0148         //    case PSDImageResourceSection::JPEG_QUAL:
0149         //        resource = new JPEG_QUAL_1030;
0150         //        break;
0151         //    case PSDImageResourceSection::GRID_GUIDE:
0152         //        resource = new GRID_GUIDE_1032;
0153         //        break;
0154         //    case PSDImageResourceSection::THUMB_RES:
0155         //        resource = new THUMB_RES_1033;
0156         //        break;
0157         //    case PSDImageResourceSection::COPYRIGHT_FLG:
0158         //        resource = new COPYRIGHT_FLG_1034;
0159         //        break;
0160         //    case PSDImageResourceSection::URL:
0161         //        resource = new URL_1035;
0162         //        break;
0163         //    case PSDImageResourceSection::THUMB_RES2:
0164         //        resource = new THUMB_RES2_1036;
0165         //        break;
0166     case PSDImageResourceSection::GLOBAL_ANGLE:
0167         resource = new GLOBAL_ANGLE_1037;
0168         break;
0169         //    case PSDImageResourceSection::COLOR_SAMPLER:
0170         //        resource = new COLOR_SAMPLER_1038;
0171         //        break;
0172     case PSDImageResourceSection::ICC_PROFILE:
0173         resource = new ICC_PROFILE_1039;
0174         break;
0175         //    case PSDImageResourceSection::WATERMARK:
0176         //        resource = new WATERMARK_1040;
0177         //        break;
0178         //    case PSDImageResourceSection::ICC_UNTAGGED:
0179         //        resource = new ICC_UNTAGGED_1041;
0180         //        break;
0181         //    case PSDImageResourceSection::EFFECTS_VISIBLE:
0182         //        resource = new EFFECTS_VISIBLE_1042;
0183         //        break;
0184         //    case PSDImageResourceSection::SPOT_HALFTONE:
0185         //        resource = new SPOT_HALFTONE_1043;
0186         //        break;
0187         //    case PSDImageResourceSection::DOC_IDS:
0188         //        resource = new DOC_IDS_1044;
0189         //        break;
0190         //    case PSDImageResourceSection::ALPHA_NAMES_UNI:
0191         //        resource = new ALPHA_NAMES_UNI_1045;
0192         //        break;
0193         //    case PSDImageResourceSection::IDX_COL_TAB_CNT:
0194         //        resource = new IDX_COL_TAB_CNT_1046;
0195         //        break;
0196         //    case PSDImageResourceSection::IDX_TRANSPARENT:
0197         //        resource = new IDX_TRANSPARENT_1047;
0198         //        break;
0199     case PSDImageResourceSection::GLOBAL_ALT:
0200         resource = new GLOBAL_ALT_1049;
0201         break;
0202         //    case PSDImageResourceSection::SLICES:
0203         //        resource = new SLICES_1050;
0204         //        break;
0205         //    case PSDImageResourceSection::WORKFLOW_URL_UNI:
0206         //        resource = new WORKFLOW_URL_UNI_1051;
0207         //        break;
0208         //    case PSDImageResourceSection::JUMP_TO_XPEP:
0209         //        resource = new JUMP_TO_XPEP_1052;
0210         //        break;
0211         //    case PSDImageResourceSection::ALPHA_ID:
0212         //        resource = new ALPHA_ID_1053;
0213         //        break;
0214         //    case PSDImageResourceSection::URL_LIST_UNI:
0215         //        resource = new URL_LIST_UNI_1054;
0216         //        break;
0217         //    case PSDImageResourceSection::VERSION_INFO:
0218         //        resource = new VERSION_INFO_1057;
0219         //        break;
0220         //    case PSDImageResourceSection::EXIF_DATA:
0221         //        resource = new EXIF_DATA_1058;
0222         //        break;
0223         //    case PSDImageResourceSection::XMP_DATA:
0224         //        resource = new XMP_DATA_1060;
0225         //        break;
0226         //    case PSDImageResourceSection::PATH_INFO_FIRST:
0227         //        resource = new PATH_INFO_FIRST_2000;
0228         //        break;
0229         //    case PSDImageResourceSection::PATH_INFO_LAST:
0230         //        resource = new PATH_INFO_LAST_2998;
0231         //        break;
0232         //    case PSDImageResourceSection::CLIPPING_PATH:
0233         //        resource = new CLIPPING_PATH_2999;
0234         //        break;
0235         //    case PSDImageResourceSection::PRINT_FLAGS_2:
0236         //        resource = new PRINT_FLAGS_2_10000;
0237         //        break;
0238     default:;
0239     }
0240 
0241     if (resource) {
0242         resource->interpretBlock(data);
0243     }
0244 
0245     return valid();
0246 }
0247 
0248 bool PSDResourceBlock::write(QIODevice &io) const
0249 {
0250     dbgFile << "Writing Resource Block" << PSDImageResourceSection::idToString((PSDImageResourceSection::PSDResourceID)identifier) << identifier;
0251 
0252     if (resource && !resource->valid()) {
0253         error = QString("Cannot write an invalid Resource Block");
0254         return false;
0255     }
0256 
0257     if (identifier == PSDImageResourceSection::LAYER_STATE || identifier == PSDImageResourceSection::LAYER_GROUP
0258         || identifier == PSDImageResourceSection::LAYER_COMPS || identifier == PSDImageResourceSection::LAYER_GROUP_ENABLED_ID
0259         || identifier == PSDImageResourceSection::LAYER_SELECTION_ID) {
0260         /**
0261          * We can actually handle LAYER_SELECTION_ID. It consists
0262          * of a number of layers and a list of IDs to select, which
0263          * are retrieved from 'lyid' additional layer block.
0264          */
0265         dbgFile << "Skip writing resource block" << identifier << displayText();
0266         return true;
0267     }
0268 
0269     QByteArray ba;
0270 
0271     // createBlock returns true by default but does not change the data.
0272     if (resource && !resource->createBlock(ba)) {
0273         error = resource->error;
0274         return false;
0275     } else if (!resource) {
0276         // reconstruct from the data
0277         QBuffer buf(&ba);
0278         buf.open(QBuffer::WriteOnly);
0279         psdwrite(buf, "8BIM");
0280         psdwrite(buf, identifier);
0281         psdwrite_pascalstring(buf, name);
0282         psdwrite(buf, dataSize);
0283         buf.write(data);
0284         buf.close();
0285     }
0286     if (io.write(ba.constData(), ba.size()) != ba.size()) {
0287         error = QString("Could not write complete resource");
0288         return false;
0289     }
0290 
0291     return true;
0292 }
0293 
0294 bool PSDResourceBlock::valid()
0295 {
0296     if (identifier == PSDImageResourceSection::UNKNOWN) {
0297         error = QString("Unknown ID: %1").arg(identifier);
0298         return false;
0299     }
0300     if (data.size() != (int)dataSize) {
0301         error = QString("Needed %1 bytes, got %2 bytes of data").arg(dataSize).arg(data.length());
0302         return false;
0303     }
0304     return true;
0305 }
0306 
0307 bool RESN_INFO_1005::interpretBlock(QByteArray data)
0308 {
0309     dbgFile << "Reading RESN_INFO_1005";
0310 
0311     // the resolution we set on the image should be dpi; we can also set the unit on the KisDocument.
0312     QDataStream ds(data);
0313     ds.setByteOrder(QDataStream::BigEndian);
0314 
0315     ds >> hRes >> hResUnit >> widthUnit >> vRes >> vResUnit >> heightUnit;
0316 
0317     /* Resolution always recorded as pixels / inch in a fixed point implied
0318        decimal int32 with 16 bits before point and 16 after (i.e. cast as
0319        double and divide resolution by 2^16 */
0320     dbgFile << "hres" << hRes << "vres" << vRes;
0321 
0322     hRes = hRes / 65536.0;
0323     vRes = vRes / 65536.0;
0324 
0325     dbgFile << hRes << hResUnit << widthUnit << vRes << vResUnit << heightUnit;
0326 
0327     return ds.atEnd();
0328 }
0329 
0330 bool RESN_INFO_1005::createBlock(QByteArray &data)
0331 {
0332     dbgFile << "Writing RESN_INFO_1005";
0333     QBuffer buf(&data);
0334 
0335     startBlock(buf, PSDImageResourceSection::RESN_INFO, 16);
0336 
0337     // Convert to 16.16 fixed point
0338     Fixed h = hRes * 65536.0 + 0.5;
0339     dbgFile << "h" << h << "hRes" << hRes;
0340     psdwrite(buf, h);
0341     psdwrite(buf, hResUnit);
0342     psdwrite(buf, widthUnit);
0343 
0344     // Convert to 16.16 fixed point
0345     Fixed v = vRes * 65536.0 + 0.5;
0346     dbgFile << "v" << v << "vRes" << vRes;
0347     psdwrite(buf, v);
0348     psdwrite(buf, vResUnit);
0349     psdwrite(buf, heightUnit);
0350 
0351     buf.close();
0352 
0353     return true;
0354 }
0355 
0356 bool ICC_PROFILE_1039::interpretBlock(QByteArray data)
0357 {
0358     dbgFile << "Reading ICC_PROFILE_1039";
0359 
0360     icc = data;
0361 
0362     return true;
0363 }
0364 
0365 bool ICC_PROFILE_1039::createBlock(QByteArray &data)
0366 {
0367     dbgFile << "Writing ICC_PROFILE_1039";
0368     if (icc.size() == 0) {
0369         error = "ICC_PROFILE_1039: Trying to save an empty profile";
0370         return false;
0371     }
0372     QBuffer buf(&data);
0373     startBlock(buf, PSDImageResourceSection::ICC_PROFILE, icc.size());
0374     buf.write(icc.constData(), icc.size());
0375     buf.close();
0376 
0377     return true;
0378 }