module Apache::ImageResizer::Util

Constants

DEFAULT_FORMAT
DEFAULT_HEIGHT
DEFAULT_MAX_DIM
DEFAULT_PREFIX_RE
DEFAULT_PROXY_CACHE
DEFAULT_SOURCE_DIR
DEFAULT_VERBOSITY
DIRECTIVES_RE
MIME_RE
PROXY_RE
REPLACE

Public Instance Methods

extract_directives(path) click to toggle source
# File lib/apache/image_resizer/util.rb, line 151
def extract_directives(path)
  return unless path.sub!(DIRECTIVES_RE, '')
  match, directives, max = Regexp.last_match, {}, @max_dim

  if o = match[3]
    wh = [o.to_f, match[4].to_f]
    xy = match.values_at(5, 6)

    if wh.all? { |i| 0 < i && i <= max }
      directives[:offset] = xy.map! { |i| i.tr!('pm', '+-').to_f }.concat(wh)
    else
      return
    end
  end

  if w = match[1]
    h = match[2]

    wh = [w.to_f]
    wh << h.to_f if h

    max *= 2 if o

    if wh.all? { |i| 0 < i && i <= max }
      directives[:resize] = wh
    else
      return
    end
  end

  [directives, match[0]]
end
get_paths(request, path, base, prefix, source_dir, target_dir, proxy_cache, secret) click to toggle source
# File lib/apache/image_resizer/util.rb, line 184
def get_paths(request, path, base, prefix, source_dir, target_dir, proxy_cache, secret)
  real_base = request.lookup_uri(base).filename.untaint
  target    = File.join(real_base, prefix, target_dir, path).untaint
  return [nil, target] if File.exist?(target)

  source = request.lookup_uri(url_for(File.join(base, prefix,
    source_dir, path.sub(*REPLACE.reverse)), secret)).filename.untaint
  return [source, target] unless source.sub!(PROXY_RE, '') && proxy_cache

  cache = File.join(real_base, prefix, proxy_cache, path).untaint
  return [cache, target] if File.exist?(cache)

  begin
    URI.get_redirect(source) { |res|
      if res.is_a?(Net::HTTPSuccess) && res.content_type =~ MIME_RE
        content = res.body.untaint

        mkdir_for(cache)
        File.open(cache, 'w') { |f| f.write(content) }

        return [cache, target]
      end
    }
  rescue => err
    log_err(err, "#{source} => #{cache}")
  end

  [source, target]
end
parse_url(url, base, prefix_re, &block) click to toggle source
# File lib/apache/image_resizer/util.rb, line 133
def parse_url(url, base, prefix_re, &block)
  block ||= lambda { |*| }

  return block['No URL'] unless url

  path = Apache::SecureDownload::Util.real_path(url)
  return block['Invalid Format'] unless path.sub!(
    %r{\A#{Regexp.escape(base)}/(#{prefix_re})}, ''
  )

  prefix, directives, dir = $1 || '', *extract_directives(path)
  return block['Invalid Directives'] unless directives
  return block['No Path'] if path.empty?
  return block['No File'] if path =~ %r{/\z}

  [path, prefix, directives, dir]
end
resize(source, target, directives, enlarge, &block) click to toggle source
# File lib/apache/image_resizer/util.rb, line 214
def resize(source, target, directives, enlarge, &block)
  img = do_magick('Read', source, block) { |value|
    Magick::Image.read(value).first
  } or return

  resize, offset = directives.values_at(:resize, :offset)
  link = !offset

  if resize
    c, r = img.columns, img.rows

    w, h = resize
    h  ||= DEFAULT_HEIGHT

    unless enlarge || offset
      w = [w, c].min
      h = [h, r].min
    end

    img.resize_to_fit!(w, h)

    link &&= img.columns == c && img.rows == r
  end

  if offset
    img.crop!(*offset)
  end

  mkdir_for(target)

  if link
    source = File.expand_path(File.readlink(source),
      File.dirname(source)) if File.symlink?(source)

    if system('ln', source.untaint, target)
      return img
    elsif block
      block['Link error: %s' % $?.exitstatus]
    end
  end

  do_magick('Write', target, block) { |value|
    img.write(value) or raise Magick::ImageMagickError
  }
rescue => err
  log_err(err)
  block['Resize Error: %s' % err] if block
end
resize_url(size = DEFAULT_SOURCE_DIR, *path) click to toggle source
# File lib/apache/image_resizer/util.rb, line 111
def resize_url(size = DEFAULT_SOURCE_DIR, *path)
  case size
    when String  then nil
    when Numeric then size = "r#{size}"
    when Array   then size = "r#{size.join('x')}"
    when Hash    then size = size.map { |k, v| case k.to_s
      when /\A[rs]/
        "r#{Array(v).join('x')}" if v
      when /\Ao/
        x, y, w, h = v
        "o#{w}x#{h}#{x < 0 ? 'm' : 'p'}#{x.abs}#{y < 0 ? 'm' : 'p'}#{y.abs}"
    end }.compact.join
  end

  if path.empty?
    size
  else
    file = path.pop.sub(*REPLACE)
    File.join(path << size << file)
  end
end
secure_resize_url(secret, args = [], options = {}) click to toggle source
# File lib/apache/image_resizer/util.rb, line 107
def secure_resize_url(secret, args = [], options = {})
  url_for(resize_url(*args), secret, options)
end
send_image(request, target, img = nil) { |'Send Error'| ... } click to toggle source
# File lib/apache/image_resizer/util.rb, line 263
def send_image(request, target, img = nil)
  File.open(target) { |f|
    request.content_type = (t = img && img.format) ?
      "image/#{t.downcase}" : f.content_type

    request.status = HTTP_OK
    request.send_fd(f)
  }
rescue IOError => err
  request.log_reason(err.message, target)
  yield('Send Error') if block_given?
end

Private Instance Methods

do_magick(what, value, block) { |value| ... } click to toggle source
# File lib/apache/image_resizer/util.rb, line 278
def do_magick(what, value, block)
  yield value
rescue Magick::ImageMagickError => err
  unless value.start_with?(DEFAULT_FORMAT)
    value = "#{DEFAULT_FORMAT}#{value}"
    retry
  else
    block['%s Error: %s' % [what, err]] if block
  end
end
log(level = 1, loc = 0, trace = nil) { || ... } click to toggle source
# File lib/apache/image_resizer/util.rb, line 304
def log(level = 1, loc = 0, trace = nil)
  return if @verbosity < level

  case msg = yield
    when Array then msg = msg.shift % msg
    when Hash  then msg = msg.map { |k, v|
      "#{k} = #{v.inspect}"
    }.join(', ')
  end

  warn "#{caller[loc]}: #{msg}#{" [#{trace.join(', ')}]" if trace}"
end
log_err(err, msg = nil) click to toggle source
# File lib/apache/image_resizer/util.rb, line 298
def log_err(err, msg = nil)
  log(0, 1, err.backtrace) {
    "[ERROR] #{"#{msg}: " if msg}#{err} (#{err.class})"
  }
end
mkdir_for(path) click to toggle source
# File lib/apache/image_resizer/util.rb, line 289
def mkdir_for(path)
  dir = File.dirname(path).untaint
  FileUtils.mkdir_p(dir) unless File.exist?(dir)
end
url_for(url, sec = nil, opt = {}) click to toggle source
# File lib/apache/image_resizer/util.rb, line 294
def url_for(url, sec = nil, opt = {})
  sec ? Apache::SecureDownload::Util.secure_url(sec, url, opt) : url
end