Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

layer.type.styles doesn't work #92

Open
jacr1102 opened this issue Jan 21, 2016 · 2 comments
Open

layer.type.styles doesn't work #92

jacr1102 opened this issue Jan 21, 2016 · 2 comments

Comments

@jacr1102
Copy link

I'm reading some PSDs and when i try to get the font I get this, instead of the color and family font, I get empty values

        psd.tree.descendant_layers.each do |l|
          next unless l.text
                      l.type.styles # {}
                     l.text # {
      :value => "www.websiteforge.com\n",
       :font => {
      :name => nil,
     :sizes => [],
    :colors => [
      [0] [
        [0] 0,
        [1] 0,
        [2] 0,
        [3] 255
      ]
    ],
       :css => "font-family: ;\nfont-size: pt;\ncolor: rgba(0, 0, 0, 255);"
  },
       :left => 0,
        :top => 0,
      :right => 0,
     :bottom => 0,
  :transform => {
    :xx => 1.0,
    :xy => 0.0,
    :yx => 0.0,
    :yy => 1.0,
    :tx => 84.0,
    :ty => 565.0
  }
}


        end

this is the sample psd https://www.dropbox.com/s/0bb8k8zgnqukpz2/textos.psd?dl=0

@neohunter
Copy link

There is an error when reading EngineData on the other gem

They define strings content with this regex

Regexp.new('^\(\xFE\xFF(.*)\)$'.force_encoding('binary')); end

but it doesn't match the current data. when an error is raised the whole engineData parsing is stopped, and you end without any information.

This can be fixed using this regex instead

Regexp.new('\(˛ˇ(.*)\)$'.force_encoding('binary'))

but this raise a new error due to incompatible encoding on EngineData::Instruction::String the way to solve this is forcing encoding to binary on the text.

After this, the execute! method on EngineData::Instruction::String is doing some encoding transformation that is also breaking the string, not sure what is the purpose of this code

       data
              .force_encoding('UTF-16BE')
              .encode('UTF-8', 'UTF-16BE', universal_newline: true)
              .strip

After this, # enginedata.rb on parse_tokens method tries to match using Instructions::String class text + @text.next that if is a bytes stream is not encoding on binary, that raise incompatible encoding error and break the parse logic.

There is also some other issues...

but, if you want a workaround for this, use this monkey patching:

# -*- encoding : utf-8 -*-

class PSD
  class EngineData
    class Text
      # enginedata.rb on parse_tokens method tries to match using 
      # Instructions::String class @text.next is not encoding on binary
      # that raise an error and break the parse logic
      alias_method :orig_current, :current
      def current
        t = orig_current
        t ? orig_current.force_encoding('binary') : nil
      end
      def next
        r = @text[@line + 1]
        r ? r.force_encoding('binary') : nil
      end
    end


    # if the original method raise an error, it breaks the whole
    # engine_data parsing
    alias_method :orig_parse_tokens, :parse_tokens
    def parse_tokens(text)
      orig_parse_tokens(text)
    rescue => e
      puts "----------------------------"
      puts e.message
      puts "Parse_token error: #{text}"
      puts e.backtrace.join "\n"
    end

    class Instruction
      def self.match(text)
        begin
          token.match(text.force_encoding('binary'))
        rescue Encoding::CompatibilityError
          puts "rescueing from encoding compatibility error #{text}"
          nil
        end
      end
      class String < Instruction
        def execute!
          data = self.class.token.match(
            @text.force_encoding('binary')
          )[1]

          data.gsub! "\r", ""

          return data

          # I'm not sure what is the purpose of this, is in the original method
          # this is not executed as is after a return, just to remember to check this 
          begin
            data
              .force_encoding('UTF-16BE')
              .encode('UTF-8', 'UTF-16BE', universal_newline: true)
              .strip
          rescue
            data
          end
        end

        class << self

            def token; 
            Regexp.new('\(˛ˇ(.*)\)$'.force_encoding('binary'))
                # Regexp.new('^\(\xFE\xFF(.*)\)$'.force_encoding('binary'));  
            end

          alias_method :orig_match, :match
            def match(text)
            begin
              token.match(text.force_encoding('binary'))
            rescue Encoding::CompatibilityError
              puts "rescueing from encoding compatibility error #{text}"
              nil
            end
            end
         end
      end
    end
  end
end

Aparently this affectects this gem also because if you check the typetool.rb file, it has this (check comment):

def text_value
      if engine_data.nil?
        # Something went wrong, lets hack our way through.
        /\/Text \(˛ˇ(.*)\)$/.match(@data[:text]['EngineData'])[1].gsub /\r/, "\n"
      else
        engine_data.EngineDict.Editor.Text
      end
end

My monkey patch works as a workaround. I'm not submitting a merge request because I don't know the PSD format well enought to submit a descent solution.

@jeffmcfadden
Copy link

@neohunter Thanks for the patch, it's working for me on the PSD I'm working with at the moment. Are you aware of any major side effects of the patch that I might want to know about?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants