I need to resize images in PaperClip which uses ImageMagick over a background image. I made custom PaperClip processors (https://gist.github.com/xxx/1051938 and https://github.com/thoughtbot/paperclip#custom-attachment-processors) and they are working but I dont know which commands to use to compose the images.
This is process I would like:
User uploads image X
Processor runs and resizes the image X to given dimensions with tranparent fill - Y
Next the background image is cropped to given dimensions - Z
Y is overlayed over the Z centered.
Thanks!
Well after few days of struggle the answer is here:
For IM command line version step by step (a.png is input, tiled.png is source of background)
convert a.png -thumbnail 100x100 -background none -gravity center -extent 100x100 resized.png
convert tiled.png -crop 100x100+0+0 +repage cropped.png
convert cropped.png out.png -composite result.png
For IM command line combined code
convert tiled.png -crop 1000x1000+0+0 +repage a.png -thumbnail 1000x1000 -background none -gravity center -extent 1000x1000 -composite result.png
For use in image magick copy the default Thumbnail processor and make changes to the make method (or just create your own processor)
def make
src = #file
dst = Tempfile.new([#basename, #format ? ".#{#format}" : ''])
dst.binmode
begin
tgeom = #target_geometry.width.to_s + 'x' + #target_geometry.height.to_s
tiled_path = Rails.root.join('public','system','tiled.png')
parameters = []
parameters << tiled_path
parameters << '-crop'
parameters << tgeom + '+0+0 +repage'
parameters << ':source'
parameters << '-thumbnail ' + tgeom
parameters << '-background none'
parameters << '-gravity center'
parameters << '-extent ' + tgeom
parameters << '-composite'
parameters << ':dest'
parameters = parameters.flatten.compact.join(' ').strip.squeeze(' ')
success = convert(parameters, :source => "#{File.expand_path(src.path)}#{'[0]' unless animated?}", :dest => File.expand_path(dst.path))
rescue Cocaine::ExitStatusError => e
raise Paperclip::Error, "There was an error processing the thumbnail for #{#basename}" if #whiny
rescue Cocaine::CommandNotFoundError => e
raise Paperclip::Errors::CommandNotFoundError.new("Could not run the `convert` command. Please install ImageMagick.")
end
dst
end
Related
On Rails 5.2.1, I am attempting to use MiniMagick to write text on an image. The problem is, it overflows beyond the bounds of the image's width for long texts.
I have attempted to use draw, label, annotation and caption methods from here but none give me the right result. caption does not even add the text to the image.
This is my code:
temp_img = MiniMagick::Image.open(url_for(#post.image))
img_width = temp_img[:width]
temp_img.combine_options do |c|
c.gravity 'North'
c.draw "text 0, 0 '#{top_txt}'"
#c.annotate '0,0', "'#{top_txt}'" (same result)
#c.caption "'#{top_txt}'" (same result)
#c.label "'#{top_txt}'" (same result)
c.gravity 'South'
c.draw "text 0, 0 '#{bot_txt}'"
#c.annotate '0,0', "'#{bot_txt}'" (same result)
#c.caption "'#{bot_txt}'" (same result)
#c.label "'#{bot_txt}'" (same result)
c.stroke('#000000')
c.strokewidth 1
c.fill('#FFFFFF')
c.size "#{img_width}x"
c.pointsize '40'
c.font "#{Rails.root.join('public', 'font',
'Franklin_Gothic_Heavy_Regular.ttf')}"
end
This is my result:
The closest I have seen to a solution is this but is too messy.
Could there be a better way?
Sorry, I do not know Minimagick. But in ImageMagick command line there is label: that automatically fits text to some dimension such as the image width. See https://imagemagick.org/Usage/text/#label. If MiniMagick does not support that directly, then perhaps you could use Ruby/Rmagick commands. See https://github.com/minimagick/minimagick (methods section), assuming RMagick supports a label: like method. Note that with label: and caption: you have to create a new image with with your text on a transparent background and then composite it over your original image.
Here is an example:
Input:
convert image.png \( -size 639x -background none -font Arial -fill black label:"The quick brown fox jumps over the lazy dog" \) -gravity center -compose over -composite result.png
You need to use Convert with MiniMagick and the syntax is a little tricky because there isn't many examples with Ruby for it.
caption_string = "caption: #{top_txt}"
MiniMagick::Tool::Convert.new do |img|
img.gravity 'north'
img.stroke '#000000'
img.strokewidth 1
img.fill '#FFFFFF'
img.size "#{img_width}x"
img.pointsize '40' #don't add this if you want it to adjust according to size
img.font "#{Rails.root.join('public', 'font',
'Franklin_Gothic_Heavy_Regular.ttf')}"
img << caption_string
img << url_for(#post.image)
end
Using Carrierwave on Ruby 5 with MiniMagick, is it possible to trim transparent pixels ?
Suppose a user uploads a 500x500 image but only the inner 250x250 pixels are indeed filled, the rest is transparent. Is there a processing command that would help detect and trim the image to 250x250 before additional processing ?
I found https://www.imagemagick.org/discourse-server/viewtopic.php?t=12127 and it seems there is a trim transparent command on Imagemagick but I'm not sure how to use it with the Ruby wrapper Minimagick ?
The MiniMagick::Image.trim is all that's needed. Without a pixel-iterator, it would be simplest to apply trim on a clone image, and act on the smallest result.
require 'mini_magick'
def trimed_image(path)
image = MiniMagick::Image.open(path)
test_image = image.clone
test_image.trim
if test_image.width < image.width || test_image.height < image.height
test_image
else
image
end
end
Test case with convert rose: -resize x100 rose.png
rose = trimed_image("rose.png")
rose.write("rose_output.png")
No change expected.
Test transparent image with convert -size 100x100 gradient: -background black -extent 200x200-50-50 -alpha copy trim.png
trim = trimed_image("trim.png")
trim.write("trim_output.png")
Trim expected.
I have tried the following code in imagemagick:
convert input.jpg -morphology Erode Square output.jpg
I need to convert it into RMagick so that I can use in rails application
You can always write it using the << operator:
MiniMagick::Tool::Convert.new do |convert|
convert << 'input.jpg'
convert << '-morphology' << 'Erode' << 'Square'
convert << 'output.jpg'
end
Given:
A texture and a photograph (with no transparent background)
How do I give the photograph the texture?
To be specific, I want the following steps:
Tile the texture. From here, I have: convert -size 1056x576 tile:Castillo_001.gif Castillo_tiled.gif
Invert the result.
Do a composite with the photograph equivalent to the "Color Dodge" blending mode in Photoshop.
Any clues for MiniMagick? Or any clue for the answer in ImageMagick?
Thanks a bunch.
Answer
ImageMagick:
convert IMG_1970.JPG \( -size 2816x1584 tile:background.png -negate \) -compose ColorDodge -composite out.jpg
Full answer:
# I just negatived the background already
img = MiniMagick::Image.open(File.join('IMG_1970.JPG'))
background = MiniMagick::Image.open(File.join('background_negative.png'))
background.combine_options do |c|
c.size "#{img['width']}x#{img['height']}"
c.tile background.path
end
img = img.composite(background) do |c|
c.compose "ColorDodge"
end
You are correct in creating the texture image with the tile: format. Simply apply -negate option to invert the result. After which, a simple compose & composite command to apply the "Color Dodge" effect to any given image. See the Compose Examples article.
convert \( -size 1056x576 tile:Castillo_001.gif -negate \) \
source_image.jpg -compose Lighten -composite out_image.jpg
I would like to alter the processing of thumbnails in paperclip by having imagemagick apply a drop shadow to all the thumbnails. What I'm stuck on is the actual imagemagick command that would pull this little miracle off. Everything I've tried returns an incorrectly scaled drop shadow without the original image.
def transformation_command
scale, crop = #current_geometry.transformation_to(#target_geometry, crop?)
trans = ""
trans << " -resize \"#{scale}\""
trans << " -crop \"#{crop}\" +repage" if crop
# Apply Drop Shadow
trans << " #{convert_options}" if convert_options?
trans
end
One I've tried...
def transformation_command
scale, crop = #current_geometry.transformation_to(#target_geometry, crop?)
trans = ""
trans << " -resize \"#{scale}\""
trans << " -crop \"#{crop}\" +repage" if crop
trans << " \( +clone -background black -shadow 60x5+10+10 \) +swap -background none -layers merge +repage"
trans << " #{convert_options}" if convert_options?
trans
end
I'm completely new to imagemagick, any help would be greatly appreciated.
After some trial and error and burying my head in the docs, I finally figured it out.
has_attached_file :image,
:styles => { :thumb => ["100x100#", :png] },
:convert_options => { :thumb => '\( +clone -background black -shadow 70x4+0+0 \) +swap -background none -layers merge +repage' }
Make sure you have the latest version of ImageMagick installed.
["100x100#", :png] will convert the image to png so the drop shadow is transparent.
Under convert options, :thumb will only apply the conversion to the :thumb style, use :all to apply the conversion to all your styles.
Tweak "70x4+0+0" to get the shadow you want.
I find it a lot easier to just use the rmagick interface rather then sending command line options to imagemagick itself.
If you use rmagick you can use the shadow method.
img = Image.read('slide.png').first
shadow = img.shadow(0, 0, 0.0, '20%')
and then composite the image over the shadow.
I wrote an article on using rmagick: http://schf.uc.org/articles/2006/10/18/render-greatlooking-collages-with-ruby-and-rmagick
Try reading it over it might give you a better understanding.
I also wrote an abstraction lib to rmagick which attempts to make it even easier to use.
I called it RubyShop because it tried to mimic photoshop layer based compositing.. (I really hate the name and will probably change it if I ever resurrect the project)