riiif 0.0.1 → 0.0.2
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 +4 -4
- data/README.md +25 -0
- data/app/controllers/riiif/images_controller.rb +26 -0
- data/app/models/riiif/file.rb +87 -0
- data/app/models/riiif/image.rb +16 -36
- data/app/views/riiif/images/view.html.erb +21 -0
- data/config/routes.rb +5 -1
- data/lib/riiif.rb +1 -0
- data/lib/riiif/file_system_file_resolver.rb +1 -1
- data/lib/riiif/http_file_resolver.rb +24 -0
- data/lib/riiif/version.rb +1 -1
- data/riiif.gemspec +1 -2
- data/spec/controllers/images_controller_spec.rb +17 -0
- data/spec/models/image_spec.rb +45 -33
- data/spec/routing/resize_routes_spec.rb +26 -6
- data/vendor/assets/images/openseadragon/fullpage_grouphover.png +0 -0
- data/vendor/assets/images/openseadragon/fullpage_hover.png +0 -0
- data/vendor/assets/images/openseadragon/fullpage_pressed.png +0 -0
- data/vendor/assets/images/openseadragon/fullpage_rest.png +0 -0
- data/vendor/assets/images/openseadragon/home_grouphover.png +0 -0
- data/vendor/assets/images/openseadragon/home_hover.png +0 -0
- data/vendor/assets/images/openseadragon/home_pressed.png +0 -0
- data/vendor/assets/images/openseadragon/home_rest.png +0 -0
- data/vendor/assets/images/openseadragon/next_grouphover.png +0 -0
- data/vendor/assets/images/openseadragon/next_hover.png +0 -0
- data/vendor/assets/images/openseadragon/next_pressed.png +0 -0
- data/vendor/assets/images/openseadragon/next_rest.png +0 -0
- data/vendor/assets/images/openseadragon/previous_grouphover.png +0 -0
- data/vendor/assets/images/openseadragon/previous_hover.png +0 -0
- data/vendor/assets/images/openseadragon/previous_pressed.png +0 -0
- data/vendor/assets/images/openseadragon/previous_rest.png +0 -0
- data/vendor/assets/images/openseadragon/zoomin_grouphover.png +0 -0
- data/vendor/assets/images/openseadragon/zoomin_hover.png +0 -0
- data/vendor/assets/images/openseadragon/zoomin_pressed.png +0 -0
- data/vendor/assets/images/openseadragon/zoomin_rest.png +0 -0
- data/vendor/assets/images/openseadragon/zoomout_grouphover.png +0 -0
- data/vendor/assets/images/openseadragon/zoomout_hover.png +0 -0
- data/vendor/assets/images/openseadragon/zoomout_pressed.png +0 -0
- data/vendor/assets/images/openseadragon/zoomout_rest.png +0 -0
- data/vendor/assets/javascripts/openseadragon.js +12279 -0
- metadata +30 -18
- data/spec/samples/world.jp2 +0 -0
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 2267ef01c3a2abbf3991710ef5c4c9f6ac55500c
         | 
| 4 | 
            +
              data.tar.gz: 13fc80e6e72c789bac048f66fc020d8a0cb2e314
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 0d45589ca6d5e13de6d7a40a61b09c48e9d062118c1845d9fd786e7d8f5066980d9e1adb8d1a4b1df7b419a6729248fec8bc8ea6338d0e9216324a94d9cec7eb
         | 
| 7 | 
            +
              data.tar.gz: 64600eb8e05f1f613b7a039ed6c25b36f5f87d75f1993b9dad667ae3eea9e47e5fe9b66200ef4a03f3fc96862e307cdc2adf936e69609206e02cd4014562553b
         | 
    
        data/README.md
    CHANGED
    
    | @@ -15,7 +15,32 @@ And then execute: | |
| 15 15 | 
             
            Or install it yourself as:
         | 
| 16 16 |  | 
| 17 17 | 
             
                $ gem install riiif
         | 
| 18 | 
            +
                
         | 
| 19 | 
            +
            ## Configure
         | 
| 18 20 |  | 
| 21 | 
            +
            ### Images on the servers file system.
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            By default Riiif is set to load images from the filesystem using the Riiif::FileSystemFileResolver. 
         | 
| 24 | 
            +
            You can configure how this resolver finds the files by setting this property:
         | 
| 25 | 
            +
            ```
         | 
| 26 | 
            +
                Riiif::FileSystemFileResolver.base_path = '/opt/repository/images/'
         | 
| 27 | 
            +
            ```
         | 
| 28 | 
            +
            When the Id passed in is "foo_image", then it will look for an image file using this glob: 
         | 
