Class: Gifenc::Gif
- Inherits:
-
Object
- Object
- Gifenc::Gif
- Defined in:
- lib/gif.rb
Overview
Represents a GIF file, possibly composed of multiple images. Note that each image in a GIF file is not necessarily an animation frame, they could also be still images that should be layered on top of each other.
Constant Summary collapse
- HEADER =
6-byte block indicating the beginning of the GIF data stream. It is composed of the signature (GIF) and the version (89a).
'GIF89a'
- TRAILER =
1-byte block indicating the termination of the GIF data stream.
';'
Instance Attribute Summary collapse
-
#ar ⇒ Integer
Aspect ratio of the pixels.
-
#bg ⇒ Integer
Index of the background color in the Global Color Table.
-
#color ⇒ Integer
The default color of the GIF's images.
-
#delay ⇒ Integer
The default delay to use between images, in 1/100ths of a second.
-
#destroy ⇒ Boolean
Automatically destroy each image right after processing it during encoding.
-
#disposal ⇒ Integer
The default disposal method to use for every image in the GIF.
-
#extensions ⇒ Array<Extension>
The array of global extensions present in the GIF.
-
#gct ⇒ ColorTable
The Global Color Table.
-
#height ⇒ Integer
readonly
The height of the GIF's logical screen, i.e., its canvas.
-
#images ⇒ Array<Image>
The array of images present in the GIF.
-
#loops ⇒ Integer
The amount of times to loop the GIF.
-
#trans_color ⇒ Integer
The index of the default color to use as transparent.
-
#width ⇒ Integer
readonly
The width of the GIF's logical screen, i.e., its canvas.
Instance Method Summary collapse
-
#boomerang(first: false) ⇒ Gif
Duplicates all frames in reverse order.
-
#cycle ⇒ Gif
Shortcut to loop the GIF indefinitely.
-
#encode(stream) ⇒ Object
Encode all the data as a GIF file and write it to a stream.
-
#exhibit(delay = DEFAULT_EXHIBIT_TIME) ⇒ Gif
Shortcut to modify the delay of the GIF's last frame, intended to showcase the final result before looping it.
-
#initialize(width, height, gct: nil, color: DEFAULT_COLOR, interlace: DEFAULT_INTERLACE, delay: nil, trans_color: nil, disposal: nil, loops: DEFAULT_LOOPS, bg: DEFAULT_BACKGROUND, ar: DEFAULT_ASPECT_RATIO, destroy: false) ⇒ Gif
constructor
Creates a new GIF object.
-
#resize(width, height) ⇒ Object
Change the dimensions of the GIF's logical screen, i.e, its canvas.
-
#save(filename) ⇒ Object
Encode and write the GIF to a file.
-
#still ⇒ Gif
Shortcut to not loop the GIF at all.
-
#write ⇒ String
Encode and write the GIF to a string.
Constructor Details
#initialize(width, height, gct: nil, color: DEFAULT_COLOR, interlace: DEFAULT_INTERLACE, delay: nil, trans_color: nil, disposal: nil, loops: DEFAULT_LOOPS, bg: DEFAULT_BACKGROUND, ar: DEFAULT_ASPECT_RATIO, destroy: false) ⇒ Gif
Creates a new GIF object.
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/gif.rb', line 118 def initialize( width, height, gct: nil, color: DEFAULT_COLOR, interlace: DEFAULT_INTERLACE, delay: nil, trans_color: nil, disposal: nil, loops: DEFAULT_LOOPS, bg: DEFAULT_BACKGROUND, ar: DEFAULT_ASPECT_RATIO, destroy: false ) # GIF attributes @width = width @height = height @bg = bg @ar = ar @gct = gct # Default image attributes @color = color @interlace = interlace @delay = delay @trans_color = trans_color @disposal = disposal # GIF content data @images = [] @extensions = [] # Other @destroy = destroy # If we want the GIF to loop, then add the Netscape Extension self.loops = loops end |
Instance Attribute Details
#ar ⇒ Integer
This field is ignored by most decoders, which instead render all pixels square.
Aspect ratio of the pixels. If provided (ar > 0
), the aspect ratio is
calculated as (ar + 15) / 64, which allows for ratios roughly between 1:4
and 4:1 in increments of 1/64th. 0
means square pixels.
84 85 86 |
# File 'lib/gif.rb', line 84 def ar @ar end |
#bg ⇒ Integer
This field is ignored by most decoders, which instead render the exposed parts of the canvas transparently.
Index of the background color in the Global Color Table. This is the color of the exposed parts of the canvas, i.e., those not covered by any image.
76 77 78 |
# File 'lib/gif.rb', line 76 def bg @bg end |
#color ⇒ Integer
The default color of the GIF's images. This color is used to initialize new blank images, as well as to pad images when they are resized to a bigger size. This can be overriden individually for each image.
42 43 44 |
# File 'lib/gif.rb', line 42 def color @color end |
#delay ⇒ Integer
The default delay to use between images, in 1/100ths of a second. See Extension::GraphicControl#delay for details about its implementation. This can be overriden individually for each image.
48 49 50 |
# File 'lib/gif.rb', line 48 def delay @delay end |
#destroy ⇒ Boolean
This will make the images unusable after the first encoding! So if you plan on reusing them multiple times, do not enable this setting, or only do so before the very last encoding.
Automatically destroy each image right after processing it during encoding. This is intended to save as much memory as possible whenever that's sensitive. Normally, since the pixel data for each image gets encoded and appended to the final output, the data is briefly duplicated in memory. This avoids it.
104 105 106 |
# File 'lib/gif.rb', line 104 def destroy @destroy end |
#disposal ⇒ Integer
The default disposal method to use for every image in the GIF. The disposal method handles how each frame is disposed of before displaying the next one. See Extension::GraphicControl#disposal for the specific details. This can be overriden individually for each image.
61 62 63 |
# File 'lib/gif.rb', line 61 def disposal @disposal end |
#extensions ⇒ Array<Extension>
The array of global extensions present in the GIF. This may include Application Extensions, Comment Extensions, etc. Other extensions, like the Graphic Control Extension, are local to each image, and are set there.
94 95 96 |
# File 'lib/gif.rb', line 94 def extensions @extensions end |
#gct ⇒ ColorTable
Changing this table after images have already been created with it will NOT update their color indices, which will thus corrupt them in the final encoded GIF.
The Global Color Table. This represents the default palette of all the images in the GIF. In other words, all colors in all images are indexed in this table, unless a local table is explicitly provided for an image, in which case it overrides the global one. A color table may contain up to 256 colors. See ColorTable for more details and a list of default palettes.
36 37 38 |
# File 'lib/gif.rb', line 36 def gct @gct end |
#height ⇒ Integer (readonly)
The height of the GIF's logical screen, i.e., its canvas. To resize it, use the #resize method.
25 26 27 |
# File 'lib/gif.rb', line 25 def height @height end |
#images ⇒ Array<Image>
The array of images present in the GIF.
88 89 90 |
# File 'lib/gif.rb', line 88 def images @images end |
#loops ⇒ Integer
The amount of times to loop the GIF. Must be a number between -1 and 65535, where -1 means to loop indefinitely. Internally, any non-zero number will result in the creation of a Netscape Extension. Note that many programs do not support finite loop counts, instead rendering all GIFs as either fully static or looping indefinitely.
69 70 71 |
# File 'lib/gif.rb', line 69 def loops @loops end |
#trans_color ⇒ Integer
The index of the default color to use as transparent. For details about how transparency works in GIF files, see Extension::GraphicControl#trans_color. This can be overriden individually for each image.
54 55 56 |
# File 'lib/gif.rb', line 54 def trans_color @trans_color end |
#width ⇒ Integer (readonly)
The width of the GIF's logical screen, i.e., its canvas. To resize it, use the #resize method.
19 20 21 |
# File 'lib/gif.rb', line 19 def width @width end |
Instance Method Details
#boomerang(first: false) ⇒ Gif
Duplicates all frames in reverse order. Generates a boomerang effect, particularly neat when looped.
239 240 241 242 243 244 |
# File 'lib/gif.rb', line 239 def boomerang(first: false) (@images.size - 2).downto(first ? 0 : 1).each{ |i| @images << @images[i].dup } self end |
#cycle ⇒ Gif
Shortcut to loop the GIF indefinitely. This sets the loops count to -1, which translates to 0 in the Netscape Extension.
227 228 229 230 |
# File 'lib/gif.rb', line 227 def cycle self.loops = -1 self end |
#encode(stream) ⇒ Object
Encode all the data as a GIF file and write it to a stream.
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/gif.rb', line 159 def encode(stream) # Header stream << HEADER # Logical Screen Descriptor stream << [@width, @height].pack('S<2') flags = 0 flags |= @gct.global_flags if @gct stream << [flags].pack('C') stream << [@bg, @ar].pack('C2') # Global Color Table @gct.encode(stream) if @gct # Global extensions @extensions.each{ |e| e.encode(stream) } # Encode frames containing image data (and local extensions) @images.size.times.each{ |i| @images[i].encode(stream) if @destroy @images[i].destroy @images[i] = nil end } # Trailer stream << TRAILER end |
#exhibit(delay = DEFAULT_EXHIBIT_TIME) ⇒ Gif
Shortcut to modify the delay of the GIF's last frame, intended to showcase the final result before looping it.
251 252 253 254 |
# File 'lib/gif.rb', line 251 def exhibit(delay = DEFAULT_EXHIBIT_TIME) @images.last.delay = delay self end |
#resize(width, height) ⇒ Object
We should probably test what happens when images are out of the logical screen's bounds, and perform integrity checks here if necessary, perhaps cropping the images present in this GIF.
Change the dimensions of the GIF's logical screen, i.e, its canvas.
193 194 195 196 |
# File 'lib/gif.rb', line 193 def resize(width, height) @width = width @height = height end |
#save(filename) ⇒ Object
Encode and write the GIF to a file.
267 268 269 270 271 |
# File 'lib/gif.rb', line 267 def save(filename) File.open(filename, 'wb') do |f| encode(f) end end |
#still ⇒ Gif
Shortcut to not loop the GIF at all. This sets the loop count to 0 and removes Netscape Extension. The name of the method comes from the fact that this is typically done to make a still image instead of an animation, but if multiple frames are added, they will be played back once. Crucially, if we want to make a layered image (i.e., a still image with multiple tiles and no delay between them, a common trick to achieve more than 256 colors in a GIF image), it's usually mandatory to do this, as most decoders will actually assume multiple images in a GIF are animation frames, rather than layers of a still image, if the Netscape Extension is present.
219 220 221 222 |
# File 'lib/gif.rb', line 219 def still self.loops = 0 self end |
#write ⇒ String
Encode and write the GIF to a string.
258 259 260 261 262 263 |
# File 'lib/gif.rb', line 258 def write str = StringIO.new str.set_encoding("ASCII-8BIT") encode(str) str.string end |