Skip to content

Creating animated logo

kkrmno edited this page Dec 31, 2020 · 3 revisions

This example makes use of different dispose and blend operations to animate a logo together with different frame delays to adjust timing. The code also shows an example of applying a Gaussian blur. The logo is saved along with an ancillary tIME chunk saving information on when the image was last modified and a text chunk with a comment describing the image.

require 'imgrb'

#Scaling factor
scale = 1

#Scaled image and object sizes
width = (400*scale).round
height = width
center = [width/2, height/2]
small_radius = (width*0.075).round
small_size = small_radius*2 + 1

#Colors
small_circle_color = [255,111,100]
i_dot_color = [255, 190, 80]
i_color = [125, 210, 170]

#Radius of large circle being drawn
large_radius = (width/2 - small_radius*1.333).round

#Initial transparent black frame
logo = Imgrb::Image.new(width, height, [0, 0, 0, 0])

#Small circle used as brush to gradually paint the large circle
small_circle = Imgrb::Image.new(small_size, small_size, small_circle_color+[0])
small_circle.height.times do
  |y|
  small_circle.width.times do
    |x|
    xd = x - small_radius
    yd = y - small_radius
    dist = Math.sqrt(xd*xd + yd*yd)
    if dist <= small_radius
      small_circle.set_pixel(x, y, small_circle_color + [255])
    end
  end
end

#Apply a Gaussian blur with sigma = 1 to smooth out the edges of the "brush"
gauss = Imgrb::gaussian(1)
#2D convolution by 1D convolutions, since the Gaussian is separable.
small_circle_filtered = small_circle.convolve(gauss, :replicate)
                                    .convolve(gauss.transpose, :replicate)



#The "radius" of the dot of the i-shape
i_radius = (small_radius*0.5).round
i_size = i_radius*2+1

#The two parts of the i-shape
small_square = Imgrb::Image.new(i_size, i_size, i_dot_color+[255])
small_rectangle = Imgrb::Image.new(i_size, (3.333*i_size).round, i_color+[255])




#Start of drawing:
#===================================

#Paint the large circle using the small circle as a brush
angle_step = Math::PI/50
(0..2*Math::PI).step(angle_step).each do
  |theta|
  x = Math.cos(theta) * large_radius + center[0] - small_radius
  y = Math.sin(theta) * large_radius + center[1] - small_radius

  #Alpha overlay the brush (circle) at its new position without removing
  #pixels from previous frames. Play at 60 fps.
  logo.push_frame(small_circle_filtered, x.round, y.round, 1, 60, :none, :over)

end


#After the large circle is painted, display the stem of the i-shape for 0.2s
#in the middle of the circle
i_stem_x = center[0]-i_radius
i_stem_y = (center[1]-i_radius-large_radius*0.05).round
logo.push_frame(small_rectangle, i_stem_x, i_stem_y, 1, 5, :none, :over)

#Then add the dot of the i-shape, thus completing the logo. Display this for 3s
#The :previous dispose_op is used so that, after the logo is done displaying,
#the animation is reverted to the logo before drawing the dot of the i-shape.
#This is done so that the dot can be drawn again at a different position.
i_dot_x = center[0]-i_radius
i_dot_y = (center[1]-i_radius-large_radius*0.35).round
logo.push_frame(small_square, i_dot_x, i_dot_y, 3, 1, :previous, :over)

#Drop the dot of the i-shape and have it bounce on top of the stem once before
#falling out of frame.
x_speed = -width * 0.0012
y_speed = -width * 0.0175
gravity = width * 0.00175

bounced = false
70.times do
  #Use :previous so that the position of the dot can be updated by drawing on
  #top of the logo without the dot.
  logo.push_frame(small_square, i_dot_x.round, i_dot_y.round, 1, 60, :previous, :over)
  i_dot_x = i_dot_x + x_speed
  i_dot_y = i_dot_y + y_speed

  if (i_dot_y + i_size) > i_stem_y && !bounced
    i_dot_y = i_stem_y - i_size
    y_speed = -y_speed
    bounced = true
  end

  y_speed += gravity
end


#Add a 3s delay at the end of the animation before looping.
logo.set_frame_time(-1, 3, 1)

#Add a comment describing the image.
logo.add_text("Comment", "Animated logo for Imgrb.")
#Add tIME chunk showing latest modification to this image (UTC).
logo.add_chunk(Imgrb::Chunks::ChunktIME.assemble(Time.now.utc))
logo.save("imgrb_logo.png")
Clone this wiki locally