| 29 | 
            +
            ```
         | 
| 30 | 
            +
            /opt/repository/images/foo_image.{png,jpg,tiff,jp,jp2}
         | 
| 31 | 
            +
            ```
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            ### Images retrieved over HTTP
         | 
| 34 | 
            +
            To source the images from the network instead of the file system, we first configure Riiif to use an alternative resolver:
         | 
| 35 | 
            +
            ```
         | 
| 36 | 
            +
                  Riiif::Image.file_resolver = Riiif::HTTPFileResolver
         | 
| 37 | 
            +
            ```
         | 
| 38 | 
            +
            Then we configure the resolver with a mechanism for mapping the provided id to a url:
         | 
| 39 | 
            +
            ```
         | 
| 40 | 
            +
                  Riiif::HTTPFileResolver.id_to_uri = lambda do |id| 
         | 
| 41 | 
            +
                    "http://upload.wikimedia.org/wikipedia/commons/thumb/a/a4/#{id}.jpg/600px-#{id}.jpg"
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
            ```
         | 
| 19 44 | 
             
            ## Usage
         | 
| 20 45 |  | 
| 21 46 | 
             
            Mount the gem as an engine:
         | 
| @@ -1,9 +1,35 @@ | |
| 1 1 | 
             
            module Riiif
         | 
| 2 2 | 
             
              class ImagesController < ::ApplicationController
         | 
| 3 | 
            +
                before_filter :link_header, only: [:show, :info]
         | 
| 3 4 | 
             
                def show
         | 
| 4 5 | 
             
                  image = Image.new(params[:id])
         | 
| 5 6 | 
             
                  data = image.render(params.permit(:region, :size, :rotation, :quality, :format))
         | 
| 6 7 | 
             
                  send_data data, type: Mime::Type.lookup_by_extension(params[:format]), :disposition => 'inline'
         | 
| 7 8 | 
             
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def info
         | 
| 11 | 
            +
                  image = Image.new(params[:id])
         | 
| 12 | 
            +
                  render json: image.info.merge(server_info)
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def view
         | 
| 16 | 
            +
                  @image = Image.new(params[:id])
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                protected
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def link_header
         | 
| 22 | 
            +
                  response.headers["Link"] = '<http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2>;rel="profile"'
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def server_info
         | 
| 26 | 
            +
                  {
         | 
| 27 | 
            +
                    "@context" => "http://library.stanford.edu/iiif/image-api/1.1/context.json",
         | 
| 28 | 
            +
                    "@id" => request.original_url.sub('/info.json', ''), 
         | 
| 29 | 
            +
                    "formats" => Image::OUTPUT_FORMATS,
         | 
| 30 | 
            +
                    "profile" => "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0"
         | 
| 31 | 
            +
                    
         | 
| 32 | 
            +
                  }
         | 
| 33 | 
            +
                end
         | 
| 8 34 | 
             
              end
         | 
| 9 35 | 
             
            end
         | 
| @@ -0,0 +1,87 @@ | |
| 1 | 
            +
            require 'open3'
         | 
| 2 | 
            +
            module Riiif
         | 
| 3 | 
            +
              class File
         | 
| 4 | 
            +
                include Open3
         | 
| 5 | 
            +
                attr_reader :path
         | 
| 6 | 
            +
                # @param input_path [String] The location of an image file
         | 
| 7 | 
            +
                def initialize(input_path, tempfile = nil)
         | 
| 8 | 
            +
                  raise "HUH" if input_path.is_a? Riiif::File
         | 
| 9 | 
            +
                  @path = input_path
         | 
| 10 | 
            +
                  @tempfile = tempfile # ensures that the tempfile will stick around until this file is garbage collected.
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def self.open(file_or_url, ext = nil)
         | 
| 14 | 
            +
                  file_or_url = file_or_url.to_s # Force it to be a String... hell or highwater
         | 
| 15 | 
            +
                  if file_or_url.include?("://")
         | 
| 16 | 
            +
                    require 'open-uri'
         | 
| 17 | 
            +
                    ext ||= ::File.extname(URI.parse(file_or_url).path)
         | 
| 18 | 
            +
                    Kernel::open(file_or_url) do |f|
         | 
| 19 | 
            +
                      self.read(f, ext)
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
                  else
         | 
| 22 | 
            +
                    self.new(file_or_url)
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def self.read(stream, ext)
         | 
| 27 | 
            +
                  create(ext) do |f|
         | 
| 28 | 
            +
                    while chunk = stream.read(8192)
         | 
| 29 | 
            +
                      f.write(chunk)
         | 
