Understanding Imagemagick's Convert and Translating to Ruby Rmagick

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

  1. RMagick Documentation
  2. ImageMagick 'fx' escapes
  3. 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.

Where is Center?

Shifted left by 150px, and down by 150px.

Now compare compare NorthWestGravity position.

Where is NorthWest?

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')

gravity with text

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



Leave a reply



Submit