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
PSDWriter(BPositionIO * stream)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
~PSDWriter()64 PSDWriter::~PSDWriter()
65 {
66 }
67
68
69 bool
IsReady(void)70 PSDWriter::IsReady(void)
71 {
72 return fReady;
73 }
74
75
76 void
SetCompression(int16 compression)77 PSDWriter::SetCompression(int16 compression)
78 {
79 fCompression = compression;
80 }
81
82
83 void
SetVersion(int16 ver)84 PSDWriter::SetVersion(int16 ver)
85 {
86 fVersion = ver;
87 }
88
89
90 status_t
Encode(BPositionIO * target)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*
_PackBits(uint8 * buff,int32 len)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
_LoadChannelsFromRGBA32(void)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
_WriteInt64ToStream(BPositionIO * stream,int64 val)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
_WriteUInt64ToStream(BPositionIO * stream,uint64 val)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
_WriteInt32ToStream(BPositionIO * stream,int32 val)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
_WriteUInt32ToStream(BPositionIO * stream,uint32 val)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
_WriteInt16ToStream(BPositionIO * stream,int16 val)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
_WriteUInt16ToStream(BPositionIO * stream,uint16 val)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
_WriteInt8ToStream(BPositionIO * stream,int8 val)377 PSDWriter::_WriteInt8ToStream(BPositionIO *stream, int8 val)
378 {
379 stream->Write(&val, sizeof(int8));
380 }
381
382
383 void
_WriteUInt8ToStream(BPositionIO * stream,uint8 val)384 PSDWriter::_WriteUInt8ToStream(BPositionIO *stream, uint8 val)
385 {
386 stream->Write(&val, sizeof(uint8));
387 }
388
389
390 void
_WriteFillBlockToStream(BPositionIO * stream,uint8 val,size_t count)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
_WriteBlockToStream(BPositionIO * stream,uint8 * val,size_t count)400 PSDWriter::_WriteBlockToStream(BPositionIO *stream,
401 uint8 *val, size_t count)
402 {
403 stream->Write(val, count);
404 }
405