| 30 | 
            +
                    end
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def self.create(ext = nil, validate = true, &block)
         | 
| 35 | 
            +
                  begin
         | 
| 36 | 
            +
                    tempfile = Tempfile.new(['mini_magick', ext.to_s.downcase])
         | 
| 37 | 
            +
                    tempfile.binmode
         | 
| 38 | 
            +
                    block.call(tempfile)
         | 
| 39 | 
            +
                    tempfile.close
         | 
| 40 | 
            +
                    image = self.new(tempfile.path, tempfile)
         | 
| 41 | 
            +
                  ensure
         | 
| 42 | 
            +
                    tempfile.close if tempfile
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def extract(options)
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  command = 'convert'
         | 
| 49 | 
            +
                  command << " -crop #{options[:crop]}" if options[:crop]
         | 
| 50 | 
            +
                  command << " -resize #{options[:size]}" if options[:size]
         | 
| 51 | 
            +
                  if options[:rotation]
         | 
| 52 | 
            +
                    command << " -virtual-pixel white +distort srt #{options[:rotation]}"
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  case options[:quality]
         | 
| 56 | 
            +
                  when 'grey'
         | 
| 57 | 
            +
                    command << ' -colorspace Gray'
         | 
| 58 | 
            +
                  when 'bitonal'
         | 
| 59 | 
            +
                    command << ' -colorspace Gray'
         | 
| 60 | 
            +
                    command << ' -type Bilevel'
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
                  command << " #{path} #{options[:format]}:-"
         | 
| 63 | 
            +
                  Rails.logger.debug "RIIIF executed: #{command}"
         | 
| 64 | 
            +
                  execute(command)
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                def info
         | 
| 68 | 
            +
                  return @info if @info
         | 
| 69 | 
            +
                  height, width = execute("identify -format %hx%w #{path}").split('x')
         | 
| 70 | 
            +
                  @info = {height: Integer(height), width: Integer(width)}
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                private
         | 
| 74 | 
            +
                  def execute(command)
         | 
| 75 | 
            +
                      stdin, stdout, stderr, wait_thr = popen3(command)
         | 
| 76 | 
            +
                      stdin.close
         | 
| 77 | 
            +
                      stdout.binmode
         | 
| 78 | 
            +
                      out = stdout.read
         | 
| 79 | 
            +
                      stdout.close
         | 
| 80 | 
            +
                      err = stderr.read
         | 
| 81 | 
            +
                      stderr.close
         | 
| 82 | 
            +
                      raise "Unable to execute command \"#{command}\"\n#{err}" unless wait_thr.value.success?
         | 
| 83 | 
            +
                      out
         | 
| 84 | 
            +
                  end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
              end
         | 
| 87 | 
            +
            end
         | 
    
        data/app/models/riiif/image.rb
    CHANGED
    
    | @@ -1,37 +1,30 @@ | |
| 1 | 
            -
            require 'mini_magick'
         | 
| 2 1 | 
             
            module Riiif
         | 
| 3 2 | 
             
              class Image
         | 
| 3 | 
            +
                
         | 
| 4 4 | 
             
                class_attribute :file_resolver
         | 
| 5 5 | 
             
                self.file_resolver = FileSystemFileResolver
         | 
| 6 6 |  | 
| 7 | 
            -
                 | 
| 7 | 
            +
                OUTPUT_FORMATS = %W{jpg png}
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                attr_reader :path_name, :id
         | 
| 8 10 |  | 
| 9 11 | 
             
                # @param [String] id The identifier of the file
         | 
| 10 12 | 
             
                def initialize(id)
         | 
| 13 | 
            +
                  @id = id
         | 
| 11 14 | 
             
                  @path_name = file_resolver.find(id)
         | 
| 12 15 | 
             
                end
         | 
| 13 16 |  | 
| 14 17 | 
             
                def render(args)
         | 
| 15 18 | 
             
                  options = decode_options!(args)
         | 
| 19 | 
            +
                  Rails.cache.fetch(options.merge(id: id), compress: true, expires_in: 3.days) do
         | 
| 20 | 
            +
                    image.extract(options)
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
                end
         | 
| 16 23 |  | 
| 17 | 
            -
             | 
| 18 | 
            -
                    c.crop options[:crop] if options[:crop]
         | 
| 19 | 
            -
                    c.resize options[:size] if options[:size]
         | 
| 20 | 
            -
                    if options[:rotation]
         | 
| 21 | 
            -
                      c.virtual_pixel 'white'
         | 
| 22 | 
            -
                      c.distort.+ 'srt', options[:rotation]
         | 
