For example, I have the url in project: http://localhost:3000/images/20/thumb/300x300. Where 300x300 - dynamic params in url for crop width and height of image. How I can encrypt this url? May be by add the token for http header? I need this to protect the server from generates different urls with different width and height of image (100x100, 150x200, 300x200...) Show code example, please.
From your question I understand that you want server to render only one of accepted dimensions. So instead encrypt the URL, you can just filter it in your controller
...
ALLOW_THUMB_SIZES = %w( 100x100 150x200 300x200 )
...
def generate_image
thumb_size = params[:thumb_size]
if ALLOW_THUMB_SIZES.include? thumb_size
# do resize image to thumb_size here
else
# resize to some default size e.g. 300x300
# or throw exception...
end
end
...
You can use this at your route:
get 'images/:id/thumb/:size', size: /^[0-9]+x[0-9]+$/
and at your controller you can access id and size of the image like this:
def show
#image= Image.find( params[:id] )
width, height=params[:size].split("x").map{|s| s.to_i}
# ...
end
If you have few fixed size of image that you accept then you can use constraints like following:
Rails.application.routes.draw do
get 'images/:id/thumb/:size', size: /^[0-9]+x[0-9]+$/,
constraints: ImageSizeConstraint.new
end
class ImageSizeConstraint
def matches?(request)
params = request.path_parameters
if %w(100x100 150x200 300x200).include? params[:size]
return true
else
return false
end
end
end
Related
I'm using the following code to get the width of image using Dimensions Gem.
file_path = "http://localhost:3000/uploads/resize/avatar/25/ch05.jpg"
width = Dimensions.width(open(file_path).read)
When I put the image url in url bar it renders the image in browser. what I'm trying to do is to get the width of image. so can anyone know what I'm doing wrong?
So your issue is that Dimensions requires a file path to determine the width of the image. open will return a StringIO and open(...).read will return a String both will fail when using File.open.
Dimensions#width
def width(path)
io_for(path).width
end
Dimensions#io_for
def io_for(path)
Dimensions(File.open(path, "rb")).tap do |io|
io.read
io.close
end
end
To work around this you can download the image to a Tempfile and then use that path to pass to Dimensions.width like so
path = "http://localhost:3000/uploads/resize/avatar/25/ch05.jpg"
t = Tempfile.new # you could add a name but it doesn't matter
t.write(open(path).read) # write the image to the Tempfile
t.close # must close the file before reading it
width = Dimensions.width(t.path) # pass the Tempfile path to Dimensions
t.unlink # deletes the Tempfile
We can make this look a little cleaner like so:
def get_width_of_url_image(url)
t = Tempfile.new.tap do |f|
f.write(open(url).read)
f.close
end
width = Dimensions.width(t.path)
t.unlink and width
end
get_width_of_url_image("https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png")
#=> 272
I'm working on an App which gets shipment labels from Express Carriers in Ruby on Rails 4. At the moment I´m working with the UPS API and its label which is GIF image.
To be able to generate the PDF containing the GIF label I'm using Prawn which not support GIF. So the GIF is converted to a PNG. I´m able to have the label but when I print it out the quality is very low and difficult to read what is inside the label.
I need to understand how to add a better quality as otherwise, the label is not possible to use it.
The class I'm working on:
class UPSLabelConsolidation
attr_reader :base64_encoded_gif_labels
def initialize(base64_encoded_gif_labels)
#base64_encoded_gif_labels = base64_encoded_gif_labels
end
def perform!
identifier = SecureRandom.hex(3)
tmp_label_files = base64_encoded_gif_labels.each_with_index.map do |base64_encoded_gif_label, index|
tmp_label_file = Tempfile.new(["ups-label-#{identifier}-#{index}", ".png"], Rails.root.join("tmp"))
tmp_label_file.binmode
image = MiniMagick::Image.read(Base64.decode64(base64_encoded_gif_label), "gif")
image.combine_options do |b|
b.rotate "90" # Rotate 90-degrees clockwise
b.crop "800x1000+0+0" # Crop ~200px whitespace from the bottom of the label
end
image.format("png") # Prawn does not support GIF, so we convert it here.
image.write(tmp_label_file.path)
tmp_label_file.rewind
tmp_label_file
end
new_page = false
#pdf = Prawn::Document.new(page_size: [297, 390], margin: 20, page_layout: :portrait) # Margin is ~0.7cm
tmp_label_files.each do |label_file|
#pdf.start_new_page if new_page
#pdf.image label_file, width: 250, position: :left # Width is ~8.8cm
new_page = true
end
end
def write!(path)
if #pdf
#pdf.render_file(path)
else
raise "`#perform!` before `#write!`"
end
end
end
I'm building a website with Rails 4.2 and Mongoid. I'm using mongoid-paperclip, and I'm trying to crop an image down to a square while preserving the dimensions of the short side (so the image will fill the full square). Here's my custom processor:
module Paperclip
class Cropper < Thumbnail
def initialize(file, options = {}, attachment = nil)
super
#preserved_size = [#current_geometry.width, #current_geometry.height].min
#current_geometry.width = #preserved_size
#current_geometry.height = #preserved_size
end
def target
#attachment.instance
end
def transformation_command
if crop_command
crop_command + super.join(' ').sub(/ -crop \S+/, '').split(' ')
else
super
end
end
def crop_command
["-crop", "#{#preserved_size}x#{#preserved_size}+#{#preserved_size}+#{#preserved_size}"]
end
end
end
And the model that it's attached to looks has this line:
has_mongoid_attached_file :image, styles: {square: {processors: [:cropper]}}
But it doesn't seem to work. A version of the image named 'square' is saved, but it's identical to the original. How can I get this to work?
I was able to fix this without using a paperclip processor. In my model, I specified the styles for the image using a lambda:
has_mongoid_attached_file :image, styles: lambda {|a|
tmp = a.queued_for_write[:original]
return {} if tmp.nil?
geometry = Paperclip::Geometry.from_file(tmp)
preserved_size = [geometry.width.to_i, geometry.height.to_i].min
{square: "#{preserved_size}x#{preserved_size}#"}
}
Note that the # at the end of the dimensions ensured that the cropped image was always the specified dimensions, rather than just scaling down the image.
In my records index, I wish to insert an icon, of which name is calculated in the model, using parameters thanks to a parameters helper.
Retrieving parameters actually does not work.
In the BusinessRules index table, I specified an image tag:
<td><%= image_tag(business_rule.index_audit_tag, :alt => "Quality hit") %>
Which I extract from a public function in the model:
### display audit tag filename
def index_audit_tag
ratio = (1-self.bad_records / (self.all_records+1)) * 100
image_file = case ratio
when 0..60 then "red.png"
when 60..90 then "yellow-png"
# when red_threshold..yellow_threshold then red_image
# when yellow_threshold..green_threshold then yellow_image
else "green.png"
end
return image_file
end
It works fine when hard-coded, but I would like to use the red_threshold etc. parameters which are available through the parameters_helper:
def red_threshold
list_id = ParametersList.where("code=?", 'LIST_OF_DISPLAY_PARAMETERS').take!
#myparam = Parameter.where("parameters_list_id=? AND name=? AND ? BETWEEN active_from AND active_to", list_id, 'Tag 1-Green light', Time.now ).take!
#myparam.param_value.to_i
end
If I try using the parameters, I get the error:
undefined local variable or method `red_threshold'
How can I do that?
You can't call a helper method from within a model. Helpers are in the view layer of MVC and models are in thee model layer. To fix this you need to put both halves of the logic in the same layer.
If you want to keep index_audit_tag in the model layer:
In the Parameter model:
class Parameter
def self.red_threshold
list_id = ParametersList.where("code=?", 'LIST_OF_DISPLAY_PARAMETERS').take!
myparam = Parameter.where("parameters_list_id=? AND name=? AND ? BETWEEN active_from AND active_to", list_id, 'Tag 1-Green light', Time.now ).take!
myparam.param_value.to_i
end
end
(Note: You can probably improve this to do one query, but I'm not clear on your data model so I didn't try.)
And in your BusinessRule model:
def index_audit_tag
ratio = (1-self.bad_records / (self.all_records+1)) * 100
image_file = case ratio
when 0..60 then "red.png"
when 60..90 then "yellow-png"
when Parameter.red_threshold..Parameter.yellow_threshold then red_image
when Parameter.yellow_threshold..Parameter.green_threshold then yellow_image
else "green.png"
end
return image_file
end
If you want to put the icon logic in the view layer:
Many people would argue that the logic for choosing the right icon doesn't belong in the model. So another way to do this (and probably how I would do it) is to remove index_audit_tag from the model instead, and put it in a helper:
def index_audit_tag_for(business_rule)
ratio = (1-business_rule.bad_records / (business_rule.all_records+1)) * 100
image_file = case ratio
when 0..60 then "red.png"
when 60..90 then "yellow-png"
when red_threshold..yellow_threshold then red_image
when yellow_threshold..green_threshold then yellow_image
else "green.png"
end
return image_file
end
Then it will have no trouble finding the *_threshold methods which are also in the view.
I'm trying to finalize my image moderation code,
I have just a simple assets model with a column moderated.
Images will not be shown unless the moderated flag is set to true ( boolean )
In addition to this I have the idea to store a is_moderated (integer) inside User model and store a value there like
0 = not moderated
1 = moderated and inappropriate image
2 = moderated and correct image
Then in application controller I do something like, in before filter:
def is_moderated
if user_signed_in?
#moderate = Moderate.find(current_user) rescue nil
if #user.is_moderated == "2"
render :template => "shared/moderated_bad_images"
end
end
end
end
How about you are only allowed to upload 1 image initially.
Then after that image is deemed appropriate you can add more.