MiniMagick: Making a png partially opaque/how to use '-evaluate' - ruby

I am trying to make a partially opaque png using MiniMagick, but I guess what it really boils down to is the syntax for using '-evaluate'
This works in the terminal:
convert input.jpg -alpha on -channel a -evaluate set 25% output.png
But I don't quite understand how to turn it into minimagick code
This is (the latest permutation of) what I'm trying:
require 'mini_magick'
img = MiniMagick::Image.open('input.jpg')
img.combine_options do |mogrify|
mogrify.alpha 'on'
mogrify.channel 'a'
mogrify.evaluate 'set', '25%'
puts mogrify.inspect
end
img.write('output.png')
The inspect output shows that #args is #args=["-alpha", "\"on\"", "-channel", "\"a\"", "-evaluate", "\"set\"", "\"25%\""]
No error messages, but all I get is an identical copy of input.jpg

You are pretty much all the way there except that you also need to let minimagick know that you are outputting in PNG format using:
img.format('png')
Try this instead:
require 'mini_magick'
img = MiniMagick::Image.open('input.jpg')
img.format('png')
img.combine_options do |mogrify|
mogrify.alpha 'on'
mogrify.channel 'a'
mogrify.evaluate 'set', '25%'
end
img.write('output.png')

Related

MiniMagick Resize Image

I'm trying to use MiniMagick to resize 2 images and overlay one on top of the other. Heres the code I am using
require "mini_magick"
first_image = MiniMagick::Image.new("spider.jpg")
first_image = first_image.resize("250x250")
second_image = MiniMagick::Image.new("q.png")
second_image = second_image.resize("250x250")
result = first_image.composite(second_image) do |c|
c.compose "Over" # OverCompositeOp
c.gravity "center"
# c.resize("250x250")
end
result.write "output.jpg"
This overlays the images but neither is resized and the overlay image ends up awkwardly cropped. Ive tried making both the same size, making the bigger overlay image smaller and the smaller image bigger, but none seem to work. Any advice would be highly appreciated.

Imagemagick & Pillow generate malformed GIF frames

I need to extract the middle frame of a gif animation.
Imagemagick:
convert C:\temp\orig.gif -coalesce C:\temp\frame.jpg
generates the frames properly:
However when I extract a single frame:
convert C:\temp\orig.gif[4] -coalesce C:\temp\frame.jpg
then the frame is malformed, as if the -coalesce option was ignored:
Extraction of individual frames with Pillow and ffmpeg also results in malformed frames, tested on a couple of gifs.
Download gif: https://i.imgur.com/Aus8JpT.gif
I need to be able to extract middle frames of every gif version in either PIL, Imagemagick of ffmpeg (ideally PIL).
You are attempting to coalesce a single input image into single output image. What you got is what you asked for.
Instead you should "flatten" frames 0-4 into a single output image:
convert C:\temp\orig.gif[0-4] -flatten C:\temp\frame.jpg
If you use "-coalesce" you'll get 5 frames of output in frame-0.jpg through frame-4.jpg, the last of them being the image you wanted.
Ok, this script will find and save the middle frame of an animated GIF using Pillow.
It will also display the duration of the GIF by counting the milliseconds of each frame.
from PIL import Image
def iter_frames(im):
try:
i = 0
while 1:
im.seek(i)
frame = im.copy()
if i == 0:
# Save pallete of the first frame
palette = frame.getpalette()
else:
# Copy the pallete to the subsequent frames
frame.putpalette(palette)
yield frame
i += 1
except EOFError: # End of gif
pass
im = Image.open('animated.gif')
middle_frame_pos = int(im.n_frames / 2)
durations = []
for i, frame in enumerate(iter_frames(im)):
if i == middle_frame_pos:
middle_frame = frame.copy()
try:
durations.append(frame.info['duration'])
except KeyError:
pass
middle_frame.save('middle_frame.png', **frame.info)
duration = float("{:.2f}".format(sum(durations)))
print('Total duration: %d ms' % (duration))
Helpful code:
Python: Converting GIF frames to PNG
https://github.com/alimony/gifduration
You can do it like this:
convert pour.gif -coalesce -delete 0-3,5-8 frame4.png
Basically, it generates in full, all the frames and then deletes all frames other than from 4.

