Forums | Admin

Discussion Forums: help

Start New Thread Start New Thread

 

By: Cullam Bruce-Lockhart
RE: Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-26 15:16
OK, stuck on a new snag! Everything has been going pretty smoothly of late, but now I need to worry about international characters. Given a .ttf with a full character set, is rmagick able to draw UTF-8 characters? Thanks!

By: Cullam Bruce-Lockhart
RE: Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-21 14:00
Nevermind, I've found an answer. Turns out there's a handy little method called get_type_metrics(text), which can be called on a draw object. Using the info from that, I should be able to get what I need.

By: Cullam Bruce-Lockhart
RE: Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-20 21:05
OK, here's a fun one:
Everything I've done so far is working wonderfully. But now there's a second part to all of this. I'm basically creating font sheets, so that you can save an image of all the glyphs you'll need in an application. However, in order to be able to use them, I'm going to need to place them correctly, once read off that font sheet. Which means I need to save the relevent positioning info for each glyph. Saving it is fine, I've got how to do that all set up. The tricky part is reading it in the first place.

I'm using ttf files. So I could either try to read the ttfs themselves and try to get the glyph metrics for each character. Or, I could try to get them from rmagick, as rmagick must use them somewhere, in order to correctly use the fonts. If possible, I'd prefer to get the metrics from rmagcik. Of course, as that's not what it's designed for, there doesn't seem to be a method for it. But rmagick is clearly using the information, so there should theoretically be a way for it to get passed to me so I can use it myself. Any thoughts?
-cullam

By: Cullam Bruce-Lockhart
RE: Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-19 20:00
As expected, it was something simple, having to do with me not being used to how rmagick works, (or ruby in general, for that matter). rather than using an image.composite, I used draw.composite, and made all relevant adjustments from there. Works just fine now! Now, on to generating all the font information needed for using the glyphs. Oh joy...
-cullam

By: Mike Leonard
RE: Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-19 19:07
I just noticed that composite! issue, too. I'm not sure why everything would be piling up in the middle, though. I messed with the code a little bit, to get something that would run on my end, and the glyphs are neatly arranged from left to right.

By: Cullam Bruce-Lockhart
RE: Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-19 19:01
Found one of the issues!! When I changed composite to composite!, I started getting the image created the way I want it. However, it's also creating the mess of glyphs in the middle. So I just need to figure out how to stop that from happening, but that should be easy enough.
-cullam

By: Cullam Bruce-Lockhart
RE: Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-19 18:07
Yeah, I came up with a way of ensuring that each row of characters has enough space for every character in it.

The trimx method could definitely come in handy. It occurred to me later that another way to do it might be to align the glyphs to one side, so you can calculate the width with trim, then crop the dimensions to that width, with the same height. That doesn't work if it's centred, but if the image is all the way to one side, then it should.

The thing I'm working on now that's giving me trouble is placing all the images on one file. I've got stuff written that moves a drawing point along so that it accommodates the width of every glyph, then moves down by the right amount when it reaches the end of the row (far enough to accommodate the tallest glyph in the previous row). I'm essentially doing this by drawing my image, just as before, but instead of writing it to a file, I add it to an images list, along with the master, and call composite on them, with the current drawing point for the x and y. However, this is not producing the result I expected. They are currently all drawing on top of each other. When I looked into it, it appears that primatives on an image all get redrawn from scratch every time the image is redrawn. So different font sizes and placements that I've specified might be being set to centre, and redrawn. Alternatively, I may just be doing something silly, or misunderstanding how the images are created.

What it boils down to, right now, is that once I create an image for a glyph, I want to paste it onto a master image, purely as rasterized information. This will update my tracking co-ordinates, so that I can paste the next image I create onto the next place over in the master. These places are not set up on a grid, but are determined by the ammount of space needed for each glyph. But like I said, what I'm doing now is just pasting them all on top of each other in the middle. Any quick points on where I've gone wrong?


def make_text_images
$FONT_COLLECTION.each do |font|
master = Magick::Image.new($MASTERWIDTH, $MASTERHEIGHT)
fontSheet = Magick::Draw.new
puts "Master is #{master.rows} pixels tall. "
lineheight = 0
drawpointy = 0
drawpointx = 0
puts "fonts, "
font.fontSize.each do |size|
$CHARARRAY.each do |char|
image = Magick::Image.new(2*size, 2*size) #these values still need to be adjusted.
glyph = Magick::Draw.new
glyph.font(font.fontPath)
glyph.gravity=Magick::CenterGravity
glyph.pointsize(size)
glyph.text(0,0,char)
glyph.draw(image)
width = image.trim!.columns
if image.trim.rows > lineheight
lineheight = image.trim.rows
end

