]> git.sesse.net Git - casparcg/commitdiff
* Changed to int to simplify code in places in the photoshop producer where the exact...
authorHelge Norberg <helge.norberg@svt.se>
Thu, 3 Sep 2015 16:08:14 +0000 (18:08 +0200)
committerHelge Norberg <helge.norberg@svt.se>
Thu, 3 Sep 2015 16:08:14 +0000 (18:08 +0200)
* Fixed subtle bug in photoshop producer where an uint16 was casted to int but should have been casted to int16 before casting to int (usually widening, so more than 16 bits).
* Reverted usage of wstring in pdf_reader to string.

modules/psd/channel.h
modules/psd/descriptor.cpp
modules/psd/image.h
modules/psd/layer.cpp
modules/psd/layer.h
modules/psd/psd_document.cpp
modules/psd/psd_document.h
modules/psd/util/bigendian_file_input_stream.cpp
modules/psd/util/bigendian_file_input_stream.h
modules/psd/util/pdf_reader.cpp
modules/psd/util/pdf_reader.h

index 949c9229e2361d75e123989596d109132564b0f8..ae930adaae78ac8014517b15906fbac3b0b0bb73 100644 (file)
@@ -31,10 +31,10 @@ namespace caspar { namespace psd {
 struct channel
 {
 public:
-       channel(std::int16_t id1, std::uint32_t len) : id(id1), data_length(len) {}
+       channel(int id1, int len) : id(id1), data_length(len) {}
 
-       std::int16_t id;
-       std::uint32_t data_length;
+       int id;
+       int data_length;
 };
 
 }      //namespace psd
index 90e07a259fc9873ee475d8053022bde3141f7982..1d8d939c9756388cab08cb58e0884c8a33f017ad 100644 (file)
@@ -68,8 +68,8 @@ void descriptor::populate(bigendian_file_input_stream& stream)
 {
        stream.read_unicode_string();
        stream.read_id_string();
-       auto element_count = stream.read_long();
-       for (std::uint32_t element_index = 0; element_index < element_count; ++element_index)
+       int element_count = stream.read_long();
+       for (int element_index = 0; element_index < element_count; ++element_index)
        {
                std::wstring key = stream.read_id_string();
                read_value(key, stream);
@@ -128,8 +128,9 @@ void descriptor::read_value(const std::wstring& key, bigendian_file_input_stream
        case 'VlLs': 
                {
                        context::scoped_holder list(key, context_);
-                       auto count = stream.read_long();
-                       for(std::uint32_t i = 0; i < count; ++i)
+                       int count = stream.read_long();
+
+                       for (int i = 0; i < count; ++i)
                        {
                                read_value(L"li", stream);
                        }
index 7e1d2bb8c643ab2ffab5c5a06b796e91d8f53997..d29771c7cc6d828e7aba53e8e45a4e7ace5c1e17 100644 (file)
@@ -27,22 +27,22 @@ template<typename T>
 class image
 {
 public:
-       image(std::uint32_t width, std::uint32_t height, std::uint8_t channels) : width_(width), height_(height), channels_(channels)
+       image(int width, int height, int channels) : width_(width), height_(height), channels_(channels)
        {
                data_.resize(width*height*channels);
        }
 
-       std::uint32_t width() const { return width_; }
-       std::uint32_t height() const { return height_; }
-       std::uint8_t channel_count() const { return channels_; }
+       int width() const { return width_; }
+       int height() const { return height_; }
+       int channel_count() const { return channels_; }
 
        T* data() { return data_.data(); }
 
 private:
-       std::vector<T> data_;
-       std::uint32_t width_;
-       std::uint32_t height_;
-       std::uint8_t channels_;
+       std::vector<T>  data_;
+       int                             width_;
+       int                             height_;
+       int                             channels_;
 };
 
 typedef image<std::uint8_t>            image8bit;
index b4107b841e17bb26a09fec597379132516606dbf..7ea63afd83a9c0899ca9e1f7301bbcb4fab40951 100644 (file)
@@ -85,8 +85,8 @@ private:
        std::vector<channel>                    channels_;
        blend_mode                                              blend_mode_;
        int                                                             link_group_id_;
-       std::uint8_t                                    opacity_;
-       std::uint16_t                                   sheet_color_;
+       int                                                             opacity_;
+       int                                                             sheet_color_;
        bool                                                    baseClipping_;
        std::uint8_t                                    flags_;
        std::uint32_t                                   protection_flags_;
@@ -94,10 +94,10 @@ private:
        int                                                             masks_count_;
        double                                                  text_scale_;
 
-       rect<std::int32_t>                              vector_mask_;
+       rect<int>                                               vector_mask_;
        layer::layer_mask_info                  mask_;
 
-       rect<std::int32_t>                              bitmap_rect_;
+       rect<int>                                               bitmap_rect_;
        image8bit_ptr                                   bitmap_;
 
        boost::property_tree::wptree    text_layer_info_;
@@ -199,7 +199,7 @@ public:
                                break;
 
                        case 'lclr':
-                               sheet_color_ = stream.read_short();
+                               sheet_color_ = static_cast<std::int16_t>(stream.read_short());
                                break;
                                
                        case 'lyvr':    //layer version
@@ -244,9 +244,9 @@ public:
                solid_color_.alpha = 255;
        }
 
-       void read_vector_mask(std::uint32_t length, bigendian_file_input_stream& stream, std::uint32_t doc_width, std::uint32_t doc_height)
+       void read_vector_mask(int length, bigendian_file_input_stream& stream, int doc_width, int doc_height)
        {
-               typedef std::pair<std::uint32_t, std::uint32_t> path_point;
+               typedef std::pair<int, int> path_point;
 
                stream.read_long(); // version
                stream.read_long(); // flags
@@ -255,7 +255,12 @@ public:
                auto position = stream.current_position();
 
                std::vector<path_point> knots;
-               for(int i=1; i <= path_records; ++i)
+               
+               const int SELECTOR_SIZE = 2;
+               const int PATH_POINT_SIZE = 4 + 4;
+               const int PATH_POINT_RECORD_SIZE = SELECTOR_SIZE + (3 * PATH_POINT_SIZE);
+
+               for (int i = 1; i <= path_records; ++i)
                {
                        auto selector = stream.read_short();
                        if(selector == 2)       //we only concern ourselves with closed paths 
@@ -280,7 +285,8 @@ public:
                                }
                        }
 
-                       stream.set_position(position + 26*i);
+                       auto offset = PATH_POINT_RECORD_SIZE * i;
+                       stream.set_position(position + offset);
                }
 
                if(knots.size() != 4)   //we only support rectangular vector masks
@@ -293,15 +299,15 @@ public:
                //the path_points are given in fixed-point 8.24 as a ratio with regards to the width/height of the document. we need to divide by 16777215.0f to get the real ratio.
                float x_ratio = doc_width / 16777215.0f;
                float y_ratio = doc_height / 16777215.0f;
-               vector_mask_.location.x = static_cast<std::int32_t>(knots[0].first * x_ratio +0.5f);                                                            //add .5 to get propper rounding when converting to integer
-               vector_mask_.location.y = static_cast<std::int32_t>(knots[0].second * y_ratio +0.5f);                                                           //add .5 to get propper rounding when converting to integer
-               vector_mask_.size.width = static_cast<std::int32_t>(knots[1].first * x_ratio +0.5f)     - vector_mask_.location.x;              //add .5 to get propper rounding when converting to integer
-               vector_mask_.size.height = static_cast<std::int32_t>(knots[2].second * y_ratio +0.5f) - vector_mask_.location.y;        //add .5 to get propper rounding when converting to integer
+               vector_mask_.location.x = static_cast<int>(knots[0].first * x_ratio +0.5f);                                                             //add .5 to get propper rounding when converting to integer
+               vector_mask_.location.y = static_cast<int>(knots[0].second * y_ratio +0.5f);                                                            //add .5 to get propper rounding when converting to integer
+               vector_mask_.size.width = static_cast<int>(knots[1].first * x_ratio +0.5f)      - vector_mask_.location.x;              //add .5 to get propper rounding when converting to integer
+               vector_mask_.size.height = static_cast<int>(knots[2].second * y_ratio +0.5f) - vector_mask_.location.y; //add .5 to get propper rounding when converting to integer
        }
 
        void read_metadata(bigendian_file_input_stream& stream, const psd_document& doc)
        {
-               auto count = stream.read_long();
+               int count = stream.read_long();
                for(int index = 0; index < count; ++index)
                        read_chunk(stream, doc, true);
        }
@@ -343,9 +349,11 @@ public:
                descriptor text_descriptor(L"text");
                text_descriptor.populate(stream);
                auto text_info = text_descriptor.items().get_optional<std::wstring>(L"EngineData");
-               if(text_info)
+               
+               if (text_info)
                {
-                       read_pdf(text_layer_info_, *text_info);
+                       std::string str(text_info->begin(), text_info->end());
+                       read_pdf(text_layer_info_, str);
                        log::print_child(boost::log::trivial::trace, L"", L"text_layer_info", text_layer_info_);
                }
 
@@ -382,7 +390,7 @@ public:
 
                bool has_transparency = has_channel(channel_type::transparency);
        
-               rect<std::int32_t> clip_rect;
+               rect<int> clip_rect;
                if(!bitmap_rect_.empty())
                {
                        clip_rect = bitmap_rect_;
@@ -403,9 +411,9 @@ public:
 
                for(auto it = channels_.begin(); it != channels_.end(); ++it)
                {
-                       psd::rect<std::int32_t> src_rect;
+                       psd::rect<int> src_rect;
                        image8bit_ptr target;
-                       std::uint8_t offset = 0;
+                       int offset = 0;
                        bool discard_channel = false;
 
                        //determine target bitmap and offset
@@ -414,7 +422,7 @@ public:
                        else if((*it).id >= -1) //BGRA-data
                        {
                                target = bitmap;
-                               offset = static_cast<std::uint8_t>(((*it).id >= 0) ? 2 - (*it).id : 3);
+                               offset = ((*it).id >= 0) ? 2 - (*it).id : 3;
                                src_rect = bitmap_rect_;
                        }
                        else if(mask)   //mask
@@ -460,25 +468,25 @@ public:
                mask_.bitmap_ = mask;
        }
 
-       void read_raw_image_data(bigendian_file_input_stream& stream, std::uint32_t data_length, image8bit_ptr target, std::uint8_t offset)
+       void read_raw_image_data(bigendian_file_input_stream& stream, int data_length, image8bit_ptr target, int offset)
        {
-               std::uint32_t total_length = target->width() * target->height();
-               if(total_length != data_length)
+               auto total_length = target->width() * target->height();
+               if (total_length != data_length)
                        CASPAR_THROW_EXCEPTION(psd_file_format_exception() << msg_info("total_length != data_length"));
 
                auto data = target->data();
-
                auto stride = target->channel_count();
-               if(stride == 1)
+
+               if (stride == 1)
                        stream.read(reinterpret_cast<char*>(data + offset), total_length);
                else
                {
-                       for(std::uint32_t index = 0; index < total_length; ++index)
+                       for(int index = 0; index < total_length; ++index)
                                data[index * stride + offset] = stream.read_byte();
                }
        }
 
-       void read_rle_image_data(bigendian_file_input_stream& stream, const rect<std::int32_t>&src_rect, const rect<std::int32_t>&clip_rect, image8bit_ptr target, std::uint8_t offset)
+       void read_rle_image_data(bigendian_file_input_stream& stream, const rect<int>&src_rect, const rect<int>&clip_rect, image8bit_ptr target, int offset)
        {
                auto width = src_rect.size.width;
                auto height = src_rect.size.height;
@@ -487,26 +495,26 @@ public:
                int offset_x = clip_rect.location.x - src_rect.location.x;
                int offset_y = clip_rect.location.y - src_rect.location.y;
 
-               std::vector<std::uint8_t> scanline_lengths;
+               std::vector<int> scanline_lengths;
                scanline_lengths.reserve(height);
 
-               for (long scanlineIndex = 0; scanlineIndex < height; ++scanlineIndex)
-                       scanline_lengths.push_back(stream.read_short());
+               for (int scanlineIndex = 0; scanlineIndex < height; ++scanlineIndex)
+                       scanline_lengths.push_back(static_cast<std::int16_t>(stream.read_short()));
 
                auto target_data = target->data();
 
                std::vector<std::uint8_t> line(width);
 
-               for(long scanlineIndex=0; scanlineIndex < height; ++scanlineIndex)
+               for(int scanlineIndex=0; scanlineIndex < height; ++scanlineIndex)
                {
                        if(scanlineIndex >= target->height()+offset_y)
                                break;
 
-                       long colIndex = 0;
+                       int colIndex = 0;
 
                        do
                        {
-                               std::uint8_t length = 0;
+                               int length = 0;
 
                                //Get controlbyte
                                char controlByte = static_cast<char>(stream.read_byte());
@@ -546,8 +554,8 @@ void layer::populate(bigendian_file_input_stream& stream, const psd_document& do
 void layer::read_channel_data(bigendian_file_input_stream& stream) { impl_->read_channel_data(stream); }
 
 const std::wstring& layer::name() const { return impl_->name_; }
-std::uint8_t layer::opacity() const { return impl_->opacity_; }
-std::uint16_t layer::sheet_color() const { return impl_->sheet_color_; }
+int layer::opacity() const { return impl_->opacity_; }
+int layer::sheet_color() const { return impl_->sheet_color_; }
 
 bool layer::is_visible() { return (impl_->flags_ & 2) == 0; }  //the (PSD file-format) documentation is is saying the opposite but what the heck
 bool layer::is_position_protected() { return (impl_->protection_flags_& 4) == 4; }
@@ -562,7 +570,7 @@ const boost::property_tree::wptree& layer::timeline_data() const { return impl_-
 bool layer::is_solid() const { return impl_->solid_color_.alpha != 0; }
 color<std::uint8_t> layer::solid_color() const { return impl_->solid_color_; }
 
-const point<std::int32_t>& layer::location() const { return impl_->bitmap_rect_.location; }
+const point<int>& layer::location() const { return impl_->bitmap_rect_.location; }
 const image8bit_ptr& layer::bitmap() const { return impl_->bitmap_; }
 
 int layer::link_group_id() const { return impl_->link_group_id_; }
index d9cff17e68943db9b08b7deb495cff6e8c14638c..33a3422e678900f6ede390344162c7e3e37b90ab 100644 (file)
@@ -50,18 +50,18 @@ public:
 
                void read_mask_data(bigendian_file_input_stream&);
 
-               image8bit_ptr           bitmap_;
-               std::uint8_t            default_value_;
-               std::uint8_t            flags_;
-               char                            mask_id_;
-               rect<std::int32_t>      rect_;
+               image8bit_ptr   bitmap_;
+               std::uint8_t    default_value_;
+               std::uint8_t    flags_;
+               char                    mask_id_;
+               rect<int>               rect_;
 
        public:
                bool enabled() const { return (flags_ & 2) == 0; }
                bool linked() const { return (flags_ & 1) == 0;  }
                bool inverted() const { return (flags_ & 4) == 4; }
 
-               const point<std::int32_t>& location() const { return rect_.location; }
+               const point<int>& location() const { return rect_.location; }
                const image8bit_ptr& bitmap() const { return bitmap_; }
        };
 
@@ -71,8 +71,8 @@ public:
        void read_channel_data(bigendian_file_input_stream&);
 
        const std::wstring& name() const;
-       std::uint8_t opacity() const;
-       std::uint16_t sheet_color() const;
+       int opacity() const;
+       int sheet_color() const;
        bool is_visible();
        bool is_position_protected();
 
@@ -86,7 +86,7 @@ public:
        bool has_timeline() const;
        const boost::property_tree::wptree& timeline_data() const;
 
-       const point<std::int32_t>& location() const;
+       const point<int>& location() const;
        const image8bit_ptr& bitmap() const;
 
        int link_group_id() const;
index 909b2f567d6bec9f8b9d6b8e339bb3b3b8ee7d1f..0dac03eca119a2b1299236bc903a081742b38ca3 100644 (file)
 namespace caspar { namespace psd {
 
 psd_document::psd_document()
-       : channels_(0)
-       , width_(0)
-       , height_(0)
-       , depth_(0)
-       , color_mode_(psd::color_mode::InvalidColorMode)
 {
 }
 
 void psd_document::parse(const std::wstring& filename)
 {
+       // Most of the parsing here is based on information from http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/
        filename_ = filename;
        input_.open(filename_);
        read_header();
@@ -101,7 +97,7 @@ void psd_document::read_image_resources()
                                                        int layer_count = resource_length / 2;
                                                        for(int i = 0; i < layer_count; ++i)
                                                        {
-                                                               std::int16_t id = input_.read_short();
+                                                               int id = static_cast<std::int16_t>(input_.read_short());
 
                                                                if(i == layers_.size())
                                                                        layers_.push_back(std::make_shared<layer>());
@@ -194,7 +190,7 @@ void psd_document::read_layers()
                        auto layer_info_length = input_.read_long();    //length of "Layer info" section
                        auto end_of_layers_info = input_.current_position() + layer_info_length;
 
-                       auto layers_count = std::abs(static_cast<std::int16_t>(input_.read_short()));
+                       int layers_count = std::abs(static_cast<std::int16_t>(input_.read_short()));
                        //std::clog << "Expecting " << layers_count << " layers" << std::endl;
 
                        for(int layer_index = 0; layer_index < layers_count; ++layer_index)
index a0b29cbdf4c65f3a44ae13c93f1cd1ed94f81f27..6836bf4d630a4139c1815a133a2a1d6c8b98c44d 100644 (file)
@@ -42,11 +42,13 @@ public:
        {
                return layers_;
        }
-       std::uint32_t width() const
+
+       int width() const
        {
                return width_;
        }
-       std::uint32_t height() const
+
+       int height() const
        {
                return height_;
        }
@@ -56,28 +58,31 @@ public:
                return color_mode_;
        }
 
-       std::uint16_t color_depth() const
+       int color_depth() const
        {
                return depth_;
        }
-       std::uint16_t channels_count() const
+
+       int channels_count() const
        {
                return channels_;
        }
+
        const std::wstring& filename() const
        {
                return filename_;
        }
+
        bool has_timeline() const
        {
                return !timeline_desc_.empty();
        }
+
        const boost::property_tree::wptree& timeline() const 
        {
                return timeline_desc_;
        }
 
-
        void parse(const std::wstring& s);
 
 private:
@@ -91,11 +96,11 @@ private:
 
        std::vector<layer_ptr>                  layers_;
 
-       std::uint16_t                                   channels_;
-       std::uint32_t                                   width_;
-       std::uint32_t                                   height_;
-       std::uint16_t                                   depth_;
-       psd::color_mode                                 color_mode_;
+       int                                                             channels_               = 0;
+       int                                                             width_                  = 0;
+       int                                                             height_                 = 0;
+       int                                                             depth_                  = 0;
+       psd::color_mode                                 color_mode_             = psd::color_mode::InvalidColorMode;
        boost::property_tree::wptree    timeline_desc_;
 };
 
index 950a4bc1ea2cc59ca93c0377c38b39190863c2a3..b52d980147d38208eb71826c17b8f97669cdf666 100644 (file)
@@ -110,19 +110,20 @@ void bigendian_file_input_stream::discard_bytes(std::streamoff length)
 {
        ifs_.seekg(length, std::ios_base::cur);
 }
+
 void bigendian_file_input_stream::discard_to_next_word()
 {
-       const std::uint8_t padding = 2;
-       discard_bytes((padding - (current_position() % padding)) % padding);
+       const int PADDING = 2;
+       discard_bytes((PADDING - (current_position() % PADDING)) % PADDING);
 }
 
 void bigendian_file_input_stream::discard_to_next_dword()
 {
-       const std::uint8_t padding = 4;
-       discard_bytes((padding - (current_position() % padding)) % padding);
+       const int PADDING = 4;
+       discard_bytes((PADDING - (current_position() % PADDING)) % PADDING);
 }
 
-std::wstring bigendian_file_input_stream::read_pascal_string(std::uint8_t padding)
+std::wstring bigendian_file_input_stream::read_pascal_string(int padding)
 {
        char buffer[256];
 
@@ -139,7 +140,7 @@ std::wstring bigendian_file_input_stream::read_pascal_string(std::uint8_t paddin
 
 std::wstring bigendian_file_input_stream::read_unicode_string()
 {
-       auto length = read_long();
+       int length = read_long();
        std::wstring result;
 
        if(length > 0)
@@ -147,7 +148,7 @@ std::wstring bigendian_file_input_stream::read_unicode_string()
                result.reserve(length);
 
                //can be optimized. Reads and swaps byte-order, one char at the time
-               for (std::uint32_t i = 0; i < length; ++i)
+               for (int i = 0; i < length; ++i)
                        result.append(1, static_cast<wchar_t>(read_short()));
        }
 
@@ -157,13 +158,13 @@ std::wstring bigendian_file_input_stream::read_unicode_string()
 std::wstring bigendian_file_input_stream::read_id_string()
 {
        std::string result;
-       auto length = read_long();
+       int length = read_long();
        
        if(length > 0)
        {
                result.reserve(length);
 
-               for (std::uint32_t i = 0; i < length; ++i)
+               for (int i = 0; i < length; ++i)
                        result.append(1, read_byte());
        }
        else
index e602111e0f747dac9df124eaf42aefc07f4b61ac..eb70a85b02cc37ee3401e50acf59f1c57f1af246 100644 (file)
@@ -45,7 +45,7 @@ public:
        std::uint8_t read_byte();
        std::uint16_t read_short();
        std::uint32_t read_long();
-       std::wstring read_pascal_string(std::uint8_t padding = 1);
+       std::wstring read_pascal_string(int padding = 1);
        std::wstring read_unicode_string();
        std::wstring read_id_string();
        double read_double();
index d9766448e3a28929a20b79e05bb24c1ccf7381c5..ee63bae181100c6350e6ac2ed3b5e44abcdb23ef 100644 (file)
@@ -258,9 +258,9 @@ struct pdf_grammar : qi::grammar<Iterator, qi::space_type>
        };
 };
 
-bool read_pdf(boost::property_tree::wptree& tree, const std::wstring& s)
+bool read_pdf(boost::property_tree::wptree& tree, const std::string& s)
 {
-       typedef std::wstring::const_iterator iterator_type;
+       typedef std::string::const_iterator iterator_type;
 
        pdf_grammar<iterator_type> g;
        bool result = false;
index 5c3cb68e9bea4b9385508d043be9dbd7afd8a686..5b48ef9377063b19bd552d7a2f8cd060b6d5dbd5 100644 (file)
@@ -26,7 +26,7 @@
 
 namespace caspar { namespace psd { 
 
-bool read_pdf(boost::property_tree::wptree& tree, const std::wstring& s);
+bool read_pdf(boost::property_tree::wptree& tree, const std::string& s);
 
 }      //namespace psd
 }      //namespace caspar