]> git.sesse.net Git - casparcg/blob - modules/psd/layer.cpp
* added parsing of text-layer data
[casparcg] / modules / psd / layer.cpp
1 /*
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Niklas P Andersson, niklas.p.andersson@svt.se
20 */
21
22 #include "layer.h"
23 #include "descriptor.h"
24 #include "util\pdf_reader.h"
25
26 typedef unsigned char uint8_t;
27 #include <algorithm>
28 #include "../image/util/image_algorithms.h"
29 #include "../image/util/image_view.h"
30
31 namespace caspar { namespace psd {
32
33 void read_raw_image_data(BEFileInputStream& stream, const channel_ptr& channel, image8bit_ptr target, unsigned char offset);
34 void read_rle_image_data(BEFileInputStream& stream, const channel_ptr& channel, image8bit_ptr target, unsigned char offset);
35
36 layer_ptr layer::create(BEFileInputStream& stream)
37 {
38         layer_ptr result(std::make_shared<layer>());
39         result->rect_.top = stream.read_long();
40         result->rect_.left = stream.read_long();
41         result->rect_.bottom = stream.read_long();
42         result->rect_.right = stream.read_long();
43
44         //Get info about the channels in the layer
45         unsigned short channelCount = stream.read_short();
46         for(int channelIndex = 0; channelIndex < channelCount; ++channelIndex)
47         {
48                 short channel_id = static_cast<short>(stream.read_short());
49                 unsigned long data_length = stream.read_long();
50
51                 if(channel_id <= -2)
52                         result->masks_++;
53
54                 channel_ptr channel(std::make_shared<Channel>(channel_id, data_length));
55                 result->channels_.push_back(channel);
56         }
57
58         unsigned long blendModeSignature = stream.read_long();
59         if(blendModeSignature != '8BIM')
60                 throw PSDFileFormatException();
61
62         unsigned long blendModeKey = stream.read_long();
63         result->blend_mode_ = int_to_blend_mode(blendModeKey);
64
65         result->opacity_ = stream.read_byte();
66         result->baseClipping_ = stream.read_byte() == 1 ? false : true;
67         result->flags_ = stream.read_byte();
68
69         stream.discard_bytes(1);
70
71         unsigned long extraDataSize = stream.read_long();
72         long position1 = stream.current_position();
73         result->mask_.read_mask_data(stream);
74         result->read_blending_ranges(stream);
75
76         result->name_ = stream.read_pascal_string(4);
77
78         //Aditional Layer Information
79         unsigned long end_of_layer_info = position1 + extraDataSize;
80         
81         try
82         {
83                 while(stream.current_position() < end_of_layer_info)
84                 {
85                         unsigned long signature = stream.read_long();
86                         if(signature != '8BIM' && signature != '8B64')
87                                 throw PSDFileFormatException();
88
89                         unsigned long key = stream.read_long();
90                         unsigned long length = stream.read_long();
91                         unsigned long end_of_chunk = stream.current_position() + length;
92
93                         if(key == 'TySh')       //type tool object settings
94                         {
95                                 std::wstring text;      //the text in the layer
96
97                                 stream.read_short();    //should be 1
98                                 stream.discard_bytes(6*8);      //just throw transformation info for now
99                                 stream.read_short();    //"text version" should be 50
100                                 stream.read_long();             //"descriptor version" should be 16
101
102                                 //text data descriptor ('descriptor structure')
103                                 descriptor text_descriptor;
104                                 if(!text_descriptor.populate(stream))
105                                         throw PSDFileFormatException();
106                                 else
107                                 {
108                                         if(text_descriptor.has_item(L"EngineData"))
109                                         {
110                                                 const descriptor_item& text_data = text_descriptor.get_item(L"EngineData");
111                                                 read_pdf(result->text_layer_info_, text_data.rawdata_data);
112                                         }
113                                 }
114
115                                 stream.read_short();    //"warp version" should be 1
116                                 stream.read_long();             //"descriptor version" should be 16
117
118                                 //warp data descriptor ('descriptor structure')
119                                 descriptor warp_descriptor;
120                                 if(!text_descriptor.populate(stream))
121                                         throw PSDFileFormatException();
122
123                                 stream.discard_bytes(4*8);      //top, left, right, bottom
124                         }
125
126                         stream.set_position(end_of_chunk);
127                 }
128         }
129         catch(PSDFileFormatException& ex)
130         {
131                 stream.set_position(end_of_layer_info);
132         }
133         
134         return result;
135 }
136
137 void layer::layer_mask::read_mask_data(BEFileInputStream& stream)
138 {
139         unsigned long length = stream.read_long();
140         switch(length)
141         {
142         case 0:
143                 break;
144
145         case 20:
146                 rect_.top = stream.read_long();
147                 rect_.left = stream.read_long();
148                 rect_.bottom = stream.read_long();
149                 rect_.right = stream.read_long();
150
151                 default_value_ = stream.read_byte();
152                 flags_ = stream.read_byte();
153                 stream.discard_bytes(2);
154                 break;
155
156         case 36:
157                 stream.discard_bytes(18);       //we don't care about the user mask if there is a "total user mask"
158                 flags_ = stream.read_byte();
159                 default_value_ = stream.read_byte();
160                 rect_.top = stream.read_long();
161                 rect_.left = stream.read_long();
162                 rect_.bottom = stream.read_long();
163                 rect_.right = stream.read_long();
164                 break;
165
166         default:
167                 stream.discard_bytes(length);
168                 break;
169         };
170 }
171
172 bool layer::is_text() const
173 {
174         return !text_layer_info_.empty();
175 }
176
177 //TODO: implement
178 void layer::read_blending_ranges(BEFileInputStream& stream)
179 {
180         unsigned long length = stream.read_long();
181         stream.discard_bytes(length);
182 }
183
184 channel_ptr layer::get_channel(channel_type type)
185 {
186         auto end = channels_.end();
187         for(auto it = channels_.begin(); it != end; ++it)
188         {
189                 if((*it)->id() == type)
190                 {
191                         return (*it);
192                 }
193         }
194
195         return NULL;
196 }
197
198 void layer::read_channel_data(BEFileInputStream& stream)
199 {
200         image8bit_ptr img;
201         image8bit_ptr mask;
202
203         bool has_transparency(get_channel(psd::Transparency));
204
205         //std::clog << std::endl << "layer: " << std::string(name().begin(), name().end()) << std::endl;
206         
207         if(rect_.width() > 0 && rect_.height() > 0)
208         {
209                 img = std::make_shared<image8bit>(rect_.width(), rect_.height(), std::min<unsigned char>(channels_.size() - masks_, 4));
210                 //std::clog << std::dec << "has image: [width: " << rect_.width() << " height: " << rect_.height() << "]" << std::endl;
211
212                 if(!has_transparency)
213                         std::memset(img->data(), (unsigned long)(255<<24), rect_.width()*rect_.height());
214         }
215
216         if(masks_ > 0 && mask_.rect_.width() > 0 && mask_.rect_.height() > 0)
217         {
218                 mask = std::make_shared<image8bit>(mask_.rect_.width(), mask_.rect_.height(), 1);
219                 //std::clog << std::dec << "has mask: [width: " << mask_rect_.width() << " height: " << mask_rect_.height() << "]" << std::endl;
220         }
221
222         auto end = channels_.end();
223         for(auto it = channels_.begin(); it != end; ++it)
224         {
225                 image8bit_ptr target;
226                 unsigned char offset;
227                 bool discard_channel = false;
228
229                 //determine target bitmap and offset
230                 if((*it)->id() >= 3)
231                         discard_channel = true; //discard channels that doesn't contribute to the final image
232                 else if((*it)->id() >= -1)      //BGRA-data
233                 {
234                         target = img;
235                         offset = ((*it)->id() >= 0) ? 2 - (*it)->id() : 3;
236                 }
237                 else if(mask)   //mask
238                 {
239                         if((*it)->id() == -2 && masks_ == 2)    //if there are two mask-channels, discard the the one that's not the total mask
240                                 discard_channel = true;
241                         else
242                         {
243                                 target = mask;
244                                 offset = 0;
245                         }
246                 }
247
248                 //unsigned long cp = stream.current_position(); //for debug purposes only
249                 //std::clog << std::dec << "channel_id: " << (*it)->id() << ", reading data from: " << std::hex << cp << ", data_length: " << (*it)->data_length() << std::endl;
250
251                 if(!target)
252                         discard_channel = true;
253
254                 if(discard_channel)
255                 {
256                         //std::clog << "        -> discarding" << std::endl;
257                         stream.discard_bytes((*it)->data_length());
258                 }
259                 else
260                 {
261                         //std::clog << "        -> reading...";
262                         unsigned short encoding = stream.read_short();
263                         if(target)
264                         {
265                                 if(encoding == 0)
266                                         read_raw_image_data(stream, *it, target, offset);
267                                 else if(encoding == 1)
268                                         read_rle_image_data(stream, *it, target, offset);
269                                 else
270                                         throw PSDFileFormatException();
271                         }
272                         //std::clog << " " << std::hex << (stream.current_position() - cp) << " bytes read" << std::endl;
273                 }
274         }
275
276         if(img && has_transparency)
277         {
278                 caspar::image::image_view<caspar::image::bgra_pixel> view(img->data(), img->width(), img->height());
279                 caspar::image::premultiply(view);
280         }
281
282         image_ = img;
283         mask_.mask_ = mask;
284 }
285
286 void read_raw_image_data(BEFileInputStream& stream, const channel_ptr& channel, image8bit_ptr target, unsigned char offset)
287 {
288         unsigned long total_length = target->width() * target->height();
289         if(total_length != (channel->data_length() - 2))
290                 throw PSDFileFormatException();
291
292         unsigned char* data = target->data();
293
294         unsigned char stride = target->channel_count();
295         if(stride == 1)
296                 stream.read(reinterpret_cast<char*>(data + offset), total_length);
297         else
298         {
299                 for(unsigned long index=0; index < total_length; ++index)
300                         data[index*stride+offset] = stream.read_byte();
301         }
302 }
303
304 void read_rle_image_data(BEFileInputStream& stream, const channel_ptr& channel, image8bit_ptr target, unsigned char offset)
305 {
306         unsigned long width = target->width();
307         unsigned char stride = target->channel_count();
308         unsigned long height = target->height();
309
310         std::vector<unsigned short> scanline_lengths;
311         scanline_lengths.reserve(height);
312
313         for(unsigned long scanlineIndex=0; scanlineIndex < height; ++scanlineIndex)
314                 scanline_lengths.push_back(stream.read_short());
315
316         unsigned char* data = target->data();
317
318         for(unsigned long scanlineIndex=0; scanlineIndex < height; ++scanlineIndex)
319         {
320                 unsigned long colIndex = 0;
321                 unsigned char length = 0;
322                 do
323                 {
324                         length = 0;
325
326                         //Get controlbyte
327                         char controlByte = static_cast<char>(stream.read_byte());
328                         if(controlByte >= 0)
329                         {
330                                 //Read uncompressed string
331                                 length = controlByte+1;
332                                 for(unsigned long index=0; index < length; ++index)
333                                         data[(scanlineIndex*width+colIndex+index) * stride + offset] = stream.read_byte();
334                         }
335                         else if(controlByte > -128)
336                         {
337                                 //Repeat next byte
338                                 length = -controlByte+1;
339                                 unsigned value = stream.read_byte();
340                                 for(unsigned long index=0; index < length; ++index)
341                                         data[(scanlineIndex*width+colIndex+index) * stride + offset] = value;
342                         }
343
344                         colIndex += length;
345                 }
346                 while(colIndex < width);
347         }
348 }
349
350 }       //namespace psd
351 }       //namespace caspar