Cropping transparent pixels with carrierwave - imagemagick

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.

Related

crop / swap parts of image with magick mogrify

I am trying to crop and swap different parts of a big 800x800 image and re-create 800x800 image using imagemagick with this command.
magick mogrify titli.gif -crop 2x4# +repage -reverse -append -path converted titli.gif
my problem is "-append" creates tall image (400x1600) & "+append" creates wide image (3200x200)
How can I get a large image of original size 800x800 but with cropped and swapped (reversed) parts set in "mosaic or tiled" style...
If I understand the question, you shouldn't need "mogrify" to do that. Just "magick" should accomplish that task.
It looks like you'll have to crop the image into 8 pieces, reverse them, and "-append" them vertically as you've done.
Then after that, and in the same command, you'll need to crop that result in half vertically and "+append" those two pieces horizontally to get the 800x800 output.
This example command shows how it works...
magick in.png -crop 2x4# -reverse -append -crop 1x2# +append out.png
If you're doing any more operations within the same command you'll probably want to use "+repage" after the "+append" to reset the image geometry back to WxH+0+0.

Imagemagick how to apply gravity and extent to only short images

I have a web page where I list images that should be 600px by 600px (width & height). So I resize all big images to 600x600 using imagemagick, which works fine.
However, some images, when I resize them (in order to keep their aspect ratio), get resized to a size smaller than 600px in height (for example 600x450). So I tried to fill the needed height by using imagemagick options (gravity, background, and extent) like so :
image.combine_options do |img|
img.crop('1200x1200+0+0')
img.resize '600x600'
img.background 'white'
img.extent '600x600'
img.gravity 'center'
end
That gave me what I want for these kind of images (short images). However, this effect of centering is applied to the other images (bigger ones) as well ! Is there any way to prevent that ?
Update:
Just to show you what I mean, I made up this example... if I don't add extent and gravity the image will start from the top left corner
but if I add extent and gravity (center) the image will start from the center, something like this :
I want only images that result on resized images smaller than 600x600 to be centered, but in the example as you see even an image that get resized to exact 600x600 get centered !! that's not what I want
the solution :
I end up using shell command using system function in ruby
system "convert #{image.path} -crop 1024x1024+0+0 -resize 600x600 -background white -gravity center -extent 600x600 output.png"
and that worked fine! I don't know why minimagick wasn't working correctly, but I just get rid of that gem from my gemfile which is fine too.
Here is your command in command line Imagemagick with proper resetting of the virtual canvas after the crop.
convert image -crop 1200x1200+0+0 +repage -resize 600x600 -background white -gravity center -extent 600x600 result
Here are two results with slightly different resize arguments. It looks like your commands are using the equivalent of the ^ flag set on the resize argument.
Input:
Proper result without the ^ flag: (Note padded with white)
convert wiki.png -crop 1200x1200+0+0 +repage -resize 600x600 -background white -gravity center -extent 600x600 result1.png
Result with the ^ flag: (Note cropped)
convert wiki.png -crop 1200x1200+0+0 +repage -resize 600x600^ -background white -gravity center -extent 600x600 result2.png
The above is Unix syntax. For Windows double the ^ to ^^, since ^ is an escape character in Windows.
Perhaps your issue is with minimagick and not Imagemagick. You can check by testing my command line.

Is there anyway I an detect transparent pixels in an image using rmagick?

I am using Rmagick to generate icons for iOS. And for this I need to remove transparency. For now I am deactivating the alpha channel and flattening all the images. Here is the code I use for this.
app_store_icon = ImageList.new(app_store_icon_url)
app_store_icon.alpha(DeactivateAlphaChannel)
app_store_icon.flatten_images
But I would like to avoid this unnecessary steps if the user uploads a proper png image without transparency. So how do check if there are any transparency in the image and do the above stpes only if required?
In command line Imagemagick, extract the alpha channel and test if its average is less than 1. If so, then it has transparency. If exactly 1, then no transparency.
value=$(convert image -alpha extract -format "%[fx:mean]" info:)
or
value=$(convert image -alpha extract -scale 1x1! -format "%[fx:u]" info:)
if [ "$value" = 1 ]; then
echo "opaque"
else
echo "transparent"
fi
Sorry, I do not know RMagick.
Try if this way is ok for you: composite the image to a white background of the image size. For example, given the alpha channel image img.png:
require 'rmagick'
include Magick
image = Magick::Image.read("img.png").first
w = image.columns
h = image.rows
if image.alpha?
bg = Image.new(w,h) { self.background_color = "white" } # create a white background
image = bg.composite(image, NorthWestGravity, 0, 0, OverCompositeOp) # compose
end
image.write("img_out.png")
Look for rmagick constants.

