Skip to content

Commit

Permalink
Added height, width, and hide_fields parameters to template preview. C…
Browse files Browse the repository at this point in the history
…loses #52, Closes #53.

* Introducde an ImageUtility module to resize images system-wide.  Scales to fit height and width if needed or stretches the image to match exact dimensions.

* Wired up Template#display to use the image utility.

* Wired up Template#preview to use the image utility, taking height and width as params.  Setting the hide_fields param to true (&hide_fields=true) will not render the fields on a preview.

* Made the font size selection smarter when rendering templates.
  • Loading branch information
bamnet committed Mar 13, 2012
1 parent 7262399 commit 004b587
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 34 deletions.
70 changes: 42 additions & 28 deletions app/controllers/templates_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,81 +97,95 @@ def destroy
# GET /template/1/display
# Render the template for display on a screen.
def display
require'image_utility'
@template = Template.find(params[:id])
@media = @template.media.original.first
@image = Magick::Image.from_blob(@media.file_contents).first
image = Magick::Image.from_blob(@media.file_contents).first

# Resize the image to a height and width if they are both being set.
# Round these numbers up to ensure the image will at least fill
# the requested space.
width = nil
height = nil
width = params[:height].to_f.ceil unless params[:height].nil?
height = params[:width].to_f.ceil unless params[:width].nil?

unless height.nil? or width.nil?
# There is a lengthy discussion of resizing options here:
# http://rmagick.rubyforge.org/resizing-methods.html.
# I am not factoring any information from that page into this choice.
@image.scale!(height, width)
end
height = params[:height].to_f.ceil unless params[:height].nil?
width = params[:width].to_f.ceil unless params[:width].nil?

image = ImageUtility.resize(image, width, height, false)
case request.format
when Mime::Type.lookup_by_extension(:jpg)
@image.format = "JPG"
image.format = "JPG"
when Mime::PNG
@image.format = "PNG"
image.format = "PNG"
end

# Set some reasonable cache headers
response.headers["Last-Modified"] = CGI.rfc1123_date(@template.updated_at)
expires_in 36.hours, :public => true

send_data @image.to_blob,
:filename => "#{@template.name.underscore}.#{@image.format.downcase}",
:type => @image.mime_type, :disposition => 'inline'
send_data image.to_blob,
:filename => "#{@template.name.underscore}.#{image.format.downcase}",
:type => image.mime_type, :disposition => 'inline'
end

# GET /template/1/preview
# Generate a preview of the template based on the request format.
def preview
@template = Template.find(params[:id])
@media = @template.media.original.first
@image = Magick::Image.from_blob(@media.file_contents).first
@height = @image.rows
@width = @image.columns
image = Magick::Image.from_blob(@media.file_contents).first

# Hide the fields if the hide_fields param is set,
# show them by default though.
@hide_fields = false
if !params[:hide_fields].nil?
@hide_fields = [true, "true", 1, "1"].include?(params[:hide_fields])
end

height = image.rows
width = image.columns

jpg = Mime::Type.lookup_by_extension(:jpg) #JPG is getting defined elsewhere.
if([jpg, Mime::PNG, Mime::HTML].include?(request.format))
if !@template.positions.empty?
if !@hide_fields && !@template.positions.empty?
dw = Magick::Draw.new
@template.positions.each do |position|
#Draw the rectangle
dw.fill("grey")
dw.stroke_opacity(0)
dw.fill_opacity(0.6)
dw.rectangle(@width*position.left, @height*position.top, @width*position.right, @height*position.bottom)
dw.rectangle(width*position.left, height*position.top, width*position.right, height*position.bottom)

#Layer the field name
dw.stroke("black")
dw.fill("black")
dw.text_anchor(Magick::MiddleAnchor)
dw.opacity(1)
dw.pointsize = 100
dw.text((@width*(position.left + position.right)/2),(@height*(position.top + position.bottom)/2+40),position.field.name)
font_size = [width, height].min / 10
dw.pointsize = font_size
dw.text((width*(position.left + position.right)/2),(height*(position.top + position.bottom)/2+0.4*font_size),position.field.name)
end
dw.draw(@image)
dw.draw(image)
end

# Resize the image if needed.
# We do this post-field drawing because RMagick seems to struggle with small font sizes.
height = params[:height].nil? ? nil : params[:height].to_f.ceil
width = params[:width].nil? ? nil : params[:width].to_f.ceil
if height || width
require 'image_utility'
image = ImageUtility::resize(image, width, height)
end