| 23 | 
            -
                    end
         | 
| 24 | 
            +
                delegate :info, to: :image
         | 
| 24 25 |  | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
                      c.colorspace "Gray"
         | 
| 28 | 
            -
                    when 'bitonal'
         | 
| 29 | 
            -
                      c.colorspace "Gray"
         | 
| 30 | 
            -
                      c.type 'Bilevel'
         | 
| 31 | 
            -
                    end
         | 
| 32 | 
            -
                  end
         | 
| 33 | 
            -
                  image.format(options[:format])
         | 
| 34 | 
            -
                  image.to_blob
         | 
| 26 | 
            +
                def image
         | 
| 27 | 
            +
                  @image ||= Riiif::File.open(path_name)
         | 
| 35 28 | 
             
                end
         | 
| 36 29 |  | 
| 37 30 | 
             
                private
         | 
| @@ -63,7 +56,7 @@ module Riiif | |
| 63 56 | 
             
                  end
         | 
| 64 57 |  | 
| 65 58 | 
             
                  def validate_format!(format)
         | 
| 66 | 
            -
                    raise InvalidAttributeError, "Unsupported format: #{format}" unless  | 
| 59 | 
            +
                    raise InvalidAttributeError, "Unsupported format: #{format}" unless OUTPUT_FORMATS.include?(format)
         | 
| 67 60 |  | 
| 68 61 | 
             
                  end
         | 
| 69 62 |  | 
| @@ -72,8 +65,8 @@ module Riiif | |
| 72 65 | 
             
                      nil 
         | 
| 73 66 | 
             
                    elsif md = /^pct:(\d+),(\d+),(\d+),(\d+)$/.match(region)
         | 
| 74 67 | 
             
                      # Image magic can't do percentage offsets, so we have to calculate it
         | 
