imogen 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/lib/imogen/auto_crop/box.rb +79 -0
- data/lib/imogen/auto_crop/edges.rb +63 -0
- data/lib/imogen/auto_crop.rb +20 -0
- data/lib/imogen/zoomable.rb +15 -0
- data/lib/imogen.rb +106 -0
- metadata +75 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            !binary "U0hBMQ==":
         | 
| 3 | 
            +
              metadata.gz: !binary |-
         | 
| 4 | 
            +
                NzMwYzg4MjlkMjE0MDBmYjYzMWZlZTZiOGZkYzcyYmE3OGU0YmQ2Yg==
         | 
| 5 | 
            +
              data.tar.gz: !binary |-
         | 
| 6 | 
            +
                NTYzYjQ3ZDMyMzJjMjU1ODAxNmUyNDU4Mjc3YTFjZjY1NmIyYTM5Yw==
         | 
| 7 | 
            +
            SHA512:
         | 
| 8 | 
            +
              metadata.gz: !binary |-
         | 
| 9 | 
            +
                MmMwZWM3MDE1ZDlmZTU5Y2U3YjQ4ZWE0ZDIxMzc2ODc3NGM0NmVhYzg2YTdk
         | 
| 10 | 
            +
                MmFiY2I4OTA2MGJkNmJlYmUxNWVlMGQ4MzZmZTQ1Yjg0ZjIwNTc3MDgyNjVh
         | 
| 11 | 
            +
                ZGVmZTMxOGMxODc1YzBjMmI4ODU1YTkzZjdhNmYwM2JlNzYxYjc=
         | 
| 12 | 
            +
              data.tar.gz: !binary |-
         | 
| 13 | 
            +
                OTU3MWQ4MjI3NWY1ODAzNjQzZTg5YmI4MGMyZTU5MDYxOWI2MDAzZTgxODAz
         | 
| 14 | 
            +
                YjlhYjQwOWUwN2ZjZGFmYjcxM2U0ODdiOTM1Njg3OGYxYjNhNTc3OTg3MGMw
         | 
| 15 | 
            +
                NmNhZjc3YTQ2NGIwOWM0ZmRlNDY4N2RiMGEzOWJhMGNlOGYyODE=
         | 
| @@ -0,0 +1,79 @@ | |
| 1 | 
            +
            #!ruby
         | 
| 2 | 
            +
            require 'opencv'
         | 
| 3 | 
            +
            module Imogen::AutoCrop::Box
         | 
| 4 | 
            +
              include OpenCV
         | 
| 5 | 
            +
              class Best
         | 
| 6 | 
            +
                def initialize(grayscale)
         | 
| 7 | 
            +
                  @corners = grayscale.good_features_to_track(0.3, 1.0, block_size: 3, max: 20)
         | 
| 8 | 
            +
                  if @corners.nil? or @corners.length == 0
         | 
| 9 | 
            +
                    @center = Center.new(grayscale)
         | 
| 10 | 
            +
                  else
         | 
| 11 | 
            +
                    @center = nil
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def self.distance(p1, p2)
         | 
| 16 | 
            +
                  dx = p1.x.to_i - p2.x.to_i
         | 
| 17 | 
            +
                  dy = p1.y.to_i - p2.y.to_i
         | 
| 18 | 
            +
                  return Math.sqrt((dx * dx) + (dy * dy)) 
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def box()
         | 
| 22 | 
            +
                  return @center.box unless @center.nil?
         | 
| 23 | 
            +
                  c = median()
         | 
| 24 | 
            +
                  cp = BoxInfo.new(c[0], c[1],0)
         | 
| 25 | 
            +
                  total_distance = 0;
         | 
| 26 | 
            +
                  features = @corners.collect {|corner| d = Best.distance(corner, cp); total_distance += d; {x: corner.x, y: corner.y, d: d}}
         | 
| 27 | 
            +
                  mean_distance = total_distance/features.length
         | 
| 28 | 
            +
                  sigma = features.inject(0) {|memo, feature| v = feature[:d] - mean_distance; memo += (v*v)}
         | 
