class Origami::Graphics::ImageXObject
Public Class Methods
from_image_file(path, format = nil)
click to toggle source
# File lib/origami/graphics/xobject.rb, line 657 def self.from_image_file(path, format = nil) if path.respond_to?(:read) data = fd.read else data = File.binread(File.expand_path(path)) format ||= File.extname(path)[1..-1] end image = ImageXObject.new raise ArgumentError, "Missing file format" if format.nil? case format.downcase when 'jpg', 'jpeg', 'jpe', 'jif', 'jfif', 'jfi' image.setFilter :DCTDecode image.encoded_data = data when 'jp2','jpx','j2k','jpf','jpm','mj2' image.setFilter :JPXDecode image.encoded_data = data when '.b2', 'jbig', 'jbig2' image.setFilter :JBIG2Decode image.encoded_data = data else raise NotImplementedError, "Unknown file format: '#{format}'" end image end
Public Instance Methods
to_image_file()
click to toggle source
Converts an ImageXObject
stream into an image file data. Output format depends on the stream encoding:
* JPEG for DCTDecode * JPEG2000 for JPXDecode * JBIG2 for JBIG2Decode * PNG for everything else Returns an array of the form [ _format_, _data_ ]
# File lib/origami/graphics/xobject.rb, line 697 def to_image_file encoding = self.Filter encoding = encoding[0] if encoding.is_a? ::Array case (encoding && encoding.value) when :DCTDecode then return [ 'jpg', self.data ] when :JBIG2Decode then return [ 'jbig2', self.data ] when :JPXDecode then return [ 'jp2', self.data ] end # Assume PNG data. raise InvalidColorError, "No colorspace specified" unless self.ColorSpace case cs = self.ColorSpace.value when Color::Space::DEVICE_GRAY color_type = 0 components = 1 when Color::Space::DEVICE_RGB color_type = 2 components = 3 when ::Array cs_type = cs[0] case cs_type when :Indexed color_type = 3 components = 3 cs_base = cs[1] lookup = cs[3] when :ICCBased icc_profile = cs[1] raise InvalidColorError, "Invalid ICC Profile parameter" unless icc_profile.is_a?(Stream) case icc_profile.N when 1 color_type = 0 components = 1 when 3 color_type = 2 components = 3 else raise InvalidColorError, "Invalid number of components in ICC profile: #{icc_profile.N}" end else raise InvalidColorError, "Unsupported color space: #{self.ColorSpace}" end else raise InvalidColorError, "Unsupported color space: #{self.ColorSpace}" end bpc = self.BitsPerComponent || 8 w, h = self.Width, self.Height pixels = self.data hdr = [137, 80, 78, 71, 13, 10, 26, 10].pack('C*') chunks = [] chunks << [ 'IHDR', [ w, h, bpc, color_type, 0, 0, 0 ].pack("N2C5") ] if self.Intents intents = case self.Intents.value when Intents::PERCEPTUAL then 0 when Intents::RELATIVE then 1 when Intents::SATURATION then 2 when Intents::ABSOLUTE then 3 else 3 end chunks << [ 'sRGB', [ intents ].pack('C') ] chunks << [ 'gAMA', [ 45455 ].pack("N") ] chunks << [ 'cHRM', [ 31270, 32900, 64000, 33000, 30000, 60000, 15000, 6000 ].pack("N8") ] end if color_type == 3 lookup = case lookup when Stream then lookup.data when String then lookup.value else raise InvalidColorError, "Invalid indexed palette table" end raise InvalidColorError, "Invalid base color space" unless cs_base palette = "" case cs_base when Color::Space::DEVICE_GRAY lookup.each_byte do |g| palette << Color.gray_to_rgb(g).pack("C3") end when Color::Space::DEVICE_RGB palette << lookup[0, (lookup.size / 3) * 3] when Color::Space::DEVICE_CMYK (lookup.size / 4).times do |i| cmyk = lookup[i * 4, 4].unpack("C4").map!{|c| c.to_f / 255} palette << Color.cmyk_to_rgb(*cmyk).map!{|c| (c * 255).to_i}.pack("C3") end when ::Array case cs_base[0] when :ICCBased icc_profile = cs_base[1] raise InvalidColorError, "Invalid ICC Profile parameter" unless icc_profile.is_a?(Stream) case icc_profile.N when 1 lookup.each_byte do |g| palette << Color.gray_to_rgb(g).pack("C3") end when 3 palette << lookup[0, (lookup.size / 3) * 3] else raise InvalidColorError, "Invalid number of components in ICC profile: #{icc_profile.N}" end else raise InvalidColorError, "Unsupported color space: #{cs_base}" end else raise InvalidColorError, "Unsupported color space: #{cs_base}" end if icc_profile chunks << [ 'iCCP', 'ICC Profile' + "\x00\x00" + Zlib::Deflate.deflate(icc_profile.data, Zlib::BEST_COMPRESSION) ] end chunks << [ 'PLTE', palette ] bpr = w else # color_type != 3 if icc_profile chunks << [ 'iCCP', 'ICC Profile' + "\x00\x00" + Zlib::Deflate.deflate(icc_profile.data, Zlib::BEST_COMPRESSION) ] end bpr = (bpc >> 3) * components * w end nrows = pixels.size / bpr nrows.times do |irow| pixels.insert(irow * bpr + irow, "\x00") end chunks << [ 'IDAT', Zlib::Deflate.deflate(pixels, Zlib::BEST_COMPRESSION) ] if self.Metadata.is_a?(Stream) chunks << [ 'tEXt', "XML:com.adobe.xmp" + "\x00" + self.Metadata.data ] end chunks << [ 'IEND', '' ] [ 'png', hdr + chunks.map!{ |chk| [ chk[1].size, chk[0], chk[1], Zlib.crc32(chk[0] + chk[1]) ].pack("NA4A*N") }.join ] end