| 75 | 
            -
                      offset_x = ( | 
| 76 | 
            -
                      offset_y = ( | 
| 68 | 
            +
                      offset_x = (info[:width] * Integer(md[1]).to_f / 100).round
         | 
| 69 | 
            +
                      offset_y = (info[:height] * Integer(md[2]).to_f / 100).round
         | 
| 77 70 | 
             
                      "#{md[3]}%x#{md[4]}+#{offset_x}+#{offset_y}"
         | 
| 78 71 | 
             
                    elsif md = /^(\d+),(\d+),(\d+),(\d+)$/.match(region)
         | 
| 79 72 | 
             
                      "#{md[3]}x#{md[4]}+#{md[1]}+#{md[2]}"
         | 
| @@ -89,7 +82,7 @@ module Riiif | |
| 89 82 | 
             
                      "x#{md[1]}"
         | 
| 90 83 | 
             
                    elsif md = /^(\d+),$/.match(size)
         | 
| 91 84 | 
             
                      "#{md[1]}"
         | 
| 92 | 
            -
                    elsif md = /^pct:(\d+)$/.match(size)
         | 
| 85 | 
            +
                    elsif md = /^pct:(\d+(.\d+)?)$/.match(size)
         | 
| 93 86 | 
             
                      "#{md[1]}%"
         | 
| 94 87 | 
             
                    elsif md = /^(\d+),(\d+)$/.match(size)
         | 
| 95 88 | 
             
                      "#{md[1]}x#{md[2]}!"
         | 
| @@ -100,18 +93,5 @@ module Riiif | |
| 100 93 | 
             
                    end
         | 
| 101 94 | 
             
                  end
         | 
| 102 95 |  | 
| 103 | 
            -
                  def image
         | 
| 104 | 
            -
                    begin
         | 
| 105 | 
            -
                      @image ||= MiniMagick::Image.open(path_name)
         | 
| 106 | 
            -
                    rescue Errno::ENOENT => e
         | 
| 107 | 
            -
                      Rails.logger.error "Unable to find #{path_name}"
         | 
| 108 | 
            -
                      Rails.logger.error e.backtrace
         | 
| 109 | 
            -
                      raise Riiif::Error, "Unable to find #{path_name}"
         | 
| 110 | 
            -
                    rescue MiniMagick::Error => e
         | 
| 111 | 
            -
                      Rails.logger.error "Error trying to open #{path_name}"
         | 
| 112 | 
            -
                      Rails.logger.error e.backtrace
         | 
| 113 | 
            -
                      raise Riiif::Error, "Unable to open the image #{path_name}"
         | 
| 114 | 
            -
                    end
         | 
| 115 | 
            -
                  end
         | 
| 116 96 | 
             
              end
         | 
| 117 97 | 
             
            end
         | 
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
                <div id="openseadragon1" style="width: 800px; height: 600px;"></div>
         | 
| 2 | 
            +
                <%=javascript_include_tag "openseadragon.js" %>
         | 
| 3 | 
            +
                <script type="text/javascript">
         | 
| 4 | 
            +
                    var viewer = OpenSeadragon({
         | 
| 5 | 
            +
                        id: "openseadragon1",
         | 
| 6 | 
            +
                        prefixUrl: "/assets/openseadragon/",
         | 
| 7 | 
            +
                        tileSources:   [{
         | 
| 8 | 
            +
                        "image_host":     "http://localhost:8080/image-service",
         | 
| 9 | 
            +
                        "identifier":   "irises",   
         | 
| 10 | 
            +
                        "width":        4264,   
         | 
| 11 | 
            +
                        "height":       3282,   
         | 
| 12 | 
            +
                        "scale_factors": [1, 2, 3, 4, 5],   
         | 
| 13 | 
            +
                        "tile_width":   1024,   
         | 
| 14 | 
            +
                        "tile_height":  1024,   
         | 
| 15 | 
            +
                        "formats":      [ "jpg", "png" ],   
         | 
| 16 | 
            +
                        "qualities":    ["native", "bitonal", "grey", "color"],   
         | 
| 17 | 
            +
                        "profile":      "http://library.stanford.edu/iiif/image-api/compliance.html#level1"
         | 
| 18 | 
            +
                      }]
         | 
| 19 | 
            +
                    });
         | 
| 20 | 
            +
                </script>
         | 
| 21 | 
            +
            DOOD
         | 
    
        data/config/routes.rb
    CHANGED
    
    | @@ -1,4 +1,8 @@ | |
| 1 1 | 
             
            Riiif::Engine.routes.draw do
         | 
| 2 2 | 
             
              ALLOW_DOTS ||= /[\w.]+/
         | 
| 3 | 
            -
               | 
| 3 | 
            +
              PERCENTAGE ||= /(pct:)?[\w.]+/
         | 
| 4 | 
            +
              get "/:id/:region/:size/:rotation/:quality(.:format)" => "images#show", 
         | 
| 5 | 
            +
                constraints: { rotation: ALLOW_DOTS, size: PERCENTAGE}
         | 
| 6 | 
            +
              get "/:id/info(.:format)" => "images#info", :constraints => { :format => /json/}
         | 
| 7 | 
            +
              get "/:id/view(.:format)" => "images#view"
         | 
| 4 8 | 
             
            end
         | 
    
        data/lib/riiif.rb
    CHANGED
    
    
| @@ -13,7 +13,7 @@ module Riiif | |
| 13 13 |  | 
| 14 14 | 
             
                def self.pattern(id)
         | 
| 15 15 | 
             
                  raise ArgumentException, "Invalid characters in id `#{id}`" unless /^\w+$/.match(id)
         | 
| 16 | 
            -
                  File.join(base_path, "#{id}.{#{input_types.join(',')}}")
         | 
| 16 | 
            +
                  ::File.join(base_path, "#{id}.{#{input_types.join(',')}}")
         | 
| 17 17 | 
             
                end
         | 
| 18 18 |  | 
| 19 19 | 
             
              end
         | 
| @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            module Riiif
         | 
| 2 | 
            +
              module HTTPFileResolver
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                # Set a lambda that maps the first parameter (id) to a URL
         | 
| 5 | 
            +
                # Example:
         | 
| 6 | 
            +
                #
         | 
| 7 | 
            +
                # Riiif::HTTPFileResolver.id_to_uri = lambda do |id| 
         | 
| 8 | 
            +
                #  "http://upload.wikimedia.org/wikipedia/commons/thumb/a/a4/#{id}.jpg/600px-#{id}.jpg"
         | 
| 9 | 
            +
                # end
         | 
| 10 | 
            +
                #
         | 
| 11 | 
            +
                mattr_accessor :id_to_uri
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def self.find(id)
         | 
| 14 | 
            +
                  uri(id)
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                protected
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def self.uri(id)
         | 
| 20 | 
            +
                  raise "Must set the id_to_uri lambda" if id_to_uri.nil?
         | 
| 21 | 
            +
                  id_to_uri.call(id)
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
            end
         | 
    
        data/lib/riiif/version.rb
    CHANGED
    
    
    
        data/riiif.gemspec
    CHANGED
    
    | @@ -13,7 +13,7 @@ Gem::Specification.new do |spec| | |
| 13 13 | 
             
              spec.homepage      = ""
         | 
| 14 14 | 
             
              spec.license       = "APACHE2"
         | 
| 15 15 |  | 
| 16 | 
            -
              spec.files         = `git ls-files`.split($/)
         | 
| 16 | 
            +
              spec.files         = `git ls-files|grep -v spec/samples`.split($/)
         | 
| 17 17 | 
             
              spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
         | 
| 18 18 | 
             
              spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
         | 
| 19 19 | 
             
              spec.require_paths = ["lib"]
         | 
| @@ -22,6 +22,5 @@ Gem::Specification.new do |spec| | |
| 22 22 | 
             
              spec.add_development_dependency "rake"
         | 
| 23 23 | 
             
              spec.add_development_dependency "engine_cart"
         | 
| 24 24 | 
             
              spec.add_development_dependency "rspec-rails"
         | 
| 25 | 
            -
              spec.add_dependency 'mini_magick'
         | 
| 26 25 | 
             
              spec.add_dependency 'rails', '> 3.2.0'
         | 
| 27 26 | 
             
            end
         | 
| @@ -12,5 +12,22 @@ describe Riiif::ImagesController do | |
| 12 12 | 
             
                           rotation: '0', quality: 'native', format: 'jpg'
         | 
| 13 13 | 
             
                expect(response).to be_successful
         | 
| 14 14 | 
             
                expect(response.body).to eq 'IMAGEDATA'
         | 
| 15 | 
            +
                expect(response.headers['Link']).to eq '<http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2>;rel="profile"'
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              it "should return info" do
         | 
| 19 | 
            +
                image = double
         | 
| 20 | 
            +
                expect(Riiif::Image).to receive(:new).with('abcd1234').and_return(image)
         | 
| 21 | 
            +
                expect(image).to receive(:info).and_return({width: 6000, height: 4000 })
         | 
| 22 | 
            +
                get :info, id: 'abcd1234', format: 'json'
         | 
| 23 | 
            +
                expect(response).to be_successful
         | 
| 24 | 
            +
                json = JSON.parse(response.body)
         | 
| 25 | 
            +
                expect(json).to eq "@context"=>"http://library.stanford.edu/iiif/image-api/1.1/context.json",
         | 
| 26 | 
            +
                  "@id" =>"http://test.host/image-service/abcd1234",
         | 
| 27 | 
            +
                  "width" =>6000,
         | 
| 28 | 
            +
                  "height" =>4000,
         | 
| 29 | 
            +
                  "formats" =>  [ "jpg", "png" ],
         | 
| 30 | 
            +
                  "profile" =>  "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0" 
         | 
| 31 | 
            +
                expect(response.headers['Link']).to eq '<http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2>;rel="profile"'
         | 
| 15 32 | 
             
              end
         | 
| 16 33 | 
             
            end
         | 
    
        data/spec/models/image_spec.rb
    CHANGED
    
    | @@ -1,15 +1,12 @@ | |
| 1 1 | 
             
            require 'spec_helper'
         | 
| 2 2 |  | 
| 3 3 | 
             
            describe Riiif::Image do
         | 
| 4 | 
            +
              before { Rails.cache.clear }
         | 
| 5 | 
            +
              let(:filename) { File.expand_path('spec/samples/world.jp2') }
         | 
| 4 6 | 
             
              subject { Riiif::Image.new('world') }
         | 
| 5 7 | 
             
              describe "happy path" do
         | 
| 6 | 
            -
                let(:combinator) { double }
         | 
| 7 | 
            -
                let(:inner) { double }
         | 
| 8 8 | 
             
                before do
         | 
| 9 | 
            -
                  expect( | 
| 10 | 
            -
                  expect(inner).to receive(:to_blob).and_return('imagedata')
         | 
| 11 | 
            -
                  inner.stub(:combine_options).and_yield(combinator)
         | 
| 12 | 
            -
                  subject.stub(:image).and_return(inner)
         | 
| 9 | 
            +
                  expect(subject.image).to receive(:execute).with("convert #{filename} jpg:-").and_return('imagedata')
         | 
| 13 10 | 
             
                end
         | 
| 14 11 | 
             
                it "should render" do
         | 
| 15 12 | 
             
                  expect(subject.render('size' => 'full', format: 'jpg')).to eq 'imagedata'
         | 
| @@ -22,27 +19,42 @@ describe Riiif::Image do | |
| 22 19 | 
             
                end
         | 
| 23 20 | 
             
              end
         | 
| 24 21 |  | 
| 22 | 
            +
              describe "info" do
         | 
| 23 | 
            +
                it "should return the data" do
         | 
| 24 | 
            +
                  expect(subject.info).to eq height: 400, width:800
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 25 27 |  | 
| 26 | 
            -
              describe " | 
| 27 | 
            -
                let(:combinator) { double }
         | 
| 28 | 
            -
                let(:inner) { double(format: true, to_blob: 'imagedata') }
         | 
| 28 | 
            +
              describe "get images from web" do
         | 
| 29 29 | 
             
                before do
         | 
| 30 | 
            -
                   | 
| 31 | 
            -
                   | 
| 30 | 
            +
                  Riiif::Image.file_resolver = Riiif::HTTPFileResolver
         | 
| 31 | 
            +
                  Riiif::HTTPFileResolver.id_to_uri = lambda do |id| 
         | 
| 32 | 
            +
                    "http://upload.wikimedia.org/wikipedia/commons/thumb/a/a4/#{id}.jpg/600px-#{id}.jpg"
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
                after do
         | 
| 36 | 
            +
                  Riiif::Image.file_resolver = Riiif::FileSystemFileResolver
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
                subject { Riiif::Image.new('Cave_26,_Ajanta') }
         | 
| 39 | 
            +
                it "should be easy" do
         | 
| 40 | 
            +
                  expect(subject.info).to eq height: 390, width:600
         | 
| 32 41 | 
             
                end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
             | 
| 45 | 
            +
              describe "mogrify" do
         | 
| 33 46 | 
             
                describe "region" do
         | 
| 34 47 | 
             
                  it "should return the original when specifing full size" do
         | 
| 35 | 
            -
                    expect( | 
| 48 | 
            +
                    expect(subject.image).to receive(:execute).with("convert #{filename} png:-")
         | 
| 36 49 | 
             
                    subject.render(region: 'full', format: 'png')
         | 
| 37 50 | 
             
                  end
         | 
| 38 51 | 
             
                  it "should handle absolute geometry" do
         | 
| 39 | 
            -
                    expect( | 
| 52 | 
            +
                    expect(subject.image).to receive(:execute).with("convert -crop 60x75+80+15 #{filename} png:-")
         | 
| 40 53 | 
             
                    subject.render(region: '80,15,60,75', format: 'png')
         | 
| 41 54 | 
             
                  end
         | 
| 42 55 | 
             
                  it "should handle percent geometry" do
         | 
| 43 | 
            -
                    expect( | 
| 44 | 
            -
                    expect( | 
| 45 | 
            -
                    expect(combinator).to receive(:crop).with('80%x70+18+13')
         | 
| 56 | 
            +
                    expect(subject.image).to receive(:execute).with("identify -format %hx%w #{filename}").and_return('131x175')
         | 
| 57 | 
            +
                    expect(subject.image).to receive(:execute).with("convert -crop 80%x70+18+13 #{filename} png:-")
         | 
| 46 58 | 
             
                    subject.render(region: 'pct:10,10,80,70', format: 'png')
         | 
| 47 59 | 
             
                  end
         | 
| 48 60 | 
             
                  it "should raise an error for invalid geometry" do
         | 
| @@ -52,27 +64,31 @@ describe Riiif::Image do | |
| 52 64 |  | 
| 53 65 | 
             
                describe "resize" do
         | 
| 54 66 | 
             
                  it "should return the original when specifing full size" do
         | 
| 55 | 
            -
                    expect( | 
| 67 | 
            +
                    expect(subject.image).to receive(:execute).with("convert #{filename} png:-")
         | 
| 56 68 | 
             
                    subject.render(size: 'full', format: 'png')
         | 
| 57 69 | 
             
                  end
         | 
| 58 | 
            -
                  it "should handle percent sizes" do
         | 
| 59 | 
            -
                    expect( | 
| 70 | 
            +
                  it "should handle integer percent sizes" do
         | 
| 71 | 
            +
                    expect(subject.image).to receive(:execute).with("convert -resize 50% #{filename} png:-")
         | 
| 60 72 | 
             
                    subject.render(size: 'pct:50', format: 'png')
         | 
| 61 73 | 
             
                  end
         | 
| 74 | 
            +
                  it "should handle float percent sizes" do
         | 
| 75 | 
            +
                    expect(subject.image).to receive(:execute).with("convert -resize 12.5% #{filename} png:-")
         | 
| 76 | 
            +
                    subject.render(size: 'pct:12.5', format: 'png')
         | 
| 77 | 
            +
                  end
         | 
| 62 78 | 
             
                  it "should handle w," do
         | 
| 63 | 
            -
                    expect( | 
| 79 | 
            +
                    expect(subject.image).to receive(:execute).with("convert -resize 50 #{filename} png:-")
         | 
| 64 80 | 
             
                    subject.render(size: '50,', format: 'png')
         | 
| 65 81 | 
             
                  end
         | 
| 66 82 | 
             
                  it "should handle ,h" do
         | 
| 67 | 
            -
                    expect( | 
| 83 | 
            +
                    expect(subject.image).to receive(:execute).with("convert -resize x50 #{filename} png:-")
         | 
| 68 84 | 
             
                    subject.render(size: ',50', format: 'png')
         | 
| 69 85 | 
             
                  end
         | 
| 70 86 | 
             
                  it "should handle w,h" do
         | 
| 71 | 
            -
                    expect( | 
| 87 | 
            +
                    expect(subject.image).to receive(:execute).with("convert -resize 150x75! #{filename} png:-")
         | 
| 72 88 | 
             
                    subject.render(size: '150,75', format: 'png')
         | 
| 73 89 | 
             
                  end
         | 
| 74 90 | 
             
                  it "should handle bestfit (!w,h)" do
         | 
| 75 | 
            -
                    expect( | 
| 91 | 
            +
                    expect(subject.image).to receive(:execute).with("convert -resize 150x75 #{filename} png:-")
         | 
| 76 92 | 
             
                    subject.render(size: '!150,75', format: 'png')
         | 
| 77 93 | 
             
                  end
         | 
| 78 94 | 
             
                  it "should raise an error for invalid size" do
         | 
| @@ -81,15 +97,12 @@ describe Riiif::Image do | |
| 81 97 | 
             
                end
         | 
| 82 98 |  | 
| 83 99 | 
             
                describe "rotate" do
         | 
| 84 | 
            -
                  let(:distorter) { double }
         | 
| 85 100 | 
             
                  it "should return the original when specifing full size" do
         | 
| 86 | 
            -
                    expect( | 
| 101 | 
            +
                    expect(subject.image).to receive(:execute).with("convert #{filename} png:-")
         | 
| 87 102 | 
             
                    subject.render(rotation: '0', format: 'png')
         | 
| 88 103 | 
             
                  end
         | 
| 89 104 | 
             
                  it "should handle floats" do
         | 
| 90 | 
            -
                    expect( | 
| 91 | 
            -
                    expect(combinator).to receive(:virtual_pixel).with('white')
         | 
| 92 | 
            -
                    expect(distorter).to receive(:+).with("srt", 22.5)
         | 
| 105 | 
            +
                    expect(subject.image).to receive(:execute).with("convert -virtual-pixel white +distort srt 22.5 #{filename} png:-")
         | 
| 93 106 | 
             
                    subject.render(rotation: '22.5', format: 'png')
         | 
| 94 107 | 
             
                  end
         | 
| 95 108 | 
             
                  it "should raise an error for invalid angle" do
         | 
| @@ -99,20 +112,19 @@ describe Riiif::Image do | |
| 99 112 |  | 
| 100 113 | 
             
                describe "quality" do
         | 
| 101 114 | 
             
                  it "should return the original when specifing native" do
         | 
| 102 | 
            -
                    expect( | 
| 115 | 
            +
                    expect(subject.image).to receive(:execute).with("convert #{filename} png:-")
         | 
| 103 116 | 
             
                    subject.render(quality: 'native', format: 'png')
         | 
| 104 117 | 
             
                  end
         | 
| 105 118 | 
             
                  it "should return the original when specifing color" do
         | 
| 106 | 
            -
                    expect( | 
| 119 | 
            +
                    expect(subject.image).to receive(:execute).with("convert #{filename} png:-")
         | 
| 107 120 | 
             
                    subject.render(quality: 'color', format: 'png')
         | 
| 108 121 | 
             
                  end
         | 
| 109 122 | 
             
                  it "should convert to grayscale" do
         | 
| 110 | 
            -
                    expect( | 
| 123 | 
            +
                    expect(subject.image).to receive(:execute).with("convert -colorspace Gray #{filename} png:-")
         | 
| 111 124 | 
             
                    subject.render(quality: 'grey', format: 'png')
         | 
| 112 125 | 
             
                  end
         | 
| 113 126 | 
             
                  it "should convert to bitonal" do
         | 
| 114 | 
            -
                    expect( | 
| 115 | 
            -
                    expect(combinator).to receive(:type).with('Bilevel')
         | 
| 127 | 
            +
                    expect(subject.image).to receive(:execute).with("convert -colorspace Gray -type Bilevel #{filename} png:-")
         | 
| 116 128 | 
             
                    subject.render(quality: 'bitonal', format: 'png')
         | 
| 117 129 | 
             
                  end
         | 
| 118 130 | 
             
                  it "should raise an error for invalid angle" do
         |