Skip to content

Instantly share code, notes, and snippets.

@gurgeous
Created July 9, 2015 21:21
Show Gist options
  • Save gurgeous/874bc58f2fe79620fe8a to your computer and use it in GitHub Desktop.
Save gurgeous/874bc58f2fe79620fe8a to your computer and use it in GitHub Desktop.
RMagick - autoscale text within a box, like iOS UILabel
class Magick::Draw
# Autoscale text within a box. The text will be scaled to fit if the
# specified pointsize is too big. If minscale is set and the text still
# won't fit at minscale * pointsize, it gets ellipsized. halign/valign can
# be used to set horizontal and vertical alignment. This is similar to the
# behavior of iOS UILabel.
def annotate_box(image:, text:, x:, y:, w:, h:, pointsize:, minscale: nil, halign: 0, valign: 0)
draw = self.clone
draw.pointsize = pointsize
draw.gravity = Magick::NorthWestGravity
metrics = draw.get_type_metrics(text)
tw, th = metrics[:width], metrics[:height]
#
# does the text exceed the box? scale/ellipsize if necessary
#
if tw > w || th > h
scale = [ w / tw, h / th ].min
if !minscale || scale > minscale
# the new scale is valid
draw.pointsize = pointsize * scale
else
# ellipsize at minscale - how much can we fit?
draw.pointsize = pointsize * minscale
truncated = ""
0.upto(text.length) do |len|
might_fit = "#{text[0, len].strip}…"
break if draw.get_type_metrics(might_fit)[:width] > w
truncated = might_fit
end
text = truncated
end
metrics = draw.get_type_metrics(text)
tw, th = metrics[:width], metrics[:height]
end
#
# alignment
#
dx = case halign
when -1 then 0
when 1 then w - tw
else (w - tw) / 2
end
dy = case valign
when -1 then 0
when 1 then h - th
else (h - th) / 2
end
draw.annotate(image, 0, 0, x + dx, y + dy, text)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment