EndProject\r
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "screen", "modules\screen\screen.vcxproj", "{88F974F0-D09F-4788-8CF8-F563209E60C1}"\r
EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "psd", "modules\psd\psd.vcxproj", "{866A164B-6F7A-450E-8452-C6AE4E176436}"\r
+EndProject\r
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{BCB4FCF8-987F-40D8-87B5-8F7CE1D5D212}"\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "psd-test", "test\psd-test\psd-test.vcxproj", "{156C91E0-8CAC-4DBA-A212-AAFDAFACD8BC}"\r
+EndProject\r
Global\r
+ GlobalSection(SubversionScc) = preSolution\r
+ Svn-Managed = True\r
+ Manager = AnkhSVN - Subversion Support for Visual Studio\r
+ EndGlobalSection\r
GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
Debug|Mixed Platforms = Debug|Mixed Platforms\r
Debug|Win32 = Debug|Win32\r
{88F974F0-D09F-4788-8CF8-F563209E60C1}.Release|Win32.ActiveCfg = Release|x64\r
{88F974F0-D09F-4788-8CF8-F563209E60C1}.Release|x64.ActiveCfg = Release|x64\r
{88F974F0-D09F-4788-8CF8-F563209E60C1}.Release|x64.Build.0 = Release|x64\r
+ {866A164B-6F7A-450E-8452-C6AE4E176436}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32\r
+ {866A164B-6F7A-450E-8452-C6AE4E176436}.Debug|Mixed Platforms.Build.0 = Debug|Win32\r
+ {866A164B-6F7A-450E-8452-C6AE4E176436}.Debug|Win32.ActiveCfg = Debug|Win32\r
+ {866A164B-6F7A-450E-8452-C6AE4E176436}.Debug|Win32.Build.0 = Debug|Win32\r
+ {866A164B-6F7A-450E-8452-C6AE4E176436}.Debug|x64.ActiveCfg = Debug|Win32\r
+ {866A164B-6F7A-450E-8452-C6AE4E176436}.Release|Mixed Platforms.ActiveCfg = Release|Win32\r
+ {866A164B-6F7A-450E-8452-C6AE4E176436}.Release|Mixed Platforms.Build.0 = Release|Win32\r
+ {866A164B-6F7A-450E-8452-C6AE4E176436}.Release|Win32.ActiveCfg = Release|Win32\r
+ {866A164B-6F7A-450E-8452-C6AE4E176436}.Release|Win32.Build.0 = Release|Win32\r
+ {866A164B-6F7A-450E-8452-C6AE4E176436}.Release|x64.ActiveCfg = Release|Win32\r
+ {156C91E0-8CAC-4DBA-A212-AAFDAFACD8BC}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32\r
+ {156C91E0-8CAC-4DBA-A212-AAFDAFACD8BC}.Debug|Mixed Platforms.Build.0 = Debug|Win32\r
+ {156C91E0-8CAC-4DBA-A212-AAFDAFACD8BC}.Debug|Win32.ActiveCfg = Debug|Win32\r
+ {156C91E0-8CAC-4DBA-A212-AAFDAFACD8BC}.Debug|Win32.Build.0 = Debug|Win32\r
+ {156C91E0-8CAC-4DBA-A212-AAFDAFACD8BC}.Debug|x64.ActiveCfg = Debug|Win32\r
+ {156C91E0-8CAC-4DBA-A212-AAFDAFACD8BC}.Release|Mixed Platforms.ActiveCfg = Release|Win32\r
+ {156C91E0-8CAC-4DBA-A212-AAFDAFACD8BC}.Release|Mixed Platforms.Build.0 = Release|Win32\r
+ {156C91E0-8CAC-4DBA-A212-AAFDAFACD8BC}.Release|Win32.ActiveCfg = Release|Win32\r
+ {156C91E0-8CAC-4DBA-A212-AAFDAFACD8BC}.Release|Win32.Build.0 = Release|Win32\r
+ {156C91E0-8CAC-4DBA-A212-AAFDAFACD8BC}.Release|x64.ActiveCfg = Release|Win32\r
EndGlobalSection\r
GlobalSection(SolutionProperties) = preSolution\r
HideSolutionNode = FALSE\r
{3E11FF65-A9DA-4F80-87F2-A7C6379ED5E2} = {C54DA43E-4878-45DB-B76D-35970553672C}\r
{7D58BD57-FDD5-46E6-A23B-ED14B5314A0E} = {C54DA43E-4878-45DB-B76D-35970553672C}\r
{88F974F0-D09F-4788-8CF8-F563209E60C1} = {C54DA43E-4878-45DB-B76D-35970553672C}\r
- EndGlobalSection\r
- GlobalSection(SubversionScc) = preSolution\r
- Svn-Managed = True\r
- Manager = AnkhSVN - Subversion Support for Visual Studio\r
+ {866A164B-6F7A-450E-8452-C6AE4E176436} = {C54DA43E-4878-45DB-B76D-35970553672C}\r
+ {156C91E0-8CAC-4DBA-A212-AAFDAFACD8BC} = {BCB4FCF8-987F-40D8-87B5-8F7CE1D5D212}\r
EndGlobalSection\r
EndGlobal\r
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Niklas P Andersson, niklas.p.andersson@svt.se
+*/
+
+#ifndef _PSDCHANNEL_H__
+#define _PSDCHANNEL_H__
+
+#pragma once
+
+#include "util\bigendian_file_input_stream.h"
+#include <memory>
+
+namespace caspar { namespace psd {
+
+class Channel
+{
+public:
+ Channel(short id, unsigned long len) : id_(id), data_length_(len)
+ {}
+
+ short id() const
+ {
+ return id_;
+ }
+ unsigned long data_length() const
+ {
+ return data_length_;
+ }
+
+private:
+ unsigned long data_length_;
+ short id_;
+};
+
+typedef std::shared_ptr<Channel> channel_ptr;
+
+} //namespace psd
+} //namespace caspar
+
+#endif //_PSDCHANNEL_H__
\ No newline at end of file
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Niklas P Andersson, niklas.p.andersson@svt.se
+*/
+
+#include "descriptor.h"
+#include "misc.h"
+
+namespace caspar { namespace psd {
+
+bool descriptor::populate(BEFileInputStream& stream)
+{
+ bool result = true;
+
+ try
+ {
+ stream.read_unicode_string();
+ stream.read_id_string();
+ unsigned long element_count = stream.read_long();
+ for(int element_index = 0; element_index < element_count; ++element_index)
+ {
+ descriptor_item item;
+
+ std::wstring key = stream.read_id_string();
+ item.type = stream.read_long();
+
+ switch(item.type)
+ {
+ case 'obj ': break;
+ case 'Objc': break;
+ case 'VlLs': break;
+ case 'doub': break;
+ case 'UntF': break;
+
+ case 'TEXT':
+ {
+ item.text_text = stream.read_unicode_string();
+ }
+ break;
+ case 'enum':
+ {
+ item.enum_key = stream.read_id_string();
+ item.enum_val = stream.read_id_string();
+ }
+ break;
+
+ case 'long':
+ {
+ item.long_value = stream.read_long();
+ }
+ break;
+
+ case 'bool': break;
+ case 'GlbO': break;
+ case 'type':
+ case 'GlbC':
+ break;
+ case 'alis': break;
+
+ case 'tdta':
+ {
+ unsigned long rawdata_length = stream.read_long();
+ item.rawdata_data.resize(rawdata_length);
+ stream.read(item.rawdata_data.data(), rawdata_length);
+ }
+ break;
+
+ default:
+ //descriptor type not supported yet
+ throw PSDFileFormatException();
+ }
+
+ items_.insert(std::pair<std::wstring, descriptor_item>(key, item));
+ }
+ }
+ catch(std::exception& ex)
+ {
+ result = false;
+ }
+
+ return result;
+}
+
+} //namespace psd
+} //namespace caspar
\ No newline at end of file
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Niklas P Andersson, niklas.p.andersson@svt.se
+*/
+
+#pragma once
+
+#include <vector>
+#include <map>
+#include <string>
+#include <memory>
+#include "util\bigendian_file_input_stream.h"
+
+namespace caspar { namespace psd {
+
+ struct descriptor_item
+ {
+ unsigned long type;
+
+ std::wstring enum_key;
+ std::wstring enum_val;
+
+ std::wstring text_text;
+
+ unsigned long long_value;
+
+ std::vector<char> rawdata_data;
+ };
+
+class descriptor
+{
+ typedef std::map<std::wstring, descriptor_item> items_map;
+
+public:
+ bool populate(BEFileInputStream& stream);
+
+private:
+ items_map items_;
+};
+
+} //namespace psd
+} //namespace caspar
\ No newline at end of file
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Niklas P Andersson, niklas.p.andersson@svt.se
+*/
+
+#include "doc.h"
+#include <iostream>
+
+namespace caspar { namespace psd {
+
+Document::Document() : channels_(0), width_(0), height_(0), depth_(0), color_mode_(InvalidColorMode)
+{
+}
+
+
+bool Document::parse(const std::wstring& filename)
+{
+ bool result = true;
+
+ try
+ {
+ filename_ = filename;
+ input_.Open(filename_);
+ read_header();
+ read_color_mode();
+ read_image_resources();
+ read_layers();
+ }
+ catch(std::exception& ex)
+ {
+ std::clog << "ooops!" << std::endl;
+ result = false;
+ }
+
+ return result;
+}
+
+void Document::read_header()
+{
+ unsigned long signature = input_.read_long();
+ unsigned short version = input_.read_short();
+ if(!(signature == '8BPS' && version == 1))
+ throw PSDFileFormatException();
+
+ input_.discard_bytes(6);
+ channels_= input_.read_short();
+ height_ = input_.read_long();
+ width_ = input_.read_long();
+ depth_ = input_.read_short(); //bits / channel
+
+ color_mode_ = int_to_color_mode(input_.read_short());
+}
+
+void Document::read_color_mode()
+{
+ unsigned long length = input_.read_long();
+ input_.discard_bytes(length);
+}
+
+void Document::read_image_resources()
+{
+ unsigned long section_length = input_.read_long();
+
+ if(section_length > 0)
+ {
+ unsigned long end_of_section = input_.current_position() + section_length;
+
+ try
+ {
+ while(input_.current_position() < end_of_section)
+ {
+ unsigned long signature = input_.read_long();
+ if(signature != '8BIM')
+ throw PSDFileFormatException();
+
+ unsigned short resource_id = input_.read_short();
+
+ std::wstring name = input_.read_pascal_string(2);
+
+ unsigned long resource_length = input_.read_long();
+
+ //TODO: read actual data
+ switch(resource_id)
+ {
+ case 1005:
+ {
+ ////resolutionInfo
+ //struct ResolutionInfo
+ //{
+ //Fixed hRes;
+ //int16 hResUnit;
+ //int16 widthUnit;
+ //Fixed vRes;
+ //int16 vResUnit;
+ //int16 heightUnit;
+ //};
+ }
+ break;
+
+ case 1006:
+ {
+ //names of alpha channels
+ }
+ break;
+
+ case 1008:
+ {} break; //caption
+
+ case 1010:
+ {} break; //background color
+
+ case 1024:
+ {} break; //layer state info (2 bytes containing the index of target layer (0 = bottom layer))
+
+ case 1026:
+ {} break; //layer group information
+
+ case 1028:
+ {} break; //IPTC-NAA. File Info...
+ case 1029:
+ {} break; //image for raw format files
+ case 1036:
+ break; //thumbnail resource
+ case 1045: //unicode Alpha names (Unicode string (4 bytes length followed by string))
+ break;
+ case 1053:
+ break; //alpha identifiers (4 bytes of length, followed by 4 bytes each for every alpha identifier.)
+ case 1060:
+ break; //XMP metadata
+ case 1065:
+ break; //layer comps
+ case 1069:
+ break; //layer selection ID(s)
+ case 1072: //layer group(s) enabled id
+ break;
+ case 1075: //timeline information
+ break;
+ case 1077: //DisplayInfo
+ break;
+ case 2999: //name of clipping path
+ break;
+
+ default:
+ {
+ if(resource_id >= 2000 && resource_id <=2997) //path information
+ {
+ }
+ else if(resource_id >= 4000 && resource_id <= 4999) //plug-in resources
+ {
+ }
+ }
+ break;
+ }
+
+ input_.discard_bytes(resource_length);
+ }
+ }
+ catch(PSDFileFormatException& ex)
+ {
+ //if an error occurs, just skip this section
+ input_.set_position(end_of_section);
+ }
+ }
+}
+
+
+void Document::read_layers()
+{
+ //"Layer And Mask information"
+ unsigned long total_length = input_.read_long(); //length of "Layer and Mask information"
+ unsigned long end_of_layers = input_.current_position() + total_length;
+
+ try
+ {
+ //"Layer info section"
+ {
+ unsigned long layer_info_length = input_.read_long(); //length of "Layer info" section
+ unsigned long end_of_layers_info = input_.current_position() + layer_info_length;
+
+ short layers_count = abs(static_cast<short>(input_.read_short()));
+ std::clog << "Expecting " << layers_count << " layers" << std::endl;
+
+ for(unsigned short layerIndex = 0; layerIndex < layers_count; ++layerIndex)
+ {
+ layers_.push_back(Layer::create(input_)); //each layer reads it's "layer record"
+ std::clog << "Added layer: " << std::string(layers_[layerIndex]->name().begin(), layers_[layerIndex]->name().end()) << std::endl;
+ }
+
+ unsigned long channel_data_start = input_.current_position(); //TODO: remove. For debug purposes only
+
+ auto end = layers_.end();
+ for(auto layer_it = layers_.begin(); layer_it != end; ++layer_it)
+ {
+ (*layer_it)->read_channel_data(input_); //each layer reads it's "image data"
+ }
+
+ input_.set_position(end_of_layers_info);
+ }
+
+ unsigned long cp = input_.current_position();
+ //global layer mask info
+ unsigned long global_layer_mask_length = input_.read_long();
+ input_.discard_bytes(global_layer_mask_length);
+
+ }
+ catch(std::exception& ex)
+ {
+ std::clog << "big oops";
+ input_.set_position(end_of_layers);
+ }
+}
+
+} //namespace psd
+} //namespace caspar
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Niklas P Andersson, niklas.p.andersson@svt.se
+*/
+
+#ifndef _PSDDOC_H__
+#define _PSDDOC_H__
+
+#pragma once
+
+#include <string>
+#include <vector>
+#include "util\bigendian_file_input_stream.h"
+
+#include "misc.h"
+#include "layer.h"
+
+namespace caspar { namespace psd {
+
+class Document
+{
+public:
+ Document();
+
+ std::vector<layer_ptr>& layers()
+ {
+ return layers_;
+ }
+ unsigned long width()
+ {
+ return width_;
+ }
+ unsigned long height()
+ {
+ return height_;
+ }
+
+ bool parse(const std::wstring& s);
+
+private:
+ void read_header();
+ void read_color_mode();
+ void read_image_resources();
+ void read_layers();
+
+ std::wstring filename_;
+ BEFileInputStream input_;
+
+ std::vector<layer_ptr> layers_;
+
+ unsigned short channels_;
+ unsigned long width_;
+ unsigned long height_;
+ unsigned short depth_;
+ color_mode color_mode_;
+};
+
+} //namespace psd
+} //namespace caspar
+
+#endif //_PSDDOC_H__
\ No newline at end of file
--- /dev/null
+/*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Niklas P Andersson, niklas.p.andersson@svt.se
+*/
+
+#pragma once
+
+
+#include <memory>
+#include <vector>
+
+namespace caspar { namespace psd {
+
+template<typename T>
+class image
+{
+public:
+ image(unsigned long width, unsigned long height, unsigned char channels) : width_(width), height_(height), channels_(channels)
+ {
+ data_.resize(width*height*channels);
+ }
+
+ int width() const { return width_; };
+ int height() const { return height_; };
+ unsigned char channel_count() const { return channels_; }
+
+ T* data() { return data_.data(); }
+
+private:
+ std::vector<T> data_;
+ unsigned long width_;
+ unsigned long height_;
+ unsigned char channels_;
+};
+
+typedef image<unsigned char> image8bit;
+typedef image<unsigned short> image16bit;
+typedef image<unsigned long> image32bit;
+
+typedef std::shared_ptr<image8bit> image8bit_ptr;
+typedef std::shared_ptr<image16bit> image16bit_ptr;
+typedef std::shared_ptr<image32bit> image32bit_ptr;
+
+} //namespace psd
+} //namespace caspar
\ No newline at end of file
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Niklas P Andersson, niklas.p.andersson@svt.se
+*/
+
+#include "layer.h"
+#include "descriptor.h"
+#include <iostream>
+
+namespace caspar { namespace psd {
+
+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();
+
+ //Get info about the channels in the layer
+ unsigned short channelCount = stream.read_short();
+ for(int channelIndex = 0; channelIndex < channelCount; ++channelIndex)
+ {
+ short channel_id = static_cast<short>(stream.read_short());
+ unsigned long data_length = stream.read_long();
+
+ if(channel_id <= -2)
+ result->masks_++;
+
+ channel_ptr channel(std::make_shared<Channel>(channel_id, data_length));
+ result->channels_.push_back(channel);
+ }
+
+ unsigned long blendModeSignature = stream.read_long();
+ if(blendModeSignature != '8BIM')
+ throw PSDFileFormatException();
+
+ unsigned long blendModeKey = stream.read_long();
+ result->blendMode_ = IntToBlendMode(blendModeKey);
+
+ result->opacity_ = stream.read_byte();
+ result->baseClipping_ = stream.read_byte() == 1 ? false : true;
+ result->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);
+
+ result->name_ = stream.read_pascal_string(4);
+
+ //Aditional Layer Information
+ unsigned long end_of_layer_info = position1 + extraDataSize;
+
+ try
+ {
+ while(stream.current_position() < end_of_layer_info)
+ {
+ unsigned long signature = stream.read_long();
+ if(signature != '8BIM' && signature != '8B64')
+ throw PSDFileFormatException();
+
+ unsigned long key = stream.read_long();
+ unsigned long length = stream.read_long();
+ unsigned long end_of_chunk = stream.current_position() + length;
+
+ if(key == 'TySh') //type tool object settings
+ {
+ std::wstring text; //the text in the layer
+
+ stream.read_short(); //should be 1
+ stream.discard_bytes(6*8); //just throw transformation info for now
+ stream.read_short(); //"text version" should be 50
+ stream.read_long(); //"descriptor version" should be 16
+
+ //text data descriptor ('descriptor structure')
+ descriptor text_descriptor;
+ if(!text_descriptor.populate(stream))
+ throw PSDFileFormatException();
+
+ stream.read_short(); //"warp version" should be 1
+ stream.read_long(); //"descriptor version" should be 16
+
+ //warp data descriptor ('descriptor structure')
+ descriptor warp_descriptor;
+ if(!text_descriptor.populate(stream))
+ throw PSDFileFormatException();
+
+ stream.discard_bytes(4*8); //top, left, right, bottom
+ }
+
+ stream.set_position(end_of_chunk);
+ }
+ }
+ catch(PSDFileFormatException& ex)
+ {
+ stream.set_position(end_of_layer_info);
+ }
+
+ return result;
+}
+
+void Layer::read_mask_data(BEFileInputStream& stream)
+{
+ unsigned long length = stream.read_long();
+ if(length > 0)
+ {
+ 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();
+
+ 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();
+ }
+ }
+}
+
+//TODO: implement
+void Layer::ReadBlendingRanges(BEFileInputStream& stream)
+{
+ unsigned long length = stream.read_long();
+ stream.discard_bytes(length);
+}
+
+channel_ptr Layer::get_channel(ChannelType type)
+{
+ auto end = channels_.end();
+ for(auto it = channels_.begin(); it != end; ++it)
+ {
+ if((*it)->id() == type)
+ {
+ return (*it);
+ }
+ }
+
+ return NULL;
+}
+
+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;
+
+ 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;
+ }
+
+ 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;
+ }
+
+ auto end = channels_.end();
+ for(auto it = channels_.begin(); it != end; ++it)
+ {
+ image8bit_ptr target;
+ unsigned char offset;
+ bool discard_channel = false;
+
+ //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
+ {
+ target = img;
+ offset = ((*it)->id() >= 0) ? (*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
+ discard_channel = true;
+ else
+ {
+ target = mask;
+ offset = 0;
+ }
+ }
+
+ 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;
+
+ if(!target)
+ discard_channel = true;
+
+ if(discard_channel)
+ {
+ std::clog << " -> discarding" << std::endl;
+ stream.discard_bytes((*it)->data_length());
+ }
+ else
+ {
+ std::clog << " -> reading...";
+ unsigned short encoding = stream.read_short();
+ if(target)
+ {
+ if(encoding == 0)
+ read_raw_image_data(stream, *it, target, offset);
+ else if(encoding == 1)
+ read_rle_image_data(stream, *it, target, offset);
+ else
+ throw PSDFileFormatException();
+ }
+ std::clog << " " << std::hex << (stream.current_position() - cp) << " bytes read" << std::endl;
+ }
+ }
+
+ image_ = img;
+ mask_ = mask;
+}
+
+void Layer::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))
+ throw PSDFileFormatException();
+
+ unsigned char* data = target->data();
+
+ unsigned char stride = target->channel_count();
+ if(stride == 1)
+ stream.read(reinterpret_cast<char*>(data + offset), total_length);
+ else
+ {
+ for(unsigned long index=0; index < total_length; ++index)
+ data[index*stride+offset] = stream.read_byte();
+ }
+}
+
+void Layer::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();
+ unsigned long height = target->height();
+
+ std::vector<unsigned short> scanline_lengths;
+ scanline_lengths.reserve(height);
+
+ for(unsigned long scanlineIndex=0; scanlineIndex < height; ++scanlineIndex)
+ scanline_lengths.push_back(stream.read_short());
+
+ unsigned char* data = target->data();
+
+ for(unsigned long scanlineIndex=0; scanlineIndex < height; ++scanlineIndex)
+ {
+ unsigned long colIndex = 0;
+ unsigned char length = 0;
+ do
+ {
+ length = 0;
+
+ //Get controlbyte
+ char controlByte = static_cast<char>(stream.read_byte());
+ if(controlByte >= 0)
+ {
+ //Read uncompressed string
+ length = controlByte+1;
+ for(unsigned long index=0; index < length; ++index)
+ data[(scanlineIndex*width+colIndex+index) * stride + offset] = stream.read_byte();
+ }
+ else if(controlByte > -128)
+ {
+ //Repeat next byte
+ length = -controlByte+1;
+ unsigned value = stream.read_byte();
+ for(unsigned long index=0; index < length; ++index)
+ data[(scanlineIndex*width+colIndex+index) * stride + offset] = value;
+ }
+
+ colIndex += length;
+ }
+ while(colIndex < width);
+ }
+}
+
+//
+//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
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Niklas P Andersson, niklas.p.andersson@svt.se
+*/
+
+#ifndef _PSDLAYER_H__
+#define _PSDLAYER_H__
+
+#pragma once
+
+#include <vector>
+#include <string>
+#include <memory>
+#include "util\bigendian_file_input_stream.h"
+
+#include "image.h"
+#include "misc.h"
+#include "channel.h"
+
+namespace caspar { namespace psd {
+
+class Layer;
+typedef std::shared_ptr<Layer> layer_ptr;
+
+class Layer
+{
+public:
+ Layer() : blendMode_(InvalidBlendMode), opacity_(255), baseClipping_(false), flags_(0), masks_(0)
+ {}
+
+ static std::shared_ptr<Layer> create(BEFileInputStream&);
+ void read_channel_data(BEFileInputStream&);
+
+ unsigned long GetTotalDataLength();
+
+ //image_ptr read_image(BEFileInputStream&);
+
+ const std::wstring& name() const
+ {
+ return name_;
+ }
+ const rect<long>& rect() const
+ {
+ return rect_;
+ }
+
+private:
+ channel_ptr get_channel(ChannelType);
+ void read_mask_data(BEFileInputStream&);
+ void ReadBlendingRanges(BEFileInputStream&);
+
+ 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);
+
+ caspar::psd::rect<long> rect_;
+ std::vector<channel_ptr> channels_;
+ BlendMode blendMode_;
+ unsigned char opacity_;
+ bool baseClipping_;
+ unsigned char flags_;
+ std::wstring name_;
+
+ unsigned char masks_;
+ caspar::psd::rect<long> mask_rect_;
+ unsigned char default_mask_value_;
+ unsigned char mask_flags_;
+
+ image8bit_ptr image_;
+ image8bit_ptr mask_;
+};
+
+} //namespace psd
+} //namespace caspar
+
+#endif //_PSDLAYER_H__
\ No newline at end of file
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Niklas P Andersson, niklas.p.andersson@svt.se
+*/
+
+#include <vector>
+#include "misc.h"
+
+namespace caspar { namespace psd {
+
+BlendMode IntToBlendMode(unsigned long x)
+{
+ BlendMode retVal = InvalidBlendMode;
+ switch(x)
+ {
+ case Normal: retVal = Normal; break;
+ case Darken: retVal = Darken; break;
+ case Lighten: retVal = Lighten; break;
+ case Hue: retVal = Hue; break;
+ case Saturation: retVal = Saturation; break;
+ case Color: retVal = Color; break;
+ case Luminosity: retVal = Luminosity; break;
+ case Multiply: retVal = Multiply; break;
+ case Screen: retVal = Screen; break;
+ case Dissolve: retVal = Dissolve; break;
+ case Overlay: retVal = Overlay; break;
+ case HardLight: retVal = HardLight; break;
+ case SoftLight: retVal = SoftLight; break;
+ case Difference: retVal = Difference; break;
+ case Exclusion: retVal = Exclusion; break;
+ case ColorDodge: retVal = ColorDodge; break;
+ case ColorBurn: retVal = ColorBurn; break;
+ }
+
+ return retVal;
+}
+
+std::wstring BlendModeToString(BlendMode b)
+{
+ std::wstring retVal = L"Invalid";
+ switch(b)
+ {
+ case Normal: retVal = L"Normal"; break;
+ case Darken: retVal = L"Darken"; break;
+ case Lighten: retVal = L"Lighten"; break;
+ case Hue: retVal = L"Hue"; break;
+ case Saturation: retVal = L"Saturation"; break;
+ case Color: retVal = L"Color"; break;
+ case Luminosity: retVal = L"Luminosity"; break;
+ case Multiply: retVal = L"Multiply"; break;
+ case Screen: retVal = L"Screen"; break;
+ case Dissolve: retVal = L"Dissolve"; break;
+ case Overlay: retVal = L"Overlay"; break;
+ case HardLight: retVal = L"HardLight"; break;
+ case SoftLight: retVal = L"SoftLight"; break;
+ case Difference: retVal = L"Difference"; break;
+ case Exclusion: retVal = L"Exclusion"; break;
+ case ColorDodge: retVal = L"ColorDodge"; break;
+ case ColorBurn: retVal = L"ColorBurn"; break;
+ }
+
+ return retVal;
+}
+
+color_mode int_to_color_mode(unsigned short x)
+{
+ color_mode retVal = InvalidColorMode;
+ switch(x)
+ {
+ case Bitmap: retVal = Bitmap; break;
+ case Grayscale: retVal = Grayscale; break;
+ case Indexed: retVal = Indexed; break;
+ case RGB: retVal = RGB; break;
+ case CMYK: retVal = CMYK; break;
+ case Multichannel: retVal = Multichannel; break;
+ case Duotone: retVal = Duotone; break;
+ case Lab: retVal = Lab; break;
+ };
+
+ return retVal;
+}
+std::wstring color_mode_to_string(color_mode c)
+{
+ std::wstring retVal = L"Invalid";
+ switch(c)
+ {
+ case Bitmap: retVal = L"Bitmap"; break;
+ case Grayscale: retVal = L"Grayscale"; break;
+ case Indexed: retVal = L"Indexed"; break;
+ case RGB: retVal = L"RGB"; break;
+ case CMYK: retVal = L"CMYK"; break;
+ case Multichannel: retVal = L"Multichannel"; break;
+ case Duotone: retVal = L"Duotone"; break;
+ case Lab: retVal = L"Lab"; break;
+ };
+
+ return retVal;
+}
+
+} //namespace psd
+} //namespace caspar
\ No newline at end of file
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Niklas P Andersson, niklas.p.andersson@svt.se
+*/
+
+#ifndef _PSDMISC_H__
+#define _PSDMISC_H__
+
+#include <string>
+
+namespace caspar { namespace psd {
+
+template<typename T>
+struct rect
+{
+ T top;
+ T right;
+ T bottom;
+ T left;
+ T width() { return right-left; }
+ T height() { return bottom-top; }
+};
+
+class PSDFileFormatException : public std::exception
+{
+public:
+ virtual ~PSDFileFormatException()
+ {}
+ virtual const char *what() const
+ {
+ return "Unknown fileformat error";
+ }
+};
+
+enum ChannelType
+{
+ TotalUserMask = -3,
+ UserMask = -2,
+ Transparency = -1,
+ ColorRed = 0,
+ ColorGreen = 1,
+ ColorBlue = 2
+};
+
+enum BlendMode
+{
+ InvalidBlendMode = -1,
+ Normal = 'norm',
+ Darken = 'dark',
+ Lighten = 'lite',
+ Hue = 'hue ',
+ Saturation = 'sat ',
+ Color = 'colr',
+ Luminosity = 'lum ',
+ Multiply = 'mul ',
+ Screen = 'scrn',
+ Dissolve = 'diss',
+ Overlay = 'over',
+ HardLight = 'hLit',
+ SoftLight = 'sLit',
+ Difference = 'diff',
+ Exclusion = 'smud',
+ ColorDodge = 'div ',
+ ColorBurn = 'idiv'
+};
+
+BlendMode IntToBlendMode(unsigned long x);
+std::wstring BlendModeToString(BlendMode b);
+
+enum color_mode
+{
+ InvalidColorMode = -1,
+ Bitmap = 0,
+ Grayscale = 1,
+ Indexed = 2,
+ RGB = 3,
+ CMYK = 4,
+ Multichannel = 7,
+ Duotone = 8,
+ Lab = 9
+};
+
+color_mode int_to_color_mode(unsigned short x);
+std::wstring color_mode_to_string(color_mode c);
+
+} //namespace psd
+} //namespace caspar
+
+#endif
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="descriptor.cpp" />
+ <ClCompile Include="doc.cpp" />
+ <ClCompile Include="layer.cpp" />
+ <ClCompile Include="misc.cpp" />
+ <ClCompile Include="resource.cpp" />
+ <ClCompile Include="util\bigendian_file_input_stream.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="channel.h" />
+ <ClInclude Include="descriptor.h" />
+ <ClInclude Include="doc.h" />
+ <ClInclude Include="image.h" />
+ <ClInclude Include="layer.h" />
+ <ClInclude Include="misc.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="util\bigendian_file_input_stream.h" />
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{866A164B-6F7A-450E-8452-C6AE4E176436}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>psd</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <IncludePath>..\..\dependencies64\boost\;$(IncludePath)</IncludePath>
+ <OutDir>$(ProjectDir)bin\$(Configuration)\</OutDir>
+ <IntDir>$(ProjectDir)tmp\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Niklas P Andersson, niklas.p.andersson@svt.se
+*/
+
+#include "resource.h"
+
+
+resource::resource(void)
+{
+}
+
+
+resource::~resource(void)
+{
+}
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Niklas P Andersson, niklas.p.andersson@svt.se
+*/
+
+#pragma once
+
+class resource
+{
+public:
+ resource(void);
+ ~resource(void);
+};
+
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Niklas P Andersson, niklas.p.andersson@svt.se
+*/
+
+#include "bigendian_file_input_stream.h"
+#include "..\..\..\common\utf.h"
+#include <boost/locale.hpp>
+
+namespace caspar { namespace psd {
+
+BEFileInputStream::BEFileInputStream()
+{
+}
+
+BEFileInputStream::~BEFileInputStream()
+{
+ close();
+}
+
+void BEFileInputStream::Open(const std::wstring& filename)
+{
+ filename_ = filename;
+ ifs_.open(filename_.c_str(), std::ios::in | std::ios::binary);
+ if(!ifs_.is_open())
+ throw FileNotFoundException();
+}
+
+void BEFileInputStream::close()
+{
+ if(ifs_.is_open())
+ ifs_.close();
+}
+
+unsigned char BEFileInputStream::read_byte()
+{
+ unsigned char out;
+ read((char*)&out, 1);
+
+ return out;
+}
+
+unsigned short SWAP16(unsigned short inVal)
+{
+ unsigned short outVal;
+ __asm{
+ mov ax, inVal;
+ mov bl, ah;
+ mov bh, al;
+ mov outVal, bx;
+ }
+ return outVal;
+}
+
+unsigned long SWAP32(unsigned long inVal)
+{
+ unsigned long outVal;
+ __asm{
+ mov eax, inVal; //1 2 ah = 3 al = 4
+ mov bl, ah;
+ mov bh, al;
+
+ ror ebx, 16;
+ ror eax, 16;
+
+ mov bl, ah;
+ mov bh, al;
+ mov outVal, ebx;
+ }
+ return outVal;
+}
+
+unsigned short BEFileInputStream::read_short()
+{
+ unsigned short out;
+ read((char*)&out, 2);
+
+ return SWAP16(out);
+}
+
+unsigned long BEFileInputStream::read_long()
+{
+ unsigned long in;
+ read((char*)&in, 4);
+
+ return SWAP32(in);
+}
+
+void BEFileInputStream::read(char* buf, unsigned long length)
+{
+ if(length > 0)
+ {
+ if(ifs_.eof())
+ throw UnexpectedEOFException();
+
+ ifs_.read(buf, (std::streamsize)length);
+
+ if(ifs_.gcount() < (std::streamsize)length)
+ throw UnexpectedEOFException();
+ }
+}
+
+long BEFileInputStream::current_position()
+{
+ return ifs_.tellg();
+}
+
+void BEFileInputStream::set_position(unsigned long offset)
+{
+ ifs_.seekg(static_cast<std::streamsize>(offset), std::ios_base::beg);
+}
+
+void BEFileInputStream::discard_bytes(unsigned long length)
+{
+ ifs_.seekg(static_cast<std::streamsize>(length), std::ios_base::cur);
+}
+void BEFileInputStream::discard_to_next_word()
+{
+ unsigned const char padding = 2;
+ discard_bytes((padding - (current_position() % padding)) % padding);
+}
+
+void BEFileInputStream::discard_to_next_dword()
+{
+ unsigned const char padding = 4;
+ discard_bytes((padding - (current_position() % padding)) % padding);
+}
+
+std::wstring BEFileInputStream::read_pascal_string(unsigned char padding)
+{
+ char strBuffer[256];
+
+ unsigned char strLength = this->read_byte();
+
+ strBuffer[strLength] = 0;
+ this->read(strBuffer, strLength);
+
+ unsigned char padded_bytes = (padding - ((strLength+1) % padding)) % padding;
+ this->discard_bytes(padded_bytes);
+
+ return boost::locale::conv::utf_to_utf<wchar_t>(strBuffer);
+
+
+}
+
+std::wstring BEFileInputStream::read_unicode_string()
+{
+ unsigned long length = read_long();
+ std::wstring result;
+
+ if(length > 0)
+ {
+ result.reserve(length);
+
+ //can be optimized. Reads and swaps byte-order, one char at the time
+ for(int i=0;i<length; ++i)
+ result.append(1, static_cast<wchar_t>(read_short()));
+ }
+
+ return result;
+}
+
+std::wstring BEFileInputStream::read_id_string()
+{
+ std::string result;
+ unsigned long length = read_long();
+
+ if(length > 0)
+ {
+ result.reserve(length);
+
+ for(int i=0;i<length;++i)
+ result.append(1, read_byte());
+ }
+ else
+ {
+ result.reserve(4);
+ for(int i=0;i<4;++i)
+ result.append(1, read_byte());
+ }
+
+ return boost::locale::conv::utf_to_utf<wchar_t>(result);
+}
+
+} //namespace psd
+} //namespace caspar
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Niklas P Andersson, niklas.p.andersson@svt.se
+*/
+
+#ifndef _BEFILEINPUTSTREAM_H__
+#define _BEFILEINPUTSTREAM_H__
+
+#pragma once
+
+#include <string>
+#include <fstream>
+
+namespace caspar {
+namespace psd {
+
+class UnexpectedEOFException : public std::exception
+{
+public:
+ virtual ~UnexpectedEOFException()
+ {}
+ virtual const char *what() const
+ {
+ return "Unexpected end of file";
+ }
+};
+class FileNotFoundException : public std::exception
+{
+public:
+ virtual ~FileNotFoundException()
+ {}
+ virtual const char *what() const
+ {
+ return "File not found";
+ }
+};
+
+class BEFileInputStream
+{
+public:
+ explicit BEFileInputStream();
+ virtual ~BEFileInputStream();
+
+ void Open(const std::wstring& filename);
+
+ void read(char*, unsigned long);
+ unsigned char read_byte();
+ unsigned short read_short();
+ unsigned long read_long();
+ std::wstring read_pascal_string(unsigned char padding = 1);
+ std::wstring read_unicode_string();
+ std::wstring read_id_string();
+
+ void discard_bytes(unsigned long);
+ void discard_to_next_word();
+ void discard_to_next_dword();
+
+ long current_position();
+ void set_position(unsigned long);
+
+ void close();
+private:
+ std::ifstream ifs_;
+ std::wstring filename_;
+};
+
+class StreamPositionBackup
+{
+public:
+ StreamPositionBackup(BEFileInputStream* pStream, unsigned long newPos) : pStream_(pStream)
+ {
+ oldPosition_ = pStream->current_position();
+ pStream_->set_position(newPos);
+ }
+ ~StreamPositionBackup()
+ {
+ pStream_->set_position(oldPosition_);
+ }
+private:
+ unsigned long oldPosition_;
+ BEFileInputStream* pStream_;
+
+};
+
+} //namespace psd
+} //namespace caspar
+
+#endif //_BEFILEINPUTSTREAM_H__
\ No newline at end of file
--- /dev/null
+// psd-test.cpp : Defines the entry point for the console application.
+//
+
+#include "stdafx.h"
+#include "../../modules/psd/doc.h"
+
+int _tmain(int argc, _TCHAR* argv[])
+{
+ caspar::psd::Document doc;
+ doc.parse(L"C:\\Lokala Filer\\Utveckling\\CasparCG\\Server 2.1\\test\\data\\test1.psd");
+ int a = 42;
+ return 0;
+}
+
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{156C91E0-8CAC-4DBA-A212-AAFDAFACD8BC}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>psdtest</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <LibraryPath>C:\Lokala Filer\Utveckling\CasparCG\Server 2.1\dependencies64\boost\stage\lib;$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <None Include="ReadMe.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="stdafx.h" />
+ <ClInclude Include="targetver.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="psd-test.cpp" />
+ <ClCompile Include="stdafx.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\modules\psd\psd.vcxproj">
+ <Project>{866a164b-6f7a-450e-8452-c6ae4e176436}</Project>
+ <Private>true</Private>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ <CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
+ <LinkLibraryDependencies>true</LinkLibraryDependencies>
+ <UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+// stdafx.cpp : source file that includes just the standard includes
+// psd-test.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
--- /dev/null
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#include "targetver.h"
+
+#include <stdio.h>
+#include <tchar.h>
+
+
+
+// TODO: reference additional headers your program requires here
--- /dev/null
+#pragma once
+
+// Including SDKDDKVer.h defines the highest available Windows platform.
+
+// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
+// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
+
+#include <SDKDDKVer.h>