1 /* 2 * Copyright 2013, Gerasim Troeglazov, 3dEyes@gmail.com. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <File.h> 8 9 #include "BaseTranslator.h" 10 #include "PSDWriter.h" 11 #include "DataArray.h" 12 13 14 PSDWriter::PSDWriter(BPositionIO *stream) 15 { 16 fAlphaChannel = -1; 17 fStream = stream; 18 fReady = false; 19 20 TranslatorBitmap header; 21 stream->Seek(0, SEEK_SET); 22 status_t err = stream->Read(&header, sizeof(TranslatorBitmap)); 23 if (err < B_OK) 24 return; 25 else if (err < (int)sizeof(TranslatorBitmap)) 26 return; 27 28 fBitmapDataPos = stream->Position(); 29 30 BRect bounds; 31 bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left); 32 bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top); 33 bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right); 34 bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom); 35 fInRowBytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes); 36 fColorSpace = (color_space)B_BENDIAN_TO_HOST_INT32(header.colors); 37 38 switch (fColorSpace) { 39 case B_GRAY8: 40 case B_CMAP8: 41 fChannels = 1; 42 break; 43 case B_RGBA32: 44 fChannels = 4; 45 fAlphaChannel = 3; 46 break; 47 case B_RGB32: 48 fChannels = 3; 49 break; 50 default: 51 return; 52 }; 53 54 fWidth = bounds.IntegerWidth() + 1; 55 fHeight = bounds.IntegerHeight() + 1; 56 57 fVersion = PSD_FILE; 58 fCompression = PSD_COMPRESSED_RAW; 59 60 fReady = true; 61 } 62 63 64 PSDWriter::~PSDWriter() 65 { 66 } 67 68 69 bool 70 PSDWriter::IsReady(void) 71 { 72 return fReady; 73 } 74 75 76 void 77 PSDWriter::SetCompression(int16 compression) 78 { 79 fCompression = compression; 80 } 81 82 83 void 84 PSDWriter::SetVersion(int16 ver) 85 { 86 fVersion = ver; 87 } 88 89 90 status_t 91 PSDWriter::Encode(BPositionIO *target) 92 { 93 if (!fReady) 94 return B_NO_TRANSLATOR; 95 96 status_t status = _LoadChannelsFromRGBA32(); 97 if (status != B_OK) 98 return status; 99 100 // PSD header 101 BDataArray psdHeader(64); 102 psdHeader << "8BPS"; // Signature 103 psdHeader << (uint16)fVersion; // Version 104 psdHeader.Repeat(0, 6); // Reserved 105 psdHeader << fChannels; // Channels 106 psdHeader << fHeight << fWidth; // Image size 107 psdHeader << (int16)8; // Depth 108 psdHeader << (int16)PSD_COLOR_MODE_RGB; // ColorMode 109 110 // Color mode section 111 BDataArray psdColorModeSection(16); 112 psdColorModeSection << (uint32)0; 113 114 // Image resource section 115 BDataArray psdImageResourceSection(64); 116 psdImageResourceSection << "8BIM"; // Block signature 117 psdImageResourceSection << (uint16)1005; 118 psdImageResourceSection << (uint16)0; 119 psdImageResourceSection << (uint32)16; 120 uint8 resBlock[16] = {0x00, 0x48, 0x00, 0x00, 121 0x00, 0x01, 0x00, 0x01, 122 0x00, 0x48, 0x00, 0x00, 123 0x00, 0x01, 0x00, 0x01}; 124 psdImageResourceSection.Append(resBlock, 16); 125 // Current layer info 126 psdImageResourceSection << "8BIM"; // Block signature 127 psdImageResourceSection << (uint16)1024; 128 psdImageResourceSection << (uint16)0; 129 psdImageResourceSection << (uint32)2; 130 psdImageResourceSection << (uint16)0; // Set current layer to 0 131 132 // Layer & mask section 133 BDataArray psdLayersSection; 134 psdLayersSection << (uint16)1; // Layers count 135 psdLayersSection << (uint32)0; // Layer rect 136 psdLayersSection << (uint32)0; 137 psdLayersSection << (uint32)fHeight; 138 psdLayersSection << (uint32)fWidth; 139 psdLayersSection << (uint16)fChannels; 140 141 for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) { 142 if (channelIdx == 3) 143 psdLayersSection << (int16)-1; // Alpha channel id (-1) 144 else 145 psdLayersSection << (int16)channelIdx; // Channel num 146 147 if (fCompression == PSD_COMPRESSED_RAW) { 148 if (fVersion == PSD_FILE) { 149 psdLayersSection << (uint32)(psdChannel[channelIdx].Length() 150 + sizeof(int16)); 151 } else { 152 psdLayersSection << (uint64)(psdChannel[channelIdx].Length() 153 + sizeof(int16)); 154 } 155 } else { 156 if (fVersion == PSD_FILE) { 157 psdLayersSection << (uint32)(psdChannel[channelIdx].Length() 158 + psdByteCounts[channelIdx].Length() + sizeof(int16)); 159 } else { 160 psdLayersSection << (uint64)(psdChannel[channelIdx].Length() 161 + psdByteCounts[channelIdx].Length() + sizeof(int16)); 162 } 163 } 164 } 165 166 psdLayersSection << "8BIM"; 167 psdLayersSection << "norm"; // Blend mode = norm 168 psdLayersSection << (uint8)255; // Opacity 169 psdLayersSection << (uint8)0; // Clipping 170 psdLayersSection << (uint8)1; // Flags 171 psdLayersSection << (uint8)0; // Flags 172 psdLayersSection << (uint32)24; // Extra data length 173 psdLayersSection << (uint32)0; // Mask info 174 psdLayersSection << (uint32)0; 175 176 psdLayersSection << (uint8)15; // Layer name length 177 uint8 layerName[16] = {"Layer #1 "}; 178 psdLayersSection.Append(layerName, 15); // Layer name 179 180 if (fCompression == PSD_COMPRESSED_RAW) { 181 for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) { 182 psdLayersSection << fCompression; // Compression mode 183 psdLayersSection.Append(psdChannel[channelIdx]); // Channel data 184 } 185 } else { 186 for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) { 187 psdLayersSection << fCompression; // Compression mode 188 psdLayersSection.Append(psdByteCounts[channelIdx]); // Bytes count 189 psdLayersSection.Append(psdChannel[channelIdx]); // Channel data 190 } 191 } 192 193 if (fCompression == PSD_COMPRESSED_RLE 194 && psdLayersSection.Length() % 2 != 0) { 195 psdLayersSection << (uint8)0; 196 } 197 198 psdHeader.WriteToStream(target); 199 200 psdColorModeSection.WriteToStream(target); 201 202 _WriteUInt32ToStream(target, psdImageResourceSection.Length()); 203 psdImageResourceSection.WriteToStream(target); 204 205 if (fVersion == PSD_FILE) { 206 _WriteUInt32ToStream(target, psdLayersSection.Length() + sizeof(int32)); 207 _WriteUInt32ToStream(target, psdLayersSection.Length()); 208 } else { 209 _WriteUInt64ToStream(target, psdLayersSection.Length() + sizeof(int64)); 210 _WriteUInt64ToStream(target, psdLayersSection.Length()); 211 } 212 psdLayersSection.WriteToStream(target); 213 214 // Merged layer 215 _WriteUInt16ToStream(target, fCompression); // Compression mode 216 217 if (fCompression == PSD_COMPRESSED_RLE) { 218 for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) 219 psdByteCounts[channelIdx].WriteToStream(target); 220 } 221 222 for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) 223 psdChannel[channelIdx].WriteToStream(target); 224 225 return B_OK; 226 } 227 228 229 BDataArray* 230 PSDWriter::_PackBits(uint8 *buff, int32 len) 231 { 232 BDataArray *packedBits = new BDataArray(); 233 234 int32 count = len; 235 len = 0; 236 237 while (count > 0) { 238 int i; 239 for (i = 0; (i < 128) && (buff[0] == buff[i]) && (count - i > 0); i++); 240 if (i < 2) { 241 for (i = 0; i < 128; i++) { 242 bool b1 = buff[i] != buff[i + 1]; 243 bool b3 = buff[i] != buff[i + 2]; 244 bool b2 = count - (i + 2) < 1; 245 if (count - (i + 1) <= 0) 246 break; 247 if (!(b1 || b2 || b3)) 248 break; 249 } 250 251 if (count == 1) 252 i = 1; 253 254 if (i > 0) { 255 packedBits->Append((uint8)(i - 1)); 256 for (int j = 0; j < i; j++) 257 packedBits->Append((uint8)buff[j]); 258 buff += i; 259 count -= i; 260 len += (i + 1); 261 } 262 } else { 263 packedBits->Append((uint8)(-(i - 1))); 264 packedBits->Append((uint8)(*buff)); 265 buff += i; 266 count -= i; 267 len += 2; 268 } 269 } 270 return packedBits; 271 } 272 273 274 status_t 275 PSDWriter::_LoadChannelsFromRGBA32(void) 276 { 277 if (fColorSpace != B_RGB32 && fColorSpace != B_RGBA32) 278 return B_NO_TRANSLATOR; 279 280 int32 channelSize = fWidth * fHeight; 281 282 fStream->Seek(fBitmapDataPos, SEEK_SET); 283 284 if (fCompression == PSD_COMPRESSED_RAW) { 285 for (int i = 0; i < channelSize; i++) { 286 uint8 rgba[4]; 287 fStream->Read(rgba, sizeof(uint32)); 288 psdChannel[0].Append((uint8)rgba[2]); // Red channel 289 psdChannel[1].Append((uint8)rgba[1]); // Green channel 290 psdChannel[2].Append((uint8)rgba[0]); // Blue channel 291 if (fChannels == 4) 292 psdChannel[3].Append((uint8)rgba[3]); // Alpha channel 293 } 294 return B_OK; 295 } else if (fCompression == PSD_COMPRESSED_RLE) { 296 for (int32 h = 0; h < fHeight; h++) { 297 BDataArray lineData[4]; 298 299 for (int32 w = 0; w < fWidth; w++) { 300 uint8 rgba[4]; 301 fStream->Read(rgba, sizeof(uint32)); 302 lineData[0].Append((uint8)rgba[2]); // Red channel 303 lineData[1].Append((uint8)rgba[1]); // Green channel 304 lineData[2].Append((uint8)rgba[0]); // Blue channel 305 if (fChannels == 4) 306 lineData[3].Append((uint8)rgba[3]); // Alpha channel 307 } 308 309 for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) { 310 BDataArray *packedLine = _PackBits(lineData[channelIdx].Buffer(), 311 lineData[channelIdx].Length()); 312 313 if (fVersion == PSD_FILE) 314 psdByteCounts[channelIdx].Append((uint16)packedLine->Length()); 315 else 316 psdByteCounts[channelIdx].Append((uint32)packedLine->Length()); 317 318 psdChannel[channelIdx].Append(*packedLine); 319 delete packedLine; 320 } 321 } 322 return B_OK; 323 } 324 return B_NO_TRANSLATOR; 325 } 326 327 328 void 329 PSDWriter::_WriteInt64ToStream(BPositionIO *stream, int64 val) 330 { 331 val = B_HOST_TO_BENDIAN_INT64(val); 332 stream->Write(&val, sizeof(int32)); 333 } 334 335 336 void 337 PSDWriter::_WriteUInt64ToStream(BPositionIO *stream, uint64 val) 338 { 339 val = B_HOST_TO_BENDIAN_INT64(val); 340 stream->Write(&val, sizeof(uint64)); 341 } 342 343 344 void 345 PSDWriter::_WriteInt32ToStream(BPositionIO *stream, int32 val) 346 { 347 val = B_HOST_TO_BENDIAN_INT32(val); 348 stream->Write(&val, sizeof(int32)); 349 } 350 351 352 void 353 PSDWriter::_WriteUInt32ToStream(BPositionIO *stream, uint32 val) 354 { 355 val = B_HOST_TO_BENDIAN_INT32(val); 356 stream->Write(&val, sizeof(uint32)); 357 } 358 359 360 void 361 PSDWriter::_WriteInt16ToStream(BPositionIO *stream, int16 val) 362 { 363 val = B_HOST_TO_BENDIAN_INT16(val); 364 stream->Write(&val, sizeof(int16)); 365 } 366 367 368 void 369 PSDWriter::_WriteUInt16ToStream(BPositionIO *stream, uint16 val) 370 { 371 val = B_HOST_TO_BENDIAN_INT16(val); 372 stream->Write(&val, sizeof(int16)); 373 } 374 375 376 void 377 PSDWriter::_WriteInt8ToStream(BPositionIO *stream, int8 val) 378 { 379 stream->Write(&val, sizeof(int8)); 380 } 381 382 383 void 384 PSDWriter::_WriteUInt8ToStream(BPositionIO *stream, uint8 val) 385 { 386 stream->Write(&val, sizeof(uint8)); 387 } 388 389 390 void 391 PSDWriter::_WriteFillBlockToStream(BPositionIO *stream, 392 uint8 val, size_t count) 393 { 394 for (size_t i = 0; i < count; i++) 395 stream->Write(&val, sizeof(uint8)); 396 } 397 398 399 void 400 PSDWriter::_WriteBlockToStream(BPositionIO *stream, 401 uint8 *val, size_t count) 402 { 403 stream->Write(val, count); 404 } 405