Understanding ImageMagick's convert and translating to Ruby RMagick
The code checks to see if a particular image contains transparency.
-format '%[fx:u.a]' info:
This instructs image magick to check the first image u
, the alpha channel of that a
and output info on it, it will return 0 if the top-left pixel is transparent and non-zero if not I think. That is why the image is being resized to 1x1, so that only a single pixel needs to be consulted. The -channel o
is the opacity channel.
So the code in English would read, cycle through all PNG files, look at the alpha channel (opacity) only, resize to a single pixel and see if it's transparent. Hence the echo message.
Unfortunately I do not know Ruby, or RMagick, but a quick look at the API seems to suggest using image.channel(AlphaChannel)
to get the alpha channel (AlphaChannel
is a ChannelType
value, not sure if you have to specify ChannelType.AlphaChannel
), then follow with .resize(1,1)
to get the size down, and finish with either .pixel_color(0,0)
or .get_pixels(0,0,1,1)
to get the Pixel
object back (get_pixels()
returns an array), which I believe has an opacity
attribute. However, the channel()
command changes the RGB values to the value of the channel selected, and I'm not sure it preserves the opacity channel so you might just need to look at red forinstance, or omit the .channel()
call entirely - though I do not know if that would disrupt the result offhand.
Perhaps if Ruby supports decent functional programming approaches.
image.channel(AlphaChannel).resize(1,1).pixel_color(0,0).red
or this if pixel_color()
does not return the opacity for some reason
image.channel(AlphaChannel).resize(1,1).get_pixels(0,0,1,1)[0].red
Without the channel()
calls it would be:
image.resize(1,1).pixel_color(0,0).opacity
or
image.resize(1,1).get_pixels(0,0,1,1)[0].opacity
Again, my Ruby is non-existent, so you may have to rearrange those a lot, but the primitives are there.
References
- RMagick Documentation
- ImageMagick 'fx' escapes
- ImageMagick -channel options
ImageMagick: What is this convert-command doing?
Seems like it is computing the average opacity. The info
format is a dummy image format that will instruct convert to output image information to stdout (:
means stdout) in the format %[fx:u.a]
. Resizing to 1x1 is probably a way of averaging.
RMagick remove white background from image and make it transparent
convert image.png -matte -fill none -fuzz 1% -opaque white result.png
Replaces anything white with transparency. The fuzz option includes anything that is almost-white.
Ruby: Find non-transparent PNG and convert into JPG
Checking the alpha channel seems the most sensible thing to do. Is it safe to assume you are using RMagick? did you read the documentation?
>> require 'RMagick'
>> image = Magick::Image.read("a.png").first
>> image.alpha?
=> true
http://www.imagemagick.org/RMagick/doc/image1.html#alpha_q
Translate ImageMagick CLI into MiniMagick gem
Solved it:
c = MiniMagick::Tool::Convert.new
c.xc("cmyk(255,0,0,0)")
c.profile(File.open("lib/assets/USWebCoatedSWOP.icc").path)
c.profile(File.open("lib/assets/sRGB_IEC61966-2-1_black_scaled.icc").path)
c.format("%[pixel:u.p{0,0}]\n", "info:")
c.call
The trick was locating accurate profile paths and then entering "info:" as a separate second argument in the format
method.
Getting RMagick/ImageMagick gravity with text
I suppose its something in ImageMagick's gravity concept that I can't get.
What is it?..
The key to understanding what's going on is to locate the CenterGravity text.
Shifted left by 150px, and down by 150px.
Now compare compare NorthWestGravity position.
Also translated left & down by 150px respectively. Seeing a trend?
Your issue is with this line...
draw.text 150, 150, g
The Magick::Draw
API maps to MVG spec. Use Magick::Draw.push
& Magick::Draw.pop
to control drawing context.
Edit from comments...
For setting the origin of text to be drawing, you'll need to calculate the position after evaluation the text/type metrics.
Example.
require 'rmagick'
include Magick
img = Image.new(300, 300) {
self.background_color = "palegreen"
}
draw = Draw.new
dotes = Draw.new # Dotes added for point of origin
dotes.fill = "red"
cursor = 1
# for each of known gravity constants...
%w[NorthWestGravity NorthGravity NorthEastGravity WestGravity CenterGravity EastGravity SouthWestGravity SouthGravity SouthEastGravity].
each{|g|
offsetX = 150
offsetY = cursor * 25
dotes.circle offsetX, offsetY, offsetX+2, offsetY+2
# Get metrics of text
metrics = draw.get_type_metrics(img, g)
# Full width
if %w[NorthWestGravity WestGravity SouthWestGravity].include? g then
offsetX -= metrics[:width]
end
# Full height
if %w[SouthWestGravity SouthGravity SouthEastGravity].include? g then
offsetY += metrics[:ascent]
end
# Half width
if %w[NorthGravity SouthGravity CenterGravity].include? g then
offsetX -= metrics[:width] / 2
end
# Half height
if %w[WestGravity CenterGravity EastGravity].include? g then
offsetY += metrics[:ascent] / 2
end
draw.text offsetX, offsetY, g
cursor += 1
}
dotes.draw(img)
draw.draw(img)
img.write('output.png')
How to stop ImageMagick in Ruby (Rmagick) evaluating an @ sign in text annotation
This is the C code from RMagick that is returning the error:
// Translate & store in Draw structure
draw->info->text = InterpretImageProperties(NULL, image, StringValuePtr(text));
if (!draw->info->text)
{
rb_raise(rb_eArgError, "no text");
}
It is the call to InterpretImageProperties
that is modifying the input text - but it is not Ruby, or a Ruby instance variable that it is trying to reference. The function is defined here in the Image Magick core library: http://www.imagemagick.org/api/MagickCore/property_8c_source.html#l02966
Look a bit further down, and you can see the code:
/* handle a '@' replace string from file */
if (*p == '@') {
p++;
if (*p != '-' && (IsPathAccessible(p) == MagickFalse) ) {
(void) ThrowMagickException(&image->exception,GetMagickModule(),
OptionError,"UnableToAccessPath","%s",p);
return((char *) NULL);
}
return(FileToString(p,~0,&image->exception));
}
In summary, this is a core library feature which will attempt to load text from file (named SomeTwitterUser
in your case, I have confirmed this -try it!), and your work-around is probably the best you can do.
For efficiency, and minimal changes to input strings, you could rely on the selectivity of the library code and only modify the string if it starts with @
:
@text.annotate( @image, 0,0,200,54, @name_string.gsub( /^@/, '\@') )
Related Topics
How to Include External CSS and Js File in Laravel 5
PHP Sessions in a Load Balancing Cluster - How
Laravel Advanced Wheres How to Pass Variable into Function
How to Handle User Input of Invalid Utf-8 Characters
Simple PHP Form: Attachment to Email (Code Golf)
Pull All Images from a Specified Directory and Then Display Them
Pdo Try-Catch Usage in Functions
Phpmyadmin Automatic Logout Time
Issues with PHP 5.3 and Sessions Folder
How to Access a Property of an Object (Stdclass Object) Member/Element of an Array
What's the Most Efficient Test of Whether a PHP String Ends with Another String