]> git.sesse.net Git - casparcg/blob - modules/psd/layer.cpp
Merge branch '2.1.0' of https://github.com/CasparCG/Server into 2.1.0
[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 <iostream>
25
26 namespace caspar { namespace psd {
27
28 layer_ptr Layer::create(BEFileInputStream& stream)
29 {
30         layer_ptr result(std::make_shared<Layer>());
31         result->rect_.top = stream.read_long();
32         result->rect_.left = stream.read_long();
33         result->rect_.bottom = stream.read_long();
34         result->rect_.right = stream.read_long();
35
36         //Get info about the channels in the layer
37         unsigned short channelCount = stream.read_short();
38         for(int channelIndex = 0; channelIndex < channelCount; ++channelIndex)
39         {
40                 short channel_id = static_cast<short>(stream.read_short());
41                 unsigned long data_length = stream.read_long();
42
43                 if(channel_id <= -2)
44                         result->masks_++;
45
46                 channel_ptr channel(std::make_shared<Channel>(channel_id, data_length));
47                 result->channels_.push_back(channel);
48         }
49
50         unsigned long blendModeSignature = stream.read_long();
51         if(blendModeSignature != '8BIM')
52                 throw PSDFileFormatException();
53
54         unsigned long blendModeKey = stream.read_long();
55         result->blendMode_ = IntToBlendMode(blendModeKey);
56
57         result->opacity_ = stream.read_byte();
58         result->baseClipping_ = stream.read_byte() == 1 ? false : true;
59         result->flags_ = stream.read_byte();
60
61         stream.discard_bytes(1);
62
63         unsigned long extraDataSize = stream.read_long();
64         long position1 = stream.current_position();
65         result->read_mask_data(stream);
66         result->ReadBlendingRanges(stream);
67
68         result->name_ = stream.read_pascal_string(4);
69
70         //Aditional Layer Information
71         unsigned long end_of_layer_info = position1 + extraDataSize;
72         
73         try
74         {
75                 while(stream.current_position() < end_of_layer_info)
76                 {
77                         unsigned long signature = stream.read_long();
78                         if(signature != '8BIM' && signature != '8B64')
79                                 throw PSDFileFormatException();
80
81                         unsigned long key = stream.read_long();
82                         unsigned long length = stream.read_long();
83                         unsigned long end_of_chunk = stream.current_position() + length;
84
85                         if(key == 'TySh')       //type tool object settings
86                         {
87                                 std::wstring text;      //the text in the layer
88
89                                 stream.read_short();    //should be 1
90                                 stream.discard_bytes(6*8);      //just throw transformation info for now
91                                 stream.read_short();    //"text version" should be 50
92                                 stream.read_long();             //"descriptor version" should be 16
93
94                                 //text data descriptor ('descriptor structure')
95                                 descriptor text_descriptor;
96                                 if(!text_descriptor.populate(stream))
97                                         throw PSDFileFormatException();
98
99                                 stream.read_short();    //"warp version" should be 1
100                                 stream.read_long();             //"descriptor version" should be 16
101
102                                 //warp data descriptor ('descriptor structure')
103                                 descriptor warp_descriptor;
104                                 if(!text_descriptor.populate(stream))
105                                         throw PSDFileFormatException();
106
107                                 stream.discard_bytes(4*8);      //top, left, right, bottom
108                         }
109
110                         stream.set_position(end_of_chunk);
111                 }
112         }
113         catch(PSDFileFormatException& ex)
114         {
115                 stream.set_position(end_of_layer_info);
116         }
117         
118         return result;
119 }
120
121 void Layer::read_mask_data(BEFileInputStream& stream)
122 {
123         unsigned long length = stream.read_long();
124         if(length > 0)
125         {
126                 mask_rect_.top = stream.read_long();
127                 mask_rect_.left = stream.read_long();
128                 mask_rect_.bottom = stream.read_long();
129                 mask_rect_.right = stream.read_long();
130
131                 default_mask_value_ = stream.read_byte();
132                 mask_flags_ = stream.read_byte();
133
134                 if(length == 20)
135                         stream.discard_bytes(2);
136                 else
137                 {
138                         //Override user mask with total user mask
139                         mask_flags_ = stream.read_byte();
140                         default_mask_value_ = stream.read_byte();
141                         mask_rect_.top = stream.read_long();
142                         mask_rect_.left = stream.read_long();
143                         mask_rect_.bottom = stream.read_long();
144                         mask_rect_.right = stream.read_long();
145                 }
146         }
147 }
148
149 //TODO: implement
150 void Layer::ReadBlendingRanges(BEFileInputStream& stream)
151 {
152         unsigned long length = stream.read_long();
153         stream.discard_bytes(length);
154 }
155
156 channel_ptr Layer::get_channel(ChannelType type)
157 {
158         auto end = channels_.end();
159         for(auto it = channels_.begin(); it != end; ++it)
160         {
161                 if((*it)->id() == type)
162                 {
163                         return (*it);
164                 }
165         }
166
167         return NULL;
168 }
169
170 void Layer::read_channel_data(BEFileInputStream& stream)
171 {
172         image8bit_ptr img;
173         image8bit_ptr mask;
174         //std::clog << std::endl << "layer: " << std::string(name().begin(), name().end()) << std::endl;
175         
176         if(rect_.width() > 0 && rect_.height() > 0)
177         {
178                 img = std::make_shared<image8bit>(rect_.width(), rect_.height(), std::min<unsigned char>(channels_.size() - masks_, 4));
179                 //std::clog << std::dec << "has image: [width: " << rect_.width() << " height: " << rect_.height() << "]" << std::endl;
180
181                 if(!get_channel(psd::Transparency))
182                         std::memset(img->data(), (unsigned long)(255<<24), rect_.width()*rect_.height());
183         }
184
185         if(masks_ > 0 && mask_rect_.width() > 0 && mask_rect_.height() > 0)
186         {
187                 mask = std::make_shared<image8bit>(mask_rect_.width(), mask_rect_.height(), 1);
188                 //std::clog << std::dec << "has mask: [width: " << mask_rect_.width() << " height: " << mask_rect_.height() << "]" << std::endl;
189         }
190
191         auto end = channels_.end();
192         for(auto it = channels_.begin(); it != end; ++it)
193         {
194                 image8bit_ptr target;
195                 unsigned char offset;
196                 bool discard_channel = false;
197
198                 //determine target bitmap and offset
199                 if((*it)->id() >= 3)
200                         discard_channel = true; //discard channels that doesn't contribute to the final image
201                 else if((*it)->id() >= -1)      //RGBA-data
202                 {
203                         target = img;
204                         offset = ((*it)->id() >= 0) ? 2 - (*it)->id() : 3;
205                 }
206                 else if(mask)   //mask
207                 {
208                         if((*it)->id() == -2 && masks_ == 2)    //if there are two mask-channels, discard the the one that's not the total mask for now
209                                 discard_channel = true;
210                         else
211                         {
212                                 target = mask;
213                                 offset = 0;
214                         }
215                 }
216
217                 unsigned long cp = stream.current_position();   //TODO: remove, for debug purposes only
218                 //std::clog << std::dec << "channel_id: " << (*it)->id() << ", reading data from: " << std::hex << cp << ", data_length: " << (*it)->data_length() << std::endl;
219
220                 if(!target)
221                         discard_channel = true;
222
223                 if(discard_channel)
224                 {
225                         //std::clog << "        -> discarding" << std::endl;
226                         stream.discard_bytes((*it)->data_length());
227                 }
228                 else
229                 {
230                         //std::clog << "        -> reading...";
231                         unsigned short encoding = stream.read_short();
232                         if(target)
233                         {
234                                 if(encoding == 0)
235                                         read_raw_image_data(stream, *it, target, offset);
236                                 else if(encoding == 1)
237                                         read_rle_image_data(stream, *it, target, offset);
238                                 else
239                                         throw PSDFileFormatException();
240                         }
241                         //std::clog << " " << std::hex << (stream.current_position() - cp) << " bytes read" << std::endl;
242                 }
243         }
244
245         image_ = img;
246         mask_ = mask;
247 }
248
249 void Layer::read_raw_image_data(BEFileInputStream& stream, const channel_ptr& channel, image8bit_ptr target, unsigned char offset)
250 {
251         unsigned long total_length = target->width() * target->height();
252         if(total_length != (channel->data_length() - 2))
253                 throw PSDFileFormatException();
254
255         unsigned char* data = target->data();
256
257         unsigned char stride = target->channel_count();
258         if(stride == 1)
259                 stream.read(reinterpret_cast<char*>(data + offset), total_length);
260         else
261         {
262                 for(unsigned long index=0; index < total_length; ++index)
263                         data[index*stride+offset] = stream.read_byte();
264         }
265 }
266
267 void Layer::read_rle_image_data(BEFileInputStream& stream, const channel_ptr& channel, image8bit_ptr target, unsigned char offset)
268 {
269         unsigned long width = target->width();
270         unsigned char stride = target->channel_count();
271         unsigned long height = target->height();
272
273         std::vector<unsigned short> scanline_lengths;
274         scanline_lengths.reserve(height);
275
276         for(unsigned long scanlineIndex=0; scanlineIndex < height; ++scanlineIndex)
277                 scanline_lengths.push_back(stream.read_short());
278
279         unsigned char* data = target->data();
280
281         for(unsigned long scanlineIndex=0; scanlineIndex < height; ++scanlineIndex)
282         {
283                 unsigned long colIndex = 0;
284                 unsigned char length = 0;
285                 do
286                 {
287                         length = 0;
288
289                         //Get controlbyte
290                         char controlByte = static_cast<char>(stream.read_byte());
291                         if(controlByte >= 0)
292                         {
293                                 //Read uncompressed string
294                                 length = controlByte+1;
295                                 for(unsigned long index=0; index < length; ++index)
296                                         data[(scanlineIndex*width+colIndex+index) * stride + offset] = stream.read_byte();
297                         }
298                         else if(controlByte > -128)
299                         {
300                                 //Repeat next byte
301                                 length = -controlByte+1;
302                                 unsigned value = stream.read_byte();
303                                 for(unsigned long index=0; index < length; ++index)
304                                         data[(scanlineIndex*width+colIndex+index) * stride + offset] = value;
305                         }
306
307                         colIndex += length;
308                 }
309                 while(colIndex < width);
310         }
311 }
312
313 //
314 //image_ptr Layer::read_image(BEFileInputStream& stream)
315 //{
316 //      if(image == NULL)
317 //      {
318 //              unsigned char channels = (channels_.size() > 3) ? 4 : 3;
319 //
320 //              image = std::make_shared<Image>(static_cast<unsigned short>(rect_.width()), static_cast<unsigned short>(rect_.height()),  channels);
321 //
322 //              channel_ptr pChannel = get_channel(ColorRed);
323 //              if(pChannel != NULL)
324 //                      pChannel->GetChannelImageData(stream, image, 0);
325 //
326 //              pChannel = get_channel(ColorGreen);
327 //              if(pChannel != NULL)
328 //                      pChannel->GetChannelImageData(stream, image, 1);
329 //
330 //              pChannel = get_channel(ColorBlue);
331 //              if(pChannel != NULL)
332 //                      pChannel->GetChannelImageData(stream, image, 2);
333 //
334 //              pChannel = get_channel(Transparency);
335 //              if(channels == 4 && pChannel != NULL)
336 //                      pChannel->GetChannelImageData(stream, image, 3);
337 //      }
338 //
339 //      return image;
340 //}
341
342 }       //namespace psd
343 }       //namespace caspar