if drawpointx + width >= $MASTERWIDTH
# We've reached the edge of the image, and don't have space for the next character. Start a new line, taking the height of the tallest glyph into account.
drawpointx = 0
drawpointy += lineheight
lineheight = 0
end
master.composite(image, drawpointx, drawpointy, Magick::OverCompositeOp)
fontsheet.draw(master) # This might not actually need to be drawn until the loop completes. Not sure yet.
drawpointx += width
end

end
master.write("#{$OUTPUT_DIR}#{font.fontName}.png")
end

end

By: Mike Leonard
RE: Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-18 22:29
Two quick things:

1. I realized that my earlier code was flawed. It only worked because the upper case J in Helvetica extends as high above the baseline as the capital letters. This will get you the right number (defined here as total_height) to use for the height, if you haven't figured it out yet:

characters = "ABCDEFGHIjKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
family = "Helvetica"
size = 50

i = Magick::Image.new(2000,1000)
glyph = Draw.new
glyph.fill('cmyka(0,0,0,99%)')
glyph.stroke('cmyk(0,0,0,99%)')
glyph.opacity(1)
glyph.font_family(family)
glyph.text_antialias(false)
glyph.gravity=Magick::CenterGravity
glyph.pointsize(size)
glyph.text(0,0,characters)
glyph.draw(i)
i.trim!
total_height = i.rows


2. I took a stab at writing a trimx method. It isn't pretty, but it seems to work:

class Image
def trimx
collision = false
x1 = 0
result = self.copy
until collision == true
pixels = self.dispatch(x1, 0, 1, self.rows, "RGBA")
a_column = Image.constitute(1, self.rows, "RGBA", pixels)
#check whether the column contains any nonwhite pixels
white_pixel = Pixel.from_color("white")
h = a_column.color_histogram
h.delete(white_pixel)
if h.length > 0 then collision = true end
x1 += 1
end
result.crop!(x1,0,self.columns-x1, self.rows)
x2 = self.columns
collision = false
until collision == true
pixels = self.dispatch(x2, 0, 1, self.rows, "RGBA")
a_column = Image.constitute(1, self.rows, "RGBA", pixels)
#check whether the column contains any nonwhite pixels
white_pixel = Pixel.from_color("white")
h = a_column.color_histogram
h.delete(white_pixel)
if h.length > 0 then collision = true end
x2 -= 1
end
result.crop!(0,0,x2,self.rows)
return result
end
end

By: Cullam Bruce-Lockhart
RE: Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-18 19:03
Not all glyphs are centred. I could crop using the width from trim.columns, and setting an x and y. The y would be zero, obviously, but I haven't yet spotted a way to get the x-offset. Alternatively, I could modify the trim source to create a trimX and trimY. Because with that source code in front of me, those would be really easy to make. I'll have to see if I can find that.
-cullam

By: Mike Leonard
RE: Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-18 17:38
Not to my knowledge, though it probably wouldn't be difficult to implement. This will almost do it, but won't work if the glyph is not perfectly centered in the image:

def trimx!
new_width = self.trim.columns
self.crop!(Magick::CenterGravity, new_width, self.rows)
end

Depending on your requirements, you could just add in some padding to account for this.

By: Cullam Bruce-Lockhart
RE: Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-18 17:20
Is there a method that would trim in one dimension only? Something along the lines of .trimx? I'd like to get all the glyphs with the same height (aka, do exactly what you suggested), but trim the widths down to exactly how much each individual glyph needs. So an i would be thinner than an m, etc.
-cullam

By: Mike Leonard
RE: Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-18 16:14
Always happy to help. Good luck with the project!

By: Cullam Bruce-Lockhart
RE: Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-18 16:11
Sorry, that was a combination of me misunderstanding what you'd last posted, and my project requirements subtly changing today. Yes, what you've posted does exactly what I was asking about - thanks!

Now my requirements are for me to make one image file with all the glyphs, and then a separate file that says where to find any needed glyph on said png, and where to draw it when adding it to a text image. (This was NOT something I asked about previously). Obviously, putting together the one big image file shouldn't be an issue. I just need to figure out how to retrieve the coordinate system for each glyph from the ttf file. But I don't need help with that one as of yet, as I'm still reading up on it, and haven't gotten stuck enough to need bailing out, just yet. Thanks for all the help with this! It was definitely useful.
-cullam

By: Mike Leonard
RE: Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-18 16:02
I guess I'm having a hard time understanding what you're trying to do. The above script won't add the same amount of space to the top and bottom of the smaller characters. A lowercase Y will get some space added at the top and none at the bottom, while an uppercase B will get none at the top and some at the bottom. All of the characters seem to end up positioned correctly relative to each other—they all look like they're on the same baseline if you line up the output images side by side.