| 29 | 
            +
                  sigma = Math.sqrt(sigma.to_f/features.length)
         | 
| 30 | 
            +
                  # 2 sigmas would capture > 95% of normally distributed features
         | 
| 31 | 
            +
                  cp.radius = 2*sigma
         | 
| 32 | 
            +
                  cp
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def median()
         | 
| 36 | 
            +
                  @median ||= begin
         | 
| 37 | 
            +
                    xs = []
         | 
| 38 | 
            +
                    ys = []
         | 
| 39 | 
            +
                    @corners.each {|c| xs << c.x.to_i; ys << c.y.to_i}
         | 
| 40 | 
            +
                    xs.sort!
         | 
| 41 | 
            +
                    ys.sort!
         | 
| 42 | 
            +
                    ix = 0
         | 
| 43 | 
            +
                    if (@corners.length % 2 == 0)
         | 
| 44 | 
            +
                      l = (@corners.length == 2) ? 0 : (@corners.length/2)
         | 
| 45 | 
            +
                      x = ((xs[l] + xs[l+1]) /2).floor
         | 
| 46 | 
            +
                      y = ((ys[l] + ys[l+1]) /2).floor
         | 
| 47 | 
            +
                      [x,y]
         | 
| 48 | 
            +
                    else
         | 
| 49 | 
            +
                      r = (@corners.length/2).ceil
         | 
| 50 | 
            +
                      [xs[r], ys[r]]
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
              class Center
         | 
| 56 | 
            +
                def initialize(grayscale)
         | 
| 57 | 
            +
                  @center ||= [(grayscale.cols/2).floor, (grayscale.rows/2).floor]
         | 
| 58 | 
            +
                  @radius = @center.min
         | 
| 59 | 
            +
                  @ratio = @radius / @center.max
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
                def box
         | 
| 62 | 
            +
                  return BoxInfo.new(@center[0],@center[1],@radius)
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
              class BoxInfo
         | 
| 66 | 
            +
                attr_reader :x, :y
         | 
| 67 | 
            +
                attr_accessor :radius
         | 
| 68 | 
            +
                def initialize(x,y,r)
         | 
| 69 | 
            +
                  @x = x
         | 
| 70 | 
            +
                  @y = y
         | 
| 71 | 
            +
                  @radius = r
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
              def self.info(grayscale)
         | 
| 75 | 
            +
                dims = [grayscale.cols, grayscale.rows]
         | 
| 76 | 
            +
                ratio = dims.min / dims.max
         | 
| 77 | 
            +
                ratio < 0.84 ? Best.new(grayscale).box() : Center.new(grayscale).box()
         | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
            end
         | 
| @@ -0,0 +1,63 @@ | |
| 1 | 
            +
            #!ruby
         | 
| 2 | 
            +
            require 'opencv'
         | 
| 3 | 
            +
            require 'free-image'
         | 
| 4 | 
            +
            require 'tempfile'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Imogen::AutoCrop
         | 
| 7 | 
            +
            class Edges
         | 
| 8 | 
            +
              include OpenCV
         | 
| 9 | 
            +
              def initialize(src)
         | 
| 10 | 
            +
                @xoffset = 0
         | 
| 11 | 
            +
                @yoffset = 0
         | 
| 12 | 
            +
                if src.is_a? FreeImage::Bitmap
         | 
| 13 | 
            +
                  img = src
         | 
| 14 | 
            +
                  @xoffset = img.width.to_f/6
         | 
| 15 | 
            +
                  @yoffset = img.height.to_f/6
         | 
| 16 | 
            +
                  @tempfile = Tempfile.new(['crop','.png'])
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  img.copy(@xoffset,@yoffset,img.width-@xoffset,img.height-@yoffset) do |crop|
         | 
| 19 | 
            +
                    crop.save(@tempfile.path, :png)
         | 
| 20 | 
            +
                    crop.free
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
                else
         | 
| 23 | 
            +
                  raise src.class.name 
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
                # use bigger features on bigger images
         | 