mini_magick thumbnail with gravity center

I want to create a padded thumbnail, like described here
This command works:
convert src.png -thumbnail '200x200>' -gravity center -extent '200x200' dst.png
But this ruby code is not working: gravity is ignored
require 'mini_magick'
image = MiniMagick::Image.open('src.png')
image.thumbnail '200x200>'
image.gravity 'center'
image.extent '200x200'
image.write 'dst.png'
What's wrong with this code?
You need to use combine_options with MiniMagick to roll all three of your commands together before you write it:
require 'mini_magick'
image = MiniMagick::Image.open('src.png')
image.combine_options do |c|
c.thumbnail '200x200>'
c.gravity 'center'
c.extent '200x200'
end
image.write 'dst.png'
More info on the GitHub docs

Add a rectangle to the image using image magic

Good day.
How to impose white_rectangle.jpg on logo.jpg in the image below
using Imagemagic.
And a bonus question: what's Ruby's method can make the task.
def (path_to_image)
# impose white_rectangle.jpg on logo
end
This can easily be accomplished using RMagick:
require 'RMagick'
logo = Magick::Image.read("logo.jpg").first
rect = Magick::Image.read("white_rectangle.jpg").first
result = logo.composite(rect, x, y, Magick::CopyCompositeOp)
result.write "result.jpg"
An alternative is to just draw a white rectangle without using a composite image:
image = Magick::Image.read("logo.jpg").first
gc = Magick::Draw.new
gc.stroke = 'white'
gc.fill = 'white'
gc.rectangle x_start, y_start, x_end, y_end
gc.draw(image)
image.write "result.jpg"
Using ImageMagick command line tools, you can overlay one image with another like this:
$ composite white_rectangle.jpg logo.jpg -geometry +x+y result.jpg

Can't get gravity to work with RMagick and 'caption'

I'm using RMagick 2.12.2 with ImageMagick 6.5.6-10 on Snow Leopard. I'm trying to put captions on a collection of photos, and I'm getting the caption to work (i.e. it appears on the image), but I can't get the gravity parameter to work correctly.
No matter what I set it to, I end up with some variation on NorthGravity.
For instance: Setting it to SouthWestGravity gives me NorthWestGravity. Setting it to SouthEastGravity gives me NorthEastGravity. Setting it to CenterGravity gives me NorthGravity.
In other words, I can't get the caption to come down off the top of the image.
I'd consider using "annotate," but I need "caption" so the lengthy caption text for each image will wrap.
What am I doing wrong?
Here's the code:
#!/usr/bin/env ruby
require "rubygems"
require "yaml"
require "RMagick"
include Magick
base_dir = "/Users/mike/Desktop/caption_test"
photo_log = File.open("#{base_dir}/photo_log.yaml" )
YAML::load_documents(photo_log) do |doc|
caption = doc["photo-caption"]
filename = doc["file"]
canvas = ImageList.new.from_blob(open("#{base_dir}/#{filename}") { |f| f.read } )
canvas << Magick::Image.read("caption:#{caption}") {
self.gravity = SouthWestGravity
self.size = "#{canvas.first.columns}"
self.font = "Helvetica Neue"
self.pointsize = 12
self.background_color = "#fff"
}.first
canvas.flatten_images.write("#{base_dir}/images/#{filename}")
end
You've probably long since moved on, but the I found a pretty simple answer to this--use
canvas.append(true).write("#{base_dir}/images/#{filename}")
In other words, you want the append option (use 'true' to stack vertically).
I think your problem is that you're applying the gravity to the dimensions of the caption image rather than the dimensions of the underlying image. Your caption will East/West align itself within its width but because it makes it own height, North/South always just mean North.
You probably want to specify the gravity on the flatten_images call instead which looks possible...

Resources