Sorry that I couldn't be of more assistance, but please do post again if you have any more specific questions.

--Mike

By: Cullam Bruce-Lockhart
RE: Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-18 15:17
That still doesn't deal with the issue of vertical alignment. Even if they're all trimmed to their exact size, that's fine, as long as there is some way I can look up and save their baseline. I could create a table easy enough where each glyph could have it's vertical placement value stored, as long as I can somehow get that from the font.... hmmm... I'll mess around with it, see what I can find. The info is there somewhere! As always, I appreciate the assistance!!
-cullam

By: Mike Leonard
RE: Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-18 14:59
Ah, I didn't realize that you needed the glyphs to be positioned correctly relative to each other. I don't know of an exact RMagick equivalent for the ImageMagick command that you posted, but you could do two passes: one to figure out what the tallest character is and the second to actually output all of the files. There's probably a more efficient way to do this, but this worked for me:

#figure out height of tallest and width of the widest characters
tallest = 0
widest = 0
characters.each_char do |c|
i = Magick::Image.new(100,100)
glyph = Draw.new
glyph.fill('black')
glyph.stroke('black')
glyph.opacity(1)
glyph.font_family(family)
glyph.text_antialias(false)
glyph.gravity=Magick::CenterGravity
glyph.pointsize(size)
glyph.text(0,0,c)
glyph.draw(i)
i.trim!
if i.rows > tallest then tallest = i.rows end
if i.columns > widest then widest = i.columns end
end

characters.each_char do |c|
#use the height and width from above to set the image dimensions:
i = Magick::Image.new(widest,tallest)
glyph = Draw.new
glyph.fill('black')
glyph.stroke('black')
glyph.opacity(1)
glyph.font_family(family)
glyph.text_antialias(false)
glyph.gravity=Magick::CenterGravity
glyph.pointsize(size)
glyph.text(0,0,c)
glyph.draw(i)
i.write(c+".jpg")
end

By: Cullam Bruce-Lockhart
RE: Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-18 14:27
Ok, I've basically gotten that working. A few gremlins to track down, but those are on my end, so that's fine.

The problem with using a border is that it would add the same amount to the top and bottom regardless of the character, wouldn't it? But a y doesn't need as much extra space on the bottom, and a b doesn't need as much extra on the top. When used the convert command in ImageMagick, and added the text by attaching a label, this height placement was done automatically. Is there a way to re-create the exact command in RMagick, or is there not that sort of 1 to 1 correspondence? Thanks for the assistance!
-cullam

By: Mike Leonard
RE: Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-18 06:36
I think trim will do what you're trying to accomplish. The code below will generate one file each for every character in a string, with each image cropped to exactly the dimensions of its glyph. It would be a little trickier to get each individual image to be as tall as the tallest character in the string, but you could do it by generating the images, trimming them, figuring out which one is the tallest, and then adding a border to the others to make up the difference.

characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
family = "Helvetica"
size = 36

characters.each_char do |c|
i = Magick::Image.new(100,100)
glyph = Draw.new
glyph.fill('black')
glyph.stroke('black')
glyph.font_family(family)
glyph.gravity=Magick::CenterGravity
glyph.pointsize(size)
glyph.text(0,0,c)
glyph.draw(i)
i.trim!
i.write(c+".jpg")
end



By: Cullam Bruce-Lockhart
Reproducing an ImageMagick command in RMagick [ reply ]  
2011-01-17 21:51
So I've just started using RMagick. I'm making a tool for generating images of glyphs for a given set of fonts, sizes, and text. I got it working perfectly by generating a ImageMagick command string in ruby, and sending it to the command prompt. I'm now working on getting the exact same thing to happen with RMagic. Most of it is fine, but I'm having one slight hitch: I haven't figured out a way to get it to draw a letter without giving it a pre-specified canvas.

The command I use, which does exactly what I need it to do is:

"convert -font #{theFont.fontPath} -background none -gravity center -pointsize #{size} label:\"#{text}\" #{$OUTPUT_DIR}\"#{text}\"-#{size}.png"

When I run this, it generates a png that is the exact width of the glyph, and has enough height to accommodate any character in the font. So to try to do the same thing in RMagick, this is what I have (inside some blocks and such):

glyph = Magick::Draw.new
glyph.font(font.fontName)
glyph.gravity=Magick::CenterGravity
glyph.pointsize(size)
text = Magick::Image.new(0,0)
text['Label']=char
glyph.draw(text)

This isn't right, I know. I've seen examples where you add text to an image using annotate, but you always had to specify the image size, and I want to just take whatever size the glyph needs. I'm sure this is simple, but I only started using rmagick today, and am not very familiar with it yet. Does anyone know what it is that I need to do here? Thanks so much!
-cullam