| 26 | 
            +
                @grayscale = CvMat.load(@tempfile.path, CV_LOAD_IMAGE_GRAYSCALE)
         | 
| 27 | 
            +
                @xrange = (0..@grayscale.cols)
         | 
| 28 | 
            +
                @yrange = (0..@grayscale.rows)
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              def bound_min(center)
         | 
| 32 | 
            +
                [center.x - @xrange.min, @xrange.max - center.x, center.y - @yrange.min, @yrange.max - center.y].min
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              # returns leftX, topY, rightX, bottomY
         | 
| 36 | 
            +
              def get(*args)
         | 
| 37 | 
            +
                c = Imogen::AutoCrop::Box.info(@grayscale)
         | 
| 38 | 
            +
                r = c.radius.floor
         | 
| 39 | 
            +
                # adjust the box
         | 
| 40 | 
            +
                coords = [c.x, c.y]
         | 
| 41 | 
            +
                min_rad = args.max/2
         | 
| 42 | 
            +
                unless r >= min_rad && r <= bound_min(c)
         | 
| 43 | 
            +
                  # first adjust to the lesser of max (half short dimension) and min (half requested length) radius
         | 
| 44 | 
            +
                  # this might require upscaling in rare situations to preserve bound safety
         | 
| 45 | 
            +
                  r = min_rad if r < min_rad
         | 
| 46 | 
            +
                  max_rad = [@xrange.max - @xrange.min, @yrange.max - @yrange.min].min / 2
         | 
| 47 | 
            +
                  r = max_rad if r > max_rad
         | 
| 48 | 
            +
                  # now move the center point minimally to accomodate the necessary radius
         | 
| 49 | 
            +
                  coords[0] = @xrange.max - r if (coords[0] + r) > @xrange.max  
         | 
| 50 | 
            +
                  coords[0] = @xrange.min + r if (coords[0] - r) < @xrange.min  
         | 
| 51 | 
            +
                  coords[1] = @yrange.max - r if (coords[1] + r) > @yrange.max  
         | 
| 52 | 
            +
                  coords[1] = @yrange.min + r if (coords[1] - r) < @yrange.min  
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
                coords = [coords[0] + @xoffset, coords[1] + @yoffset].collect {|i| i.floor}
         | 
| 55 | 
            +
                c = coords
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                return [c[0]-r, c[1]-r, c[0]+r, c[1] + r]
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
              def unlink
         | 
| 60 | 
            +
                @tempfile.unlink
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
            end
         | 
| 63 | 
            +
            end
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            module Imogen
         | 
| 2 | 
            +
              module AutoCrop
         | 
| 3 | 
            +
                autoload :Edges, 'imogen/auto_crop/edges'
         | 
| 4 | 
            +
                autoload :Box, 'imogen/auto_crop/box'
         | 
| 5 | 
            +
                def self.convert(img, dest_path, scale=768, format=:jpeg)
         | 
| 6 | 
            +
                  frame = Edges.new(img)
         | 
| 7 | 
            +
                  edges = frame.get(scale)
         | 
| 8 | 
            +
                  img.copy(*edges) do |crop|
         | 
| 9 | 
            +
                    crop.rescale(scale, scale) do |thumb|
         | 
| 10 | 
            +
                      t24 = thumb.convert_to_24bits
         | 
| 11 | 
            +
                      dst = FreeImage::File.new(dest_path)
         | 
| 12 | 
            +
                      dst.save(t24, format)
         | 
| 13 | 
            +
                      t24.free
         | 
| 14 | 
            +
                      thumb.free
         | 
| 15 | 
            +
                    end
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                  frame.unlink
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            #require 'image_science'
         | 
| 2 | 
            +
            module Imogen
         | 
| 3 | 
            +
            	module Zoomable
         | 
| 4 | 
            +
                def self.levels_for(*dims)
         | 
| 5 | 
            +
                  max = dims[0..1].max || 0
         | 
| 6 | 
            +
                  return 0 if max < 192
         | 
