module MemeCaptain
Constants
- VERSION
Public Instance Methods
meme(input, text_poss, options={})
click to toggle source
Create a meme image.
Input can be an IO object or a blob of data. text_poss is an enumerable of TextPos
objects containing text, position and style options.
Options:
super_sample - work this many times larger before shrinking
# File lib/meme_captain/meme.rb, line 14 def meme(input, text_poss, options={}) img = Magick::ImageList.new if input.respond_to?(:read) img.from_blob(input.read) else img.from_blob(input) end img.auto_orient! super_sample = options[:super_sample] || 1.0 text_layer = Magick::Image.new( img.page.width * super_sample, img.page.height * super_sample) { self.background_color = 'none' } text_poss.each do |text_pos| caption = Caption.new(text_pos.text) if caption.drawable? wrap_tries = (1..text_pos.max_lines).map { |num_lines| caption.wrap(num_lines).upcase.annotate_quote }.uniq text_x = (text_pos.x.is_a?(Float) ? img.page.width * text_pos.x : text_pos.x) * super_sample text_y = (text_pos.y.is_a?(Float) ? img.page.height * text_pos.y : text_pos.y) * super_sample text_width = (text_pos.width.is_a?(Float) ? img.page.width * text_pos.width : text_pos.width) * super_sample text_height = (text_pos.height.is_a?(Float) ? img.page.height * text_pos.height : text_pos.height) * super_sample min_pointsize = text_pos.min_pointsize * super_sample draw = Magick::Draw.new.extend(Draw) text_pos.draw_options.each do |k,v| # options that need to be scaled by super sample if [ :stroke_width ].include?(k) v *= super_sample end draw.send("#{k}=", v) end choices = wrap_tries.map do |wrap_try| pointsize, metrics = draw.calc_pointsize(text_width, text_height, wrap_try, min_pointsize) CaptionChoice.new(pointsize, metrics, wrap_try, text_width, text_height) end choice = choices.max draw.pointsize = choice.pointsize draw.annotate text_layer, text_width, text_height, text_x, text_y, choice.text text_layer.virtual_pixel_method = Magick::TransparentVirtualPixelMethod text_layer = text_layer.blur_channel(text_pos.draw_options[:stroke_width] / 2.0, text_pos.draw_options[:stroke_width] / 4.0, Magick::OpacityChannel) draw.stroke = 'none' draw.annotate text_layer, text_width, text_height, text_x, text_y, choice.text end end if super_sample != 1 text_layer.resize!(1.0 / super_sample) text_layer = text_layer.unsharp_mask end img.each do |frame| frame.composite!(text_layer, -frame.page.x, -frame.page.y, Magick::OverCompositeOp) frame.strip! end text_layer.destroy! img end
meme_top_bottom(input, top_text, bottom_text, options={})
click to toggle source
Shortcut to generate a typical meme with text at the top and bottom.
# File lib/meme_captain/meme.rb, line 108 def meme_top_bottom(input, top_text, bottom_text, options={}) meme(input, [ TextPos.new(top_text, 0.05, 0, 0.9, 0.25, options), TextPos.new(bottom_text, 0.05, 0.75, 0.9, 0.25, options) ]) end
memebg(size, colors, num_rays, &block)
click to toggle source
Public: Generate a pie slice meme background.
size - The side length in pixels of the generated image. colors - An Array of color strings (any values that RMagick accepts). num_rays - The Fixnum of rays to create. block - An optiona block passed to Draw.new for specifying additional
draw options
Examples
memebg(400, %w{red orange yellow green blue indigo violet}, 20) { # draw options # self.stroke = 'white' }.display
Returns a Magick::Image of the meme background.
# File lib/meme_captain/memebg.rb, line 23 def memebg(size, colors, num_rays, &block) # make circle 5% too big to avoid empty space at corners from rounding # errors circle_radius = Math.sqrt(2 * ((size / 2.0) ** 2)) * 1.05 side_len = 2 * circle_radius start_x = side_len start_y = circle_radius center = "#{circle_radius},#{circle_radius}" img = Magick::Image.new(side_len, side_len) color_cycle = colors.cycle (1..num_rays).each do |ray_index| ray_radius = 2 * Math::PI / num_rays * ray_index end_x = circle_radius + (Math.cos(ray_radius) * circle_radius) end_y = circle_radius - (Math.sin(ray_radius) * circle_radius) svg = "M#{center} L#{start_x},#{start_y} A#{center} 0 0,0 #{end_x},#{end_y} z" draw = Magick::Draw.new { instance_eval(&block) if block_given? self.fill = color_cycle.next } draw.path svg draw.draw img start_x = end_x start_y = end_y end img.crop! Magick::CenterGravity, size, size end