case request.format
when jpg
@image.format = "JPG"
image.format = "JPG"
when Mime::PNG
@image.format = "PNG"
image.format = "PNG"
end

send_data @image.to_blob,
:filename => "#{@template.name.underscore}.#{@image.format.downcase}_preview",
:type => @image.mime_type, :disposition => 'inline'
send_data image.to_blob,
:filename => "#{@template.name.underscore}.#{image.format.downcase}_preview",
:type => image.mime_type, :disposition => 'inline'
else
respond_to do |format|
format.svg
Expand Down
4 changes: 2 additions & 2 deletions app/views/screens/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,10 @@
<%= f.radio_button :template_id, template.id %>
</div>

<%= image_tag preview_template_path(template, :format => :png), :style => "height: 60px; margin: 0px;" %>
<%= image_tag preview_template_path(template, :height => 60, :format => :png), :style => "height: 60px; margin: 0px;" %>

<div id="preview_<%= template.id %>" class="dd" style="display:none;">
<%= image_tag preview_template_path(template, :format => :png), :style => "width: 260px; margin: 0px;" %>
<%= image_tag preview_template_path(template, :width => 260, :format => :png), :style => "width: 260px; margin: 0px;" %>
</div>

<div class="cont">
Expand Down
2 changes: 1 addition & 1 deletion app/views/screens/_show_body.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<article>
<div class="screen-model" style="width: 800px; height: 505px;">
<%= link_to "Change Screen Template", edit_screen_path(@screen, :anchor => "template_selection"), :class => "btn clear small", :style => "position: absolute; top: 6px; right: 25px;" %>
<div class="inner" style="background: url(<%= preview_template_path(@screen.template, :format => :png) %>) center center no-repeat; width: 800px; height: 450px;">
<div class="inner" style="background: url(<%= preview_template_path(@screen.template, :width => 800, :height => 450, :format => :png) %>) center center no-repeat; width: 800px; height: 450px;">
<% @screen.template.positions.each do |pos| %>
<div class="pos" style="top: <%= pos.top * 100 %>%; left: <%= pos.left * 100 %>%; width: <%= (pos.right - pos.left) * 100 %>%; height: <%= (pos.bottom - pos.top) * 100 %>%; <%= pos.style %>">
<%= pos.id %>
Expand Down
6 changes: 4 additions & 2 deletions app/views/templates/preview.svg.erb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
<g>
<image id="background" xlink:href="<%= url_for @media %>" height="100%" width="100%" x="0" y="0"
preserveAspectRatio="none" />
<% @template.positions.each do |position| %>
<% unless @hide_fields
@template.positions.each do |position| %>
<g>
<rect x="<%= 100*position.left %>%" y="<%= 100*position.top %>%"
width="<%= 100*position.width %>%" height="<%= 100*position.height %>%"
Expand All @@ -22,6 +23,7 @@
<%= position.field.name %>
</text>
</g>
<% end %>
<% end
end %>
</g>
</svg>
2 changes: 1 addition & 1 deletion config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class Application < Rails::Application
# -- all .rb files in that directory are automatically loaded.

# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
config.autoload_paths += %W(#{config.root}/lib)

# Only load the plugins named here, in the order given (default is alphabetical).
# :all can be used as a placeholder for all plugins not explicitly named.
Expand Down
35 changes: 35 additions & 0 deletions lib/image_utility.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Common image utilities.
module ImageUtility

# Resize an image to a height and width.
# If maintain_aspect_ratio (default true) is set the constraining value
# is used when resizing the image (i.e. the largest side will match the smallest dimension)
# otherwise the image will be resized to match the width and height.
# Returns an image.
def self.resize(image, width, height, maintain_aspect_ratio=true)
unless width.nil? && height.nil?
if maintain_aspect_ratio && (!width.nil? && !height.nil?)
desired_ratio = width.to_f / height
image_ratio = image.columns.to_f / image.rows
Rails.logger.debug(desired_ratio)
Rails.logger.debug(image_ratio)
Rails.logger.debug("Done")
if image_ratio > desired_ratio
height = nil
else
width = nil
end
end
if width.nil?
width = height * image.columns.to_f / image.rows
end
if height.nil?
height = width * image.rows.to_f / image.columns
end
if image.columns != width && image.rows != height
image = image.scale(width, height)
end
end
return image
end
end

0 comments on commit 004b587

Please sign in to comment.