| 7 | 
            +
                  max_tiles = (max.to_f / 96)
         | 
| 8 | 
            +
                  Math.log2(max_tiles).floor
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
                def self.convert(img, dest_path)
         | 
| 11 | 
            +
                  dst = FreeImage::File.new(dest_path)
         | 
| 12 | 
            +
                  dst.save(img, :jp2, 8)
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
    
        data/lib/imogen.rb
    ADDED
    
    | @@ -0,0 +1,106 @@ | |
| 1 | 
            +
            # encoding: UTF-8
         | 
| 2 | 
            +
            require 'ffi'
         | 
| 3 | 
            +
            require 'rbconfig'
         | 
| 4 | 
            +
            require 'free-image'
         | 
| 5 | 
            +
            module Imogen
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              def self.from(src_path)
         | 
| 8 | 
            +
                FreeImage::Bitmap.open(src_path) do |img|
         | 
| 9 | 
            +
                  yield img
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
              module Scaled
         | 
| 13 | 
            +
                def self.convert(img, dest_path, scale=1500, format = :jpeg)
         | 
| 14 | 
            +
                  w = img.width
         | 
| 15 | 
            +
                  h = img.height
         | 
| 16 | 
            +
                  dims = (w > h) ? [1500, 1500*h/w] : [1500*w/h, 1500]
         | 
| 17 | 
            +
                  img.rescale(dims[0], dims[1]) do |scaled|
         | 
| 18 | 
            +
                    scaled = scaled.convert_to_24bits
         | 
| 19 | 
            +
                    dst = FreeImage::File.new(dest_path)
         | 
| 20 | 
            +
                    dst.save(scaled, format)
         | 
| 21 | 
            +
                    scaled.free
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
              require 'imogen/auto_crop'
         | 
| 26 | 
            +
              require 'imogen/zoomable'
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              def self.search_paths
         | 
| 29 | 
            +
                @search_paths ||= begin
         | 
| 30 | 
            +
                  if ENV['FREE_IMAGE_LIBRARY_PATH']
         | 
| 31 | 
            +
                    [ ENV['FREE_IMAGE_LIBRARY_PATH'] ]
         | 
| 32 | 
            +
                  elsif FFI::Platform::IS_WINDOWS
         | 
| 33 | 
            +
                    ENV['PATH'].split(File::PATH_SEPARATOR)
         | 
| 34 | 
            +
                  else
         | 
| 35 | 
            +
                    [ '/usr/local/{lib64,lib32,lib}', '/opt/local/{lib64,lib32,lib}', '/usr/{lib64,lib32,lib}' ]
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              def self.find_lib(lib)
         | 
| 41 | 
            +
                files = search_paths.inject(Array.new) do |array, path|
         | 
| 42 | 
            +
                  file_name = File.expand_path(File.join(path, "#{lib}.#{FFI::Platform::LIBSUFFIX}"))
         | 
| 43 | 
            +
                  array << Dir.glob(file_name)
         | 
| 44 | 
            +
                  array
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
                files.flatten.compact.first
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              def self.free_image_library_paths
         | 
| 50 | 
            +
                @free_image_library_paths ||= begin
         | 
| 51 | 
            +
                  libs = %w{libfreeimage libfreeimage.3 FreeImage}
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  libs.map do |lib|
         | 
| 54 | 
            +
                    find_lib(lib)
         | 
| 55 | 
            +
                  end.compact
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
              extend ::FFI::Library
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              if free_image_library_paths.any?
         | 
| 62 | 
            +
                ffi_lib(*free_image_library_paths)
         | 
| 63 | 
            +
              elsif FFI::Platform.windows?
         | 
| 64 | 
            +
                ffi_lib("FreeImaged")
         | 
| 65 | 
            +
              else
         | 
| 66 | 
            +
                ffi_lib("freeimage")
         | 
| 67 | 
            +
              end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
              ffi_convention :stdcall if FFI::Platform.windows?
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              def self.format_from(image_path)
         | 
| 72 | 
            +
                result = FreeImage.FreeImage_GetFileType(image_path, 0)
         | 