ImageMagick convert format, crop and resize

I have a large number of research pdf figures, and I need to preform the following actions in ImageMagick:
convert all pdf to png
crop png from left/top corner x:334/y:244; from right/bottom corner x:214/y:340;
original size 2100x2100, cropped size 1552x1552 pixels
resize cropped png to 240x240 pixels
Here is how it should be cropped for point 2, the pink area is what I want to have:
I was only be able to get 1st action done with my knowledge:
mogrify -format png -density 300 -flatten *.pdf
How can I do the 2nd and 3rd actions please? And do I need to run three separated commands or could they be combined into one command?
I do not know what exact order you need for mogrify as I do not use it. I also do not know why you need flatten Try:
mogrify -format png -density 300 -crop 1552x1552+344+244 +repage -resize 240x240 *.pdf

How can I overlay a larger watermark/frame image on a smaller one?

I have an overlay image, which is like a watermark/logo, which needs to be overlayed on top of the source image (while preserving alpha channel, etc)
When overlay is the same or smaller dimension as the source image - things are easy:
composite.exe -alpha on -gravity center logo.png in_image.jpg out_image.jpg
However, when logo.png is larger than in_image.jpg - above call truncates the logo, and out_image.jpg has the same dimensions as in_image.jpg
I would like the resulting image to be the largest of either the logo.png or in_image.jpg so I can do things like artistic frames around the photos.
Below image demonstrates the end result I want to be able to get this:
Desired Result
Note, here, the png with skulls has larger dims than the kiddo's image. The alpha channel needs to be preserved.
Edit: more clarity through examples
Here is another desired result
Here, the png file is opaque on the sides, has a clear window in the middle, and half-translucent bubbles. the JPG file is just a regular JPG from a camera.
Would love to add original and logo files that result in it, but lack reputation to add more than 2 links (or to add images)
Updated Answer
If you have v7 of ImageMagick, you can get it to do the maths for you all in one line using -fx to determine the dimensions of the larger of the two images:
magick background.jpg overlay.png -background none -gravity center -extent '%[fx:u.w>v.w?u.w:v.w]x%[fx:u.h>v.h?u.h:v.h]' -composite result.png
That basically says... "Extend the two images as follows. If the width of the first image (u.w) is greater than that of the second image (v.w), then use the width of the first, else use that of the second. Same for height.".
Original Answer
I believe you want this. Get width of whatever is wider of background and overlay. Get height of whatever is taller of background and overlay. Extend both background and overlay with transparent pixels to new dimensions. Overlay.
So, if we start with this as background (300x50):
And this as overlay (122x242) - which is a tall blue rectangle surrounded with transparency then that is bordered in black to show the extent of it:
You would run this, which is actually very simple but it is full of comments and debug output so you can see what is going on:
#!/bin/bash
# Get background width and height
read wb hb < <(convert background.jpg -format "%w %h" info: )
echo "Background: " $wb $hb
# Get overlay width and height
read wo ho < <(convert overlay.png -format "%w %h" info: )
echo "Overlay: " $wo $ho
# Get wider of the two
w=$wb
[ $wo -gt $w ] && w=$wo
# Get taller of the two
h=$hb
[ $ho -gt $h ] && h=$ho
echo "New dimensions: " $w $h
convert background.jpg overlay.png -background none -gravity center -extent ${w}x${h} -composite result.png
Here is how it looks running:
Background: 300 50
Overlay: 122 242
New dimensions: 300 242
Presumably, when you have done your overlay, you would add -trim as the final part of the command line to remove any extraneous stuff that has been added.
Try using convert rather than composite. It is more flexible than composite.
convert logo.png in_image.jpg -gravity center -compose over -composite out_image.jpg
But if you insist on using composite, then
composite in_image.jpg logo.png -gravity center -compose src_over out_image.jpg
Note sure exactly what you mean by preserving the alpha channel, since jpg does not support transparency. Perhaps you can post a pair of inputs and your desired output, if what I have posted does not do what you want.

Resources