#include "layer.h"
#include "descriptor.h"
-#include <iostream>
+#include "util\pdf_reader.h"
+
+typedef unsigned char uint8_t;
+#include <algorithm>
+#include "../image/util/image_algorithms.h"
+#include "../image/util/image_view.h"
namespace caspar { namespace psd {
-layer_ptr Layer::create(BEFileInputStream& stream)
+void read_raw_image_data(BEFileInputStream& stream, const channel_ptr& channel, image8bit_ptr target, unsigned char offset);
+void read_rle_image_data(BEFileInputStream& stream, const channel_ptr& channel, image8bit_ptr target, unsigned char offset);
+
+layer_ptr layer::create(BEFileInputStream& stream)
{
- layer_ptr result(std::make_shared<Layer>());
- result->rect_.top = stream.read_long();
- result->rect_.left = stream.read_long();
- result->rect_.bottom = stream.read_long();
- result->rect_.right = stream.read_long();
+ layer_ptr result(std::make_shared<layer>());
+ result->populate(stream);
+ return result;
+}
+
+void layer::populate(BEFileInputStream& stream)
+{
+ rect_.top = stream.read_long();
+ rect_.left = stream.read_long();
+ rect_.bottom = stream.read_long();
+ rect_.right = stream.read_long();
//Get info about the channels in the layer
unsigned short channelCount = stream.read_short();
unsigned long data_length = stream.read_long();
if(channel_id <= -2)
- result->masks_++;
+ masks_++;
channel_ptr channel(std::make_shared<Channel>(channel_id, data_length));
- result->channels_.push_back(channel);
+ channels_.push_back(channel);
}
unsigned long blendModeSignature = stream.read_long();
throw PSDFileFormatException();
unsigned long blendModeKey = stream.read_long();
- result->blendMode_ = IntToBlendMode(blendModeKey);
+ blend_mode_ = int_to_blend_mode(blendModeKey);
- result->opacity_ = stream.read_byte();
- result->baseClipping_ = stream.read_byte() == 1 ? false : true;
- result->flags_ = stream.read_byte();
+ opacity_ = stream.read_byte();
+ baseClipping_ = stream.read_byte() == 1 ? false : true;
+ flags_ = stream.read_byte();
stream.discard_bytes(1);
unsigned long extraDataSize = stream.read_long();
long position1 = stream.current_position();
- result->read_mask_data(stream);
- result->ReadBlendingRanges(stream);
+ mask_.read_mask_data(stream);
+ read_blending_ranges(stream);
- result->name_ = stream.read_pascal_string(4);
+ name_ = stream.read_pascal_string(4);
//Aditional Layer Information
unsigned long end_of_layer_info = position1 + extraDataSize;
unsigned long length = stream.read_long();
unsigned long end_of_chunk = stream.current_position() + length;
- if(key == 'TySh') //type tool object settings
+ if(key == 'lspf')
+ {
+ protection_flags_ = stream.read_long();
+ }
+ else if(key == 'TySh') //type tool object settings
{
std::wstring text; //the text in the layer
descriptor text_descriptor;
if(!text_descriptor.populate(stream))
throw PSDFileFormatException();
+ else
+ {
+ if(text_descriptor.has_item(L"EngineData"))
+ {
+ const descriptor_item& text_data = text_descriptor.get_item(L"EngineData");
+ read_pdf(text_layer_info_, text_data.rawdata_data);
+ }
+ }
stream.read_short(); //"warp version" should be 1
stream.read_long(); //"descriptor version" should be 16
{
stream.set_position(end_of_layer_info);
}
-
- return result;
}
-void Layer::read_mask_data(BEFileInputStream& stream)
+void layer::layer_mask::read_mask_data(BEFileInputStream& stream)
{
unsigned long length = stream.read_long();
- if(length > 0)
+ switch(length)
{
- mask_rect_.top = stream.read_long();
- mask_rect_.left = stream.read_long();
- mask_rect_.bottom = stream.read_long();
- mask_rect_.right = stream.read_long();
-
- default_mask_value_ = stream.read_byte();
- mask_flags_ = stream.read_byte();
+ case 0:
+ break;
+
+ case 20:
+ rect_.top = stream.read_long();
+ rect_.left = stream.read_long();
+ rect_.bottom = stream.read_long();
+ rect_.right = stream.read_long();
+
+ default_value_ = stream.read_byte();
+ flags_ = stream.read_byte();
+ stream.discard_bytes(2);
+ break;
+
+ case 36:
+ stream.discard_bytes(18); //we don't care about the user mask if there is a "total user mask"
+ flags_ = stream.read_byte();
+ default_value_ = stream.read_byte();
+ rect_.top = stream.read_long();
+ rect_.left = stream.read_long();
+ rect_.bottom = stream.read_long();
+ rect_.right = stream.read_long();
+ break;
+
+ default:
+ stream.discard_bytes(length);
+ break;
+ };
+}
- if(length == 20)
- stream.discard_bytes(2);
- else
- {
- //Override user mask with total user mask
- mask_flags_ = stream.read_byte();
- default_mask_value_ = stream.read_byte();
- mask_rect_.top = stream.read_long();
- mask_rect_.left = stream.read_long();
- mask_rect_.bottom = stream.read_long();
- mask_rect_.right = stream.read_long();
- }
- }
+bool layer::is_text() const
+{
+ return !text_layer_info_.empty();
}
//TODO: implement
-void Layer::ReadBlendingRanges(BEFileInputStream& stream)
+void layer::read_blending_ranges(BEFileInputStream& stream)
{
unsigned long length = stream.read_long();
stream.discard_bytes(length);
}
-channel_ptr Layer::get_channel(ChannelType type)
+channel_ptr layer::get_channel(channel_type type)
{
auto end = channels_.end();
for(auto it = channels_.begin(); it != end; ++it)
return NULL;
}
-void Layer::read_channel_data(BEFileInputStream& stream)
+void layer::read_channel_data(BEFileInputStream& stream)
{
image8bit_ptr img;
image8bit_ptr mask;
- std::clog << std::endl << "layer: " << std::string(name().begin(), name().end()) << std::endl;
+
+ bool has_transparency(get_channel(psd::Transparency));
+
+ //std::clog << std::endl << "layer: " << std::string(name().begin(), name().end()) << std::endl;
if(rect_.width() > 0 && rect_.height() > 0)
{
- img = std::make_shared<image8bit>(rect_.width(), rect_.height(), std::min<unsigned char>(channels_.size() - masks_, 4));
- std::clog << std::dec << "has image: [width: " << rect_.width() << " height: " << rect_.height() << "]" << std::endl;
+ img = std::make_shared<image8bit>(rect_.width(), rect_.height(), 4);
+ //std::clog << std::dec << "has image: [width: " << rect_.width() << " height: " << rect_.height() << "]" << std::endl;
+
+ if(!has_transparency)
+ std::memset(img->data(), 255, img->width()*img->height()*img->channel_count());
}
- if(masks_ > 0 && mask_rect_.width() > 0 && mask_rect_.height() > 0)
+ if(masks_ > 0 && mask_.rect_.width() > 0 && mask_.rect_.height() > 0)
{
- mask = std::make_shared<image8bit>(mask_rect_.width(), mask_rect_.height(), 1);
- std::clog << std::dec << "has mask: [width: " << mask_rect_.width() << " height: " << mask_rect_.height() << "]" << std::endl;
+ mask = std::make_shared<image8bit>(mask_.rect_.width(), mask_.rect_.height(), 1);
+ //std::clog << std::dec << "has mask: [width: " << mask_rect_.width() << " height: " << mask_rect_.height() << "]" << std::endl;
}
auto end = channels_.end();
//determine target bitmap and offset
if((*it)->id() >= 3)
discard_channel = true; //discard channels that doesn't contribute to the final image
- else if((*it)->id() >= -1) //RGBA-data
+ else if((*it)->id() >= -1) //BGRA-data
{
target = img;
- offset = ((*it)->id() >= 0) ? (*it)->id() : 3;
+ offset = ((*it)->id() >= 0) ? 2 - (*it)->id() : 3;
}
else if(mask) //mask
{
- if((*it)->id() == -2 && masks_ == 2) //if there are two mask-channels, discard the the one that's not the total mask for now
+ if((*it)->id() == -2 && masks_ == 2) //if there are two mask-channels, discard the the one that's not the total mask
discard_channel = true;
else
{
}
}
- unsigned long cp = stream.current_position(); //TODO: remove, for debug purposes only
- std::clog << std::dec << "channel_id: " << (*it)->id() << ", reading data from: " << std::hex << cp << ", data_length: " << (*it)->data_length() << std::endl;
+ //unsigned long cp = stream.current_position(); //for debug purposes only
+ //std::clog << std::dec << "channel_id: " << (*it)->id() << ", reading data from: " << std::hex << cp << ", data_length: " << (*it)->data_length() << std::endl;
if(!target)
discard_channel = true;
if(discard_channel)
{
- std::clog << " -> discarding" << std::endl;
+ //std::clog << " -> discarding" << std::endl;
stream.discard_bytes((*it)->data_length());
}
else
{
- std::clog << " -> reading...";
+ //std::clog << " -> reading...";
unsigned short encoding = stream.read_short();
if(target)
{
else
throw PSDFileFormatException();
}
- std::clog << " " << std::hex << (stream.current_position() - cp) << " bytes read" << std::endl;
+ //std::clog << " " << std::hex << (stream.current_position() - cp) << " bytes read" << std::endl;
}
}
+ if(img && has_transparency)
+ {
+ caspar::image::image_view<caspar::image::bgra_pixel> view(img->data(), img->width(), img->height());
+ caspar::image::premultiply(view);
+ }
+
image_ = img;
- mask_ = mask;
+ mask_.mask_ = mask;
}
-void Layer::read_raw_image_data(BEFileInputStream& stream, const channel_ptr& channel, image8bit_ptr target, unsigned char offset)
+void read_raw_image_data(BEFileInputStream& stream, const channel_ptr& channel, image8bit_ptr target, unsigned char offset)
{
unsigned long total_length = target->width() * target->height();
if(total_length != (channel->data_length() - 2))
}
}
-void Layer::read_rle_image_data(BEFileInputStream& stream, const channel_ptr& channel, image8bit_ptr target, unsigned char offset)
+void read_rle_image_data(BEFileInputStream& stream, const channel_ptr& channel, image8bit_ptr target, unsigned char offset)
{
unsigned long width = target->width();
unsigned char stride = target->channel_count();
}
}
-//
-//image_ptr Layer::read_image(BEFileInputStream& stream)
-//{
-// if(image == NULL)
-// {
-// unsigned char channels = (channels_.size() > 3) ? 4 : 3;
-//
-// image = std::make_shared<Image>(static_cast<unsigned short>(rect_.width()), static_cast<unsigned short>(rect_.height()), channels);
-//
-// channel_ptr pChannel = get_channel(ColorRed);
-// if(pChannel != NULL)
-// pChannel->GetChannelImageData(stream, image, 0);
-//
-// pChannel = get_channel(ColorGreen);
-// if(pChannel != NULL)
-// pChannel->GetChannelImageData(stream, image, 1);
-//
-// pChannel = get_channel(ColorBlue);
-// if(pChannel != NULL)
-// pChannel->GetChannelImageData(stream, image, 2);
-//
-// pChannel = get_channel(Transparency);
-// if(channels == 4 && pChannel != NULL)
-// pChannel->GetChannelImageData(stream, image, 3);
-// }
-//
-// return image;
-//}
-
} //namespace psd
} //namespace caspar
\ No newline at end of file