| 73 | 
            +
                FreeImage.check_last_error
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                if result == :unknown
         | 
| 76 | 
            +
                  # Try to guess the file format from the file extension
         | 
| 77 | 
            +
                  result = FreeImage.FreeImage_GetFIFFromFilename(image_path)
         | 
| 78 | 
            +
                  FreeImage.check_last_error
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
                result
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
              def self.image(src_path)
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                flags = 0
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                fif = format_from(src_path)
         | 
| 88 | 
            +
                if ((fif != :unknown) and FreeImage.FreeImage_FIFSupportsReading(fif))
         | 
| 89 | 
            +
                  ptr = FreeImage.FreeImage_Load(fif, src_path, flags)
         | 
| 90 | 
            +
                  FreeImage.check_last_error
         | 
| 91 | 
            +
                  return FreeImage::Bitmap.new(ptr, nil)
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
                return nil
         | 
| 94 | 
            +
              end
         | 
| 95 | 
            +
              def self.with_image(src_path, &block)
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                flags = 0
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                fif = format_from(src_path)
         | 
| 100 | 
            +
                if ((fif != :unknown) and FreeImage.FreeImage_FIFSupportsReading(fif))
         | 
| 101 | 
            +
                  ptr = FreeImage.FreeImage_Load(fif, src_path, flags)
         | 
| 102 | 
            +
                  FreeImage.check_last_error
         | 
| 103 | 
            +
                  FreeImage::Bitmap.new(ptr, nil, &block)
         | 
| 104 | 
            +
                end
         | 
| 105 | 
            +
              end
         | 
| 106 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,75 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: imogen
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.0.3
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Ben Armintor
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2014-08-12 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: ruby-opencv
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - ! '>='
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '0'
         | 
| 20 | 
            +
              type: :runtime
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - ! '>='
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '0'
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: rspec
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - ! '>='
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: '0'
         | 
| 34 | 
            +
              type: :development
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - ! '>='
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: '0'
         | 
| 41 | 
            +
            description: 
         | 
| 42 | 
            +
            email: armintor@gmail.com
         | 
| 43 | 
            +
            executables: []
         | 
| 44 | 
            +
            extensions: []
         | 
| 45 | 
            +
            extra_rdoc_files: []
         | 
| 46 | 
            +
            files:
         | 
| 47 | 
            +
            - lib/imogen.rb
         | 
| 48 | 
            +
            - lib/imogen/auto_crop.rb
         | 
| 49 | 
            +
            - lib/imogen/auto_crop/box.rb
         | 
| 50 | 
            +
            - lib/imogen/auto_crop/edges.rb
         | 
| 51 | 
            +
            - lib/imogen/zoomable.rb
         | 
| 52 | 
            +
            homepage: https://github.com/cul/imogen
         | 
| 53 | 
            +
            licenses: []
         | 
| 54 | 
            +
            metadata: {}
         | 
| 55 | 
            +
            post_install_message: 
         | 
| 56 | 
            +
            rdoc_options: []
         | 
| 57 | 
            +
            require_paths:
         | 
| 58 | 
            +
            - lib
         | 
| 59 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 60 | 
            +
              requirements:
         | 
| 61 | 
            +
              - - ! '>='
         | 
| 62 | 
            +
                - !ruby/object:Gem::Version
         | 
| 63 | 
            +
                  version: '0'
         | 
| 64 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
              requirements:
         | 
| 66 | 
            +
              - - ! '>='
         | 
| 67 | 
            +
                - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                  version: '0'
         | 
| 69 | 
            +
            requirements: []
         | 
| 70 | 
            +
            rubyforge_project: 
         | 
| 71 | 
            +
            rubygems_version: 2.2.2
         | 
| 72 | 
            +
            signing_key: 
         | 
| 73 | 
            +
            specification_version: 4
         | 
| 74 | 
            +
            summary: derivative generation via FreeImage and smart square thumbnail via OpenCV
         | 
| 75 | 
            +
            test_files: []
         |