]> git.sesse.net Git - casparcg/commitdiff
primal psd-file reading
authorniklaspandersson <niklas.p.andersson@svt.se>
Thu, 4 Jul 2013 10:50:27 +0000 (12:50 +0200)
committerniklaspandersson <niklas.p.andersson@svt.se>
Thu, 4 Jul 2013 10:50:27 +0000 (12:50 +0200)
21 files changed:
casparcg.sln
modules/psd/channel.h [new file with mode: 0644]
modules/psd/descriptor.cpp [new file with mode: 0644]
modules/psd/descriptor.h [new file with mode: 0644]
modules/psd/doc.cpp [new file with mode: 0644]
modules/psd/doc.h [new file with mode: 0644]
modules/psd/image.h [new file with mode: 0644]
modules/psd/layer.cpp [new file with mode: 0644]
modules/psd/layer.h [new file with mode: 0644]
modules/psd/misc.cpp [new file with mode: 0644]
modules/psd/misc.h [new file with mode: 0644]
modules/psd/psd.vcxproj [new file with mode: 0644]
modules/psd/resource.cpp [new file with mode: 0644]
modules/psd/resource.h [new file with mode: 0644]
modules/psd/util/bigendian_file_input_stream.cpp [new file with mode: 0644]
modules/psd/util/bigendian_file_input_stream.h [new file with mode: 0644]
test/psd-test/psd-test.cpp [new file with mode: 0644]
test/psd-test/psd-test.vcxproj [new file with mode: 0644]
test/psd-test/stdafx.cpp [new file with mode: 0644]
test/psd-test/stdafx.h [new file with mode: 0644]
test/psd-test/targetver.h [new file with mode: 0644]

index de59e760ce7bef8f12b21ce10464046aad86019d..bfa3d2e9e29f62d5c603b96deec9640e6d54ddc7 100644 (file)
@@ -36,7 +36,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "accelerator", "accelerator\
 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
@@ -176,6 +186,26 @@ Global
                {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
@@ -189,9 +219,7 @@ Global
                {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
diff --git a/modules/psd/channel.h b/modules/psd/channel.h
new file mode 100644 (file)
index 0000000..4f8fc97
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+* 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
diff --git a/modules/psd/descriptor.cpp b/modules/psd/descriptor.cpp
new file mode 100644 (file)
index 0000000..deabf62
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+* 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
diff --git a/modules/psd/descriptor.h b/modules/psd/descriptor.h
new file mode 100644 (file)
index 0000000..61e37b0
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+* 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
diff --git a/modules/psd/doc.cpp b/modules/psd/doc.cpp
new file mode 100644 (file)
index 0000000..3e73c02
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+* 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
diff --git a/modules/psd/doc.h b/modules/psd/doc.h
new file mode 100644 (file)
index 0000000..1e0fe69
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+* 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
diff --git a/modules/psd/image.h b/modules/psd/image.h
new file mode 100644 (file)
index 0000000..674a5fe
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+* 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
diff --git a/modules/psd/layer.cpp b/modules/psd/layer.cpp
new file mode 100644 (file)
index 0000000..9664377
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+* 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
diff --git a/modules/psd/layer.h b/modules/psd/layer.h
new file mode 100644 (file)
index 0000000..ade1705
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+* 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
diff --git a/modules/psd/misc.cpp b/modules/psd/misc.cpp
new file mode 100644 (file)
index 0000000..bd79246
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+* 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
diff --git a/modules/psd/misc.h b/modules/psd/misc.h
new file mode 100644 (file)
index 0000000..b754165
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+* 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
diff --git a/modules/psd/psd.vcxproj b/modules/psd/psd.vcxproj
new file mode 100644 (file)
index 0000000..3cd7dbd
--- /dev/null
@@ -0,0 +1,96 @@
+<?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
diff --git a/modules/psd/resource.cpp b/modules/psd/resource.cpp
new file mode 100644 (file)
index 0000000..45d2116
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+* 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)
+{
+}
diff --git a/modules/psd/resource.h b/modules/psd/resource.h
new file mode 100644 (file)
index 0000000..1e91eeb
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+* 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);
+};
+
diff --git a/modules/psd/util/bigendian_file_input_stream.cpp b/modules/psd/util/bigendian_file_input_stream.cpp
new file mode 100644 (file)
index 0000000..e670970
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+* 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
diff --git a/modules/psd/util/bigendian_file_input_stream.h b/modules/psd/util/bigendian_file_input_stream.h
new file mode 100644 (file)
index 0000000..41020f8
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+* 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
diff --git a/test/psd-test/psd-test.cpp b/test/psd-test/psd-test.cpp
new file mode 100644 (file)
index 0000000..a3d9a14
--- /dev/null
@@ -0,0 +1,14 @@
+// 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;
+}
+
diff --git a/test/psd-test/psd-test.vcxproj b/test/psd-test/psd-test.vcxproj
new file mode 100644 (file)
index 0000000..c18d39d
--- /dev/null
@@ -0,0 +1,101 @@
+<?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
diff --git a/test/psd-test/stdafx.cpp b/test/psd-test/stdafx.cpp
new file mode 100644 (file)
index 0000000..b70818d
--- /dev/null
@@ -0,0 +1,8 @@
+// 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
diff --git a/test/psd-test/stdafx.h b/test/psd-test/stdafx.h
new file mode 100644 (file)
index 0000000..b005a83
--- /dev/null
@@ -0,0 +1,15 @@
+// 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
diff --git a/test/psd-test/targetver.h b/test/psd-test/targetver.h
new file mode 100644 (file)
index 0000000..87c0086
--- /dev/null
@@ -0,0 +1,8 @@
+#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>