2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
4 * This file is part of CasparCG (www.casparcg.com).
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.
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.
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/>.
19 * Author: Niklas P Andersson, niklas.p.andersson@svt.se
24 #include "descriptor.h"
25 #include <common/log.h>
26 #include "util\pdf_reader.h"
29 #include "../image/util/image_algorithms.h"
30 #include "../image/util/image_view.h"
32 #include <boost/property_tree/ptree.hpp>
34 namespace caspar { namespace psd {
36 void layer::layer_mask_info::read_mask_data(BEFileInputStream& stream)
38 unsigned long length = stream.read_long();
45 case 36: //discard total user mask data
46 rect_.location.y = stream.read_long();
47 rect_.location.x = stream.read_long();
48 rect_.size.height = stream.read_long() - rect_.location.y;
49 rect_.size.width = stream.read_long() - rect_.location.x;
51 default_value_ = stream.read_byte();
52 flags_ = stream.read_byte();
53 stream.discard_bytes(2);
57 stream.discard_bytes(18); //discard "total user mask" data
58 //flags_ = stream.read_byte();
59 //default_value_ = stream.read_byte();
60 //rect_.location.y = stream.read_long();
61 //rect_.location.x = stream.read_long();
62 //rect_.size.height = stream.read_long() - rect_.location.y;
63 //rect_.size.width = stream.read_long() - rect_.location.x;
68 //TODO: Log that we discard a mask that is not supported
69 stream.discard_bytes(length);
78 impl() : blend_mode_(InvalidBlendMode), link_group_id_(0), opacity_(255), sheet_color_(0), baseClipping_(false), flags_(0), protection_flags_(0), masks_count_(0), text_scale_(1.0f)
82 std::vector<channel> channels_;
83 blend_mode blend_mode_;
85 unsigned char opacity_;
86 unsigned short sheet_color_;
89 int protection_flags_;
94 rect<long> vector_mask_;
95 layer::layer_mask_info mask_;
97 rect<long> bitmap_rect_;
98 image8bit_ptr bitmap_;
100 boost::property_tree::wptree text_layer_info_;
101 boost::property_tree::wptree timeline_info_;
103 color<unsigned char> solid_color_;
106 void populate(BEFileInputStream& stream, const psd_document& doc)
108 bitmap_rect_.location.y = stream.read_long();
109 bitmap_rect_.location.x = stream.read_long();
110 bitmap_rect_.size.height = stream.read_long() - bitmap_rect_.location.y;
111 bitmap_rect_.size.width = stream.read_long() - bitmap_rect_.location.x;
113 //Get info about the channels in the layer
114 unsigned short channelCount = stream.read_short();
115 for(int channelIndex = 0; channelIndex < channelCount; ++channelIndex)
117 short id = static_cast<short>(stream.read_short());
118 channel c(id, stream.read_long());
123 channels_.push_back(c);
126 unsigned long blendModeSignature = stream.read_long();
127 if(blendModeSignature != '8BIM')
128 throw PSDFileFormatException();
130 blend_mode_ = int_to_blend_mode(stream.read_long());
131 opacity_ = stream.read_byte();
132 baseClipping_ = stream.read_byte() == 1 ? false : true;
133 flags_ = stream.read_byte();
135 stream.discard_bytes(1); //padding
137 unsigned long extras_size = stream.read_long();
138 long position = stream.current_position();
139 mask_.read_mask_data(stream);
140 read_blending_ranges(stream);
141 name_ = stream.read_pascal_string(4);
143 //Aditional Layer Information
144 long end_of_layer_info = position + extras_size;
147 while(stream.current_position() < end_of_layer_info)
149 read_chunk(stream, doc);
152 catch(PSDFileFormatException&)
154 stream.set_position(end_of_layer_info);
158 void read_chunk(BEFileInputStream& stream, const psd_document& doc, bool isMetadata = false)
160 unsigned long signature = stream.read_long();
161 if(signature != '8BIM' && signature != '8B64')
162 throw PSDFileFormatException();
164 unsigned long key = stream.read_long();
166 if(isMetadata) stream.read_long();
168 unsigned long length = stream.read_long();
169 unsigned long end_of_chunk = stream.current_position() + length;
176 read_solid_color(stream);
179 case 'lspf': //protection settings
180 protection_flags_ = stream.read_long();
183 case 'Txt2': //text engine data
187 name_ = stream.read_unicode_string();
190 case 'TySh': //type tool object settings
191 read_text_data(stream);
194 case 'shmd': //metadata
195 read_metadata(stream, doc);
199 sheet_color_ = stream.read_short();
202 case 'lyvr': //layer version
205 case 'lnkD': //linked layer
206 case 'lnk2': //linked layer
207 case 'lnk3': //linked layer
211 read_vector_mask(length, stream, doc.width(), doc.height());
215 read_timeline_data(stream);
222 catch(PSDFileFormatException& ex)
224 //ignore failed chunks silently
225 CASPAR_LOG(warning) << ex.what();
228 stream.set_position(end_of_chunk);
231 void read_solid_color(BEFileInputStream& stream)
233 if(stream.read_long() != 16) //"descriptor version" should be 16
234 throw PSDFileFormatException();
236 descriptor solid_descriptor;
237 if(!solid_descriptor.populate(stream))
238 throw PSDFileFormatException("Failed to read solid color data");
241 solid_color_.red = static_cast<unsigned char>(solid_descriptor.items().get(L"Clr .Rd ", 0.0) + 0.5);
242 solid_color_.green = static_cast<unsigned char>(solid_descriptor.items().get(L"Clr .Grn ", 0.0) + 0.5);
243 solid_color_.blue = static_cast<unsigned char>(solid_descriptor.items().get(L"Clr .Bl ", 0.0) + 0.5);
244 solid_color_.alpha = 255;
248 void read_vector_mask(unsigned long length, BEFileInputStream& stream, long doc_width, long doc_height)
250 typedef std::pair<unsigned long, unsigned long> path_point;
252 unsigned long version = stream.read_long();
253 unsigned long flags = stream.read_long();
254 int path_records = (length-8) / 26;
256 long position = stream.current_position();
258 std::vector<path_point> knots;
259 for(int i=1; i <= path_records; ++i)
261 unsigned short selector = stream.read_short();
262 if(selector == 2) //we only concern ourselves with closed paths
264 unsigned long p_y = stream.read_long();
265 unsigned long p_x = stream.read_long();
266 path_point cp_prev(p_x, p_y);
268 unsigned long a_y = stream.read_long();
269 unsigned long a_x = stream.read_long();
270 path_point anchor(a_x, a_y);
272 unsigned long n_y = stream.read_long();
273 unsigned long n_x = stream.read_long();
274 path_point cp_next(n_x, n_y);
276 if(anchor == cp_prev && anchor == cp_next)
277 knots.push_back(anchor);
279 { //we can't handle smooth curves yet
280 throw PSDFileFormatException();
284 stream.set_position(position + 26*i);
287 if(knots.size() != 4) //we only support rectangular vector masks
288 throw PSDFileFormatException();
290 //we only support rectangular vector masks
291 if(!(knots[0].first == knots[3].first && knots[1].first == knots[2].first && knots[0].second == knots[1].second && knots[2].second == knots[3].second))
292 throw PSDFileFormatException();
294 //the path_points are given in fixed-point 8.24 as a ratio with regards to the width/height of the document. we need to divide by 16777215.0f to get the real ratio.
295 float x_ratio = doc_width / 16777215.0f;
296 float y_ratio = doc_height / 16777215.0f;
297 vector_mask_.location.x = static_cast<long>(knots[0].first * x_ratio +0.5f); //add .5 to get propper rounding when converting to integer
298 vector_mask_.location.y = static_cast<long>(knots[0].second * y_ratio +0.5f); //add .5 to get propper rounding when converting to integer
299 vector_mask_.size.width = static_cast<long>(knots[1].first * x_ratio +0.5f) - vector_mask_.location.x; //add .5 to get propper rounding when converting to integer
300 vector_mask_.size.height = static_cast<long>(knots[2].second * y_ratio +0.5f) - vector_mask_.location.y; //add .5 to get propper rounding when converting to integer
303 void read_metadata(BEFileInputStream& stream, const psd_document& doc)
305 unsigned long count = stream.read_long();
306 for(unsigned long index = 0; index < count; ++index)
307 read_chunk(stream, doc, true);
310 void read_timeline_data(BEFileInputStream& stream)
312 if(stream.read_long() != 16) //"descriptor version" should be 16
313 throw PSDFileFormatException();
315 descriptor timeline_descriptor;
316 if(!timeline_descriptor.populate(stream))
317 throw PSDFileFormatException();
320 timeline_info_.swap(timeline_descriptor.items());
324 void read_text_data(BEFileInputStream& stream)
326 std::wstring text; //the text in the layer
328 stream.read_short(); //should be 1
330 //transformation info
331 double xx = stream.read_double();
332 double xy = stream.read_double();
333 double yx = stream.read_double();
334 double yy = stream.read_double();
335 double tx = stream.read_double();
336 double ty = stream.read_double();
337 if(xx != yy || (xy != 0 && yx != 0))
338 throw PSDFileFormatException("Rotation and non-uniform scaling of dynamic textfields is not supported yet");
340 text_scale_ = static_cast<float>(xx);
342 if(stream.read_short() != 50) //"text version" should be 50
343 throw PSDFileFormatException("invalid text version");
345 if(stream.read_long() != 16) //"descriptor version" should be 16
346 throw PSDFileFormatException("Invalid descriptor version while reading text-data");
348 descriptor text_descriptor;
349 if(!text_descriptor.populate(stream))
350 throw PSDFileFormatException("Failed to read text-info");
353 auto text_info = text_descriptor.items().get_optional<std::wstring>(L"EngineData");
354 if(text_info.is_initialized())
356 std::string str(text_info.get().begin(), text_info.get().end());
357 read_pdf(text_layer_info_, str);
361 if(stream.read_short() != 1) //"warp version" should be 1
362 throw PSDFileFormatException("invalid warp version");
364 if(stream.read_long() != 16) //"descriptor version" should be 16
365 throw PSDFileFormatException("Invalid descriptor version while reading text warp-data");
367 descriptor warp_descriptor;
368 if(!warp_descriptor.populate(stream))
369 throw PSDFileFormatException("Failed to read text warp-data");
372 double w_top = stream.read_double();
373 double w_left = stream.read_double();
374 double w_right = stream.read_double();
375 double w_bottom = stream.read_double();
380 void read_blending_ranges(BEFileInputStream& stream)
382 unsigned long length = stream.read_long();
383 stream.discard_bytes(length);
386 bool has_channel(channel_type type)
388 return std::find_if(channels_.begin(), channels_.end(), [=](const channel& c) { return c.id == type; }) != channels_.end();
391 void read_channel_data(BEFileInputStream& stream)
393 image8bit_ptr bitmap;
396 bool has_transparency = has_channel(psd::transparency);
398 rect<long> clip_rect;
399 if(!bitmap_rect_.empty())
401 clip_rect = bitmap_rect_;
403 if(!vector_mask_.empty())
404 clip_rect = vector_mask_;
406 bitmap = std::make_shared<image8bit>(clip_rect.size.width, clip_rect.size.height, 4);
408 if(!has_transparency)
409 std::memset(bitmap->data(), 255, bitmap->width()*bitmap->height()*bitmap->channel_count());
412 if(masks_count_ > 0 && !mask_.rect_.empty())
414 mask = std::make_shared<image8bit>(mask_.rect_.size.width, mask_.rect_.size.height, 1);
417 for(auto it = channels_.begin(); it != channels_.end(); ++it)
419 psd::rect<long> src_rect;
420 image8bit_ptr target;
421 unsigned char offset;
422 bool discard_channel = false;
424 //determine target bitmap and offset
426 discard_channel = true; //discard channels that doesn't contribute to the final image
427 else if((*it).id >= -1) //BGRA-data
430 offset = ((*it).id >= 0) ? 2 - (*it).id : 3;
431 src_rect = bitmap_rect_;
435 if((*it).id == -3) //discard the "total user mask"
436 discard_channel = true;
441 src_rect = mask_.rect_;
445 if(!target || src_rect.empty())
446 discard_channel = true;
448 unsigned long end_of_data = stream.current_position() + (*it).data_length;
451 unsigned short encoding = stream.read_short();
455 read_raw_image_data(stream, (*it).data_length-2, target, offset);
456 else if(encoding == 1)
457 read_rle_image_data(stream, src_rect, (target == bitmap) ? clip_rect : mask_.rect_, target, offset);
459 throw PSDFileFormatException();
462 stream.set_position(end_of_data);
465 if(bitmap && has_transparency)
467 caspar::image::image_view<caspar::image::bgra_pixel> view(bitmap->data(), bitmap->width(), bitmap->height());
468 caspar::image::premultiply(view);
472 bitmap_rect_ = clip_rect;
473 mask_.bitmap_ = mask;
476 void read_raw_image_data(BEFileInputStream& stream, unsigned long data_length, image8bit_ptr target, unsigned char offset)
478 unsigned long total_length = target->width() * target->height();
479 if(total_length != data_length)
480 throw PSDFileFormatException();
482 unsigned char* data = target->data();
484 unsigned char stride = target->channel_count();
486 stream.read(reinterpret_cast<char*>(data + offset), total_length);
489 for(unsigned long index=0; index < total_length; ++index)
490 data[index*stride+offset] = stream.read_byte();
494 void read_rle_image_data(BEFileInputStream& stream, const rect<long>&src_rect, const rect<long>&clip_rect, image8bit_ptr target, unsigned char offset)
496 unsigned long width = src_rect.size.width;
497 unsigned long height = src_rect.size.height;
498 unsigned char stride = target->channel_count();
500 int offset_x = clip_rect.location.x - src_rect.location.x;
501 int offset_y = clip_rect.location.y - src_rect.location.y;
503 std::vector<unsigned short> scanline_lengths;
504 scanline_lengths.reserve(height);
506 for(unsigned long scanlineIndex=0; scanlineIndex < height; ++scanlineIndex)
507 scanline_lengths.push_back(stream.read_short());
509 unsigned char *target_data = target->data();
511 std::vector<unsigned char> line(width);
513 for(long scanlineIndex=0; scanlineIndex < height; ++scanlineIndex)
515 if(scanlineIndex >= target->height()+offset_y)
518 unsigned long colIndex = 0;
519 unsigned char length = 0;
525 char controlByte = static_cast<char>(stream.read_byte());
528 //Read uncompressed string
529 length = controlByte+1;
530 for(unsigned long index=0; index < length; ++index)
531 line[colIndex+index] = stream.read_byte();
533 else if(controlByte > -128)
536 length = -controlByte+1;
537 unsigned char value = stream.read_byte();
538 for(unsigned long index=0; index < length; ++index)
539 line[colIndex+index] = value;
544 while(colIndex < width);
546 //use line to populate target
547 if(scanlineIndex >= offset_y)
548 for(int index = offset_x; index < target->width(); ++index)
550 target_data[((scanlineIndex-offset_y)*target->width()+index-offset_x) * stride + offset] = line[index];
556 layer::layer() : impl_(spl::make_shared<impl>()) {}
558 void layer::populate(BEFileInputStream& stream, const psd_document& doc) { impl_->populate(stream, doc); }
559 void layer::read_channel_data(BEFileInputStream& stream) { impl_->read_channel_data(stream); }
561 const std::wstring& layer::name() const { return impl_->name_; }
562 unsigned char layer::opacity() const { return impl_->opacity_; }
563 unsigned short layer::sheet_color() const { return impl_->sheet_color_; }
565 bool layer::is_visible() { return (impl_->flags_ & 2) == 0; } //the (PSD file-format) documentation is is saying the opposite but what the heck
566 bool layer::is_position_protected() { return (impl_->protection_flags_& 4) == 4; }
568 float layer::text_scale() const { return impl_->text_scale_; }
569 bool layer::is_text() const { return !impl_->text_layer_info_.empty(); }
570 const boost::property_tree::wptree& layer::text_data() const { return impl_->text_layer_info_; }
572 bool layer::has_timeline() const { return !impl_->timeline_info_.empty(); }
573 const boost::property_tree::wptree& layer::timeline_data() const { return impl_->timeline_info_; }
575 bool layer::is_solid() const { return impl_->solid_color_.alpha != 0; }
576 color<unsigned char> layer::solid_color() const { return impl_->solid_color_; }
578 const point<long>& layer::location() const { return impl_->bitmap_rect_.location; }
579 const image8bit_ptr& layer::bitmap() const { return impl_->bitmap_; }
581 int layer::link_group_id() const { return impl_->link_group_id_; }
582 void layer::set_link_group_id(int id) { impl_->link_group_id_ = id; }