Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F632456
gif.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Authored By
Unknown
Size
13 KB
Referenced Files
None
Subscribers
None
gif.c
View Options
#include
"algif.h"
#include
"lzw.h"
#include
<stdlib.h>
#include
<string.h>
GIF_ANIMATION
*
algif_create_raw_animation
(
int
frames_count
)
{
GIF_ANIMATION
*
gif
=
calloc
(
1
,
sizeof
*
gif
);
/* Create frames. */
gif
->
frames_count
=
frames_count
;
gif
->
frames
=
calloc
(
gif
->
frames_count
,
sizeof
*
gif
->
frames
);
return
gif
;
}
/* Destroy a complete gif, including all frames. */
void
algif_destroy_raw_animation
(
GIF_ANIMATION
*
gif
)
{
int
i
;
for
(
i
=
0
;
i
<
gif
->
frames_count
;
i
++
)
{
GIF_FRAME
*
frame
=
gif
->
frames
+
i
;
if
(
frame
->
bitmap_8_bit
)
destroy_bitmap
(
frame
->
bitmap_8_bit
);
}
if
(
gif
->
store
)
destroy_bitmap
(
gif
->
store
);
free
(
gif
->
frames
);
free
(
gif
);
}
static
void
write_palette
(
PACKFILE
*
file
,
GIF_PALETTE
*
palette
,
int
bits
)
{
int
i
;
for
(
i
=
0
;
i
<
(
1
<<
bits
);
i
++
)
{
pack_putc
(
palette
->
colors
[
i
].
r
,
file
);
pack_putc
(
palette
->
colors
[
i
].
g
,
file
);
pack_putc
(
palette
->
colors
[
i
].
b
,
file
);
}
}
static
void
read_palette
(
PACKFILE
*
file
,
GIF_PALETTE
*
palette
)
{
int
i
;
for
(
i
=
0
;
i
<
palette
->
colors_count
;
i
++
)
{
palette
->
colors
[
i
].
r
=
pack_getc
(
file
);
palette
->
colors
[
i
].
g
=
pack_getc
(
file
);
palette
->
colors
[
i
].
b
=
pack_getc
(
file
);
}
}
/*
* Compresses all the frames in the animation and writes to a gif file.
* Nothing else like extensions or comments is written.
*
* Returns 0 on success.
*
* Note: All bitmaps must have a color depth of 8.
*/
int
algif_save_raw_animation
(
const
char
*
filename
,
GIF_ANIMATION
*
gif
)
{
int
frame
;
int
i
,
j
;
PACKFILE
*
file
;
file
=
pack_fopen
(
filename
,
"w"
);
if
(
!
file
)
return
-1
;
pack_fwrite
(
"GIF89a"
,
6
,
file
);
pack_iputw
(
gif
->
width
,
file
);
pack_iputw
(
gif
->
height
,
file
);
/* 7 global palette
* 456 color richness
* 3 sorted
* 012 palette bits
*/
for
(
i
=
1
,
j
=
0
;
i
<
gif
->
palette
.
colors_count
;
i
*=
2
,
j
++
);
pack_putc
((
j
?
128
:
0
)
+
64
+
32
+
16
+
(
j
?
j
-
1
:
0
),
file
);
pack_putc
(
gif
->
background_index
,
file
);
pack_putc
(
0
,
file
);
/* No aspect ratio. */
if
(
j
)
write_palette
(
file
,
&
gif
->
palette
,
j
);
if
(
gif
->
loop
!=
-1
)
/* Loop count extension. */
{
pack_putc
(
0x21
,
file
);
/* Extension Introducer. */
pack_putc
(
0xff
,
file
);
/* Application Extension. */
pack_putc
(
11
,
file
);
/* Size. */
pack_fwrite
(
"NETSCAPE2.0"
,
11
,
file
);
pack_putc
(
3
,
file
);
/* Size. */
pack_putc
(
1
,
file
);
pack_iputw
(
gif
->
loop
,
file
);
pack_putc
(
0
,
file
);
}
for
(
frame
=
0
;
frame
<
gif
->
frames_count
;
frame
++
)
{
int
w
=
gif
->
frames
[
frame
].
bitmap_8_bit
->
w
;
int
h
=
gif
->
frames
[
frame
].
bitmap_8_bit
->
h
;
pack_putc
(
0x21
,
file
);
/* Extension Introducer. */
pack_putc
(
0xf9
,
file
);
/* Graphic Control Extension. */
pack_putc
(
4
,
file
);
/* Size. */
/* Disposal method, and enable transparency. */
i
=
gif
->
frames
[
frame
].
disposal_method
<<
2
;
if
(
gif
->
frames
[
frame
].
transparent_index
!=
-1
)
i
|=
1
;
pack_putc
(
i
,
file
);
pack_iputw
(
gif
->
frames
[
frame
].
duration
,
file
);
/* In 1/100th seconds. */
if
(
gif
->
frames
[
frame
].
transparent_index
!=
-1
)
pack_putc
(
gif
->
frames
[
frame
].
transparent_index
,
file
);
/* Transparent color index. */
else
pack_putc
(
0
,
file
);
pack_putc
(
0x00
,
file
);
/* Terminator. */
pack_putc
(
0x2c
,
file
);
/* Image Descriptor. */
pack_iputw
(
gif
->
frames
[
frame
].
xoff
,
file
);
pack_iputw
(
gif
->
frames
[
frame
].
yoff
,
file
);
pack_iputw
(
w
,
file
);
pack_iputw
(
h
,
file
);
/* 7: local palette
* 6: interlaced
* 5: sorted
* 012: palette bits
*/
for
(
i
=
1
,
j
=
0
;
i
<
gif
->
frames
[
frame
].
palette
.
colors_count
;
i
*=
2
,
j
++
);
pack_putc
((
j
?
128
:
0
)
+
(
j
?
j
-
1
:
0
),
file
);
if
(
j
)
write_palette
(
file
,
&
gif
->
frames
[
frame
].
palette
,
j
);
LZW_encode
(
file
,
gif
->
frames
[
frame
].
bitmap_8_bit
);
pack_putc
(
0x00
,
file
);
/* Terminator. */
}
pack_putc
(
0x3b
,
file
);
/* Trailer. */
pack_fclose
(
file
);
return
0
;
}
static
void
deinterlace
(
BITMAP
*
bmp
)
{
BITMAP
*
n
=
create_bitmap_ex
(
bitmap_color_depth
(
bmp
),
bmp
->
w
,
bmp
->
h
);
int
y
,
i
=
0
;
for
(
y
=
0
;
y
<
n
->
h
;
y
+=
8
)
{
blit
(
bmp
,
n
,
0
,
i
++
,
0
,
y
,
n
->
w
,
1
);
}
for
(
y
=
4
;
y
<
n
->
h
;
y
+=
8
)
{
blit
(
bmp
,
n
,
0
,
i
++
,
0
,
y
,
n
->
w
,
1
);
}
for
(
y
=
2
;
y
<
n
->
h
;
y
+=
4
)
{
blit
(
bmp
,
n
,
0
,
i
++
,
0
,
y
,
n
->
w
,
1
);
}
for
(
y
=
1
;
y
<
n
->
h
;
y
+=
2
)
{
blit
(
bmp
,
n
,
0
,
i
++
,
0
,
y
,
n
->
w
,
1
);
}
blit
(
n
,
bmp
,
0
,
0
,
0
,
0
,
n
->
w
,
n
->
h
);
destroy_bitmap
(
n
);
}
static
GIF_ANIMATION
*
load_object
(
PACKFILE
*
file
,
long
size
)
{
int
version
;
BITMAP
*
bmp
=
NULL
;
int
i
,
j
;
GIF_ANIMATION
*
gif
=
calloc
(
1
,
sizeof
*
gif
);
GIF_FRAME
frame
;
int
have_global_palette
=
0
;
(
void
)
size
;
gif
->
frames_count
=
0
;
/* is it really a GIF? */
if
(
pack_getc
(
file
)
!=
'G'
)
goto
error
;
if
(
pack_getc
(
file
)
!=
'I'
)
goto
error
;
if
(
pack_getc
(
file
)
!=
'F'
)
goto
error
;
if
(
pack_getc
(
file
)
!=
'8'
)
goto
error
;
/* '7' or '9', for 87a or 89a. */
version
=
pack_getc
(
file
);
if
(
version
!=
'7'
&&
version
!=
'9'
)
goto
error
;
if
(
pack_getc
(
file
)
!=
'a'
)
goto
error
;
gif
->
width
=
pack_igetw
(
file
);
gif
->
height
=
pack_igetw
(
file
);
i
=
pack_getc
(
file
);
/* Global color table? */
if
(
i
&
128
)
gif
->
palette
.
colors_count
=
1
<<
((
i
&
7
)
+
1
);
else
gif
->
palette
.
colors_count
=
0
;
/* Background color is only valid with a global palette. */
gif
->
background_index
=
pack_getc
(
file
);
/* Skip aspect ratio. */
pack_fseek
(
file
,
1
);
if
(
gif
->
palette
.
colors_count
)
{
read_palette
(
file
,
&
gif
->
palette
);
have_global_palette
=
1
;
}
memset
(
&
frame
,
0
,
sizeof
frame
);
/* For first frame. */
frame
.
transparent_index
=
-1
;
do
{
i
=
pack_getc
(
file
);
switch
(
i
)
{
case
0x2c
:
/* Image Descriptor */
{
int
w
,
h
;
int
interlaced
=
0
;
frame
.
xoff
=
pack_igetw
(
file
);
frame
.
yoff
=
pack_igetw
(
file
);
w
=
pack_igetw
(
file
);
h
=
pack_igetw
(
file
);
bmp
=
create_bitmap_ex
(
8
,
w
,
h
);
if
(
!
bmp
)
goto
error
;
i
=
pack_getc
(
file
);
/* Local palette. */
if
(
i
&
128
)
{
frame
.
palette
.
colors_count
=
1
<<
((
i
&
7
)
+
1
);
read_palette
(
file
,
&
frame
.
palette
);
}
else
{
frame
.
palette
.
colors_count
=
0
;
}
if
(
i
&
64
)
interlaced
=
1
;
if
(
LZW_decode
(
file
,
bmp
))
goto
error
;
if
(
interlaced
)
deinterlace
(
bmp
);
frame
.
bitmap_8_bit
=
bmp
;
bmp
=
NULL
;
gif
->
frames_count
++
;
gif
->
frames
=
realloc
(
gif
->
frames
,
gif
->
frames_count
*
sizeof
*
gif
->
frames
);
gif
->
frames
[
gif
->
frames_count
-
1
]
=
frame
;
memset
(
&
frame
,
0
,
sizeof
frame
);
/* For next frame. */
frame
.
transparent_index
=
-1
;
break
;
}
case
0x21
:
/* Extension Introducer. */
j
=
pack_getc
(
file
);
/* Extension Type. */
i
=
pack_getc
(
file
);
/* Size. */
if
(
j
==
0xf9
)
/* Graphic Control Extension. */
{
/* size must be 4 */
if
(
i
!=
4
)
goto
error
;
i
=
pack_getc
(
file
);
frame
.
disposal_method
=
(
i
>>
2
)
&
7
;
frame
.
duration
=
pack_igetw
(
file
);
if
(
i
&
1
)
/* Transparency? */
{
frame
.
transparent_index
=
pack_getc
(
file
);
}
else
{
pack_fseek
(
file
,
1
);
frame
.
transparent_index
=
-1
;
}
i
=
pack_getc
(
file
);
/* Size. */
}
/* Application Extension. */
else
if
(
j
==
0xff
)
{
if
(
i
==
11
)
{
char
name
[
12
];
pack_fread
(
name
,
11
,
file
);
i
=
pack_getc
(
file
);
/* Size. */
name
[
11
]
=
'\0'
;
if
(
!
strcmp
(
name
,
"NETSCAPE2.0"
))
{
if
(
i
==
3
)
{
j
=
pack_getc
(
file
);
gif
->
loop
=
pack_igetw
(
file
);
if
(
j
!=
1
)
gif
->
loop
=
0
;
i
=
pack_getc
(
file
);
/* Size. */
}
}
}
}
/* Possibly more blocks until terminator block (0). */
while
(
i
)
{
pack_fseek
(
file
,
i
);
i
=
pack_getc
(
file
);
}
break
;
case
0x3b
:
/* GIF Trailer. */
pack_fclose
(
file
);
return
gif
;
}
}
while
(
TRUE
);
error
:
if
(
file
)
pack_fclose
(
file
);
if
(
gif
)
algif_destroy_raw_animation
(
gif
);
if
(
bmp
)
destroy_bitmap
(
bmp
);
return
NULL
;
}
/*
* Allocates and reads a GIF_ANIMATION structure, filling in all the
* frames found in the file. On error, nothing is allocated, and NULL is
* returned. No extensions or comments are read in. If the gif contains
* a transparency index, and it is no 0, it is swapped with 0 - so index
* 0 will be the transparent color. There is no way to know when a file
* contained no transparency originally. Frame duration is specified in
* 1/100th seconds.
*
* All bitmaps will have a color depth of 8.
*/
GIF_ANIMATION
*
algif_load_raw_animation
(
const
char
*
filename
)
{
PACKFILE
*
file
;
GIF_ANIMATION
*
gif
=
NULL
;
file
=
pack_fopen
(
filename
,
"r"
);
if
(
file
)
gif
=
load_object
(
file
,
0
);
return
gif
;
}
GIF_ANIMATION
*
algif_load_raw_animation_packfile
(
PACKFILE
*
file
){
GIF_ANIMATION
*
gif
=
NULL
;
gif
=
load_object
(
file
,
0
);
return
gif
;
}
static
int
get_rgbcolor
(
RGB
*
rgb
)
{
return
makecol
(
rgb
->
r
,
rgb
->
g
,
rgb
->
b
);
}
/* Renders the next frame in a GIF animation to the specified bitmap and
* the given position. You need to call this in order on the same
* destination for frames [0..gif->frames_count - 1] to properly render all
* the frames in the GIF.
*/
void
algif_render_frame
(
GIF_ANIMATION
*
gif
,
BITMAP
*
bitmap
,
int
frame
,
int
xpos
,
int
ypos
)
{
int
x
,
y
,
w
,
h
;
GIF_FRAME
*
f
=
&
gif
->
frames
[
frame
];
GIF_PALETTE
*
pal
;
if
(
frame
==
0
)
rectfill
(
bitmap
,
xpos
,
ypos
,
xpos
+
gif
->
width
-
1
,
ypos
+
gif
->
height
-
1
,
bitmap_mask_color
(
bitmap
));
else
{
GIF_FRAME
*
p
=
&
gif
->
frames
[
frame
-
1
];
if
(
p
->
disposal_method
==
2
)
rectfill
(
bitmap
,
xpos
+
p
->
xoff
,
ypos
+
p
->
yoff
,
xpos
+
p
->
xoff
+
p
->
bitmap_8_bit
->
w
-
1
,
ypos
+
p
->
yoff
+
p
->
bitmap_8_bit
->
h
-
1
,
bitmap_mask_color
(
bitmap
));
else
if
(
p
->
disposal_method
==
3
&&
gif
->
store
)
{
blit
(
gif
->
store
,
bitmap
,
0
,
0
,
xpos
+
p
->
xoff
,
ypos
+
p
->
yoff
,
gif
->
store
->
w
,
gif
->
store
->
h
);
destroy_bitmap
(
gif
->
store
);
gif
->
store
=
NULL
;
}
}
w
=
f
->
bitmap_8_bit
->
w
;
h
=
f
->
bitmap_8_bit
->
h
;
if
(
f
->
disposal_method
==
3
)
{
if
(
gif
->
store
)
destroy_bitmap
(
gif
->
store
);
gif
->
store
=
create_bitmap_ex
(
bitmap_color_depth
(
bitmap
),
w
,
h
);
blit
(
bitmap
,
gif
->
store
,
xpos
+
f
->
xoff
,
ypos
+
f
->
yoff
,
0
,
0
,
w
,
h
);
}
pal
=
&
gif
->
frames
[
frame
].
palette
;
if
(
pal
->
colors_count
==
0
)
pal
=
&
gif
->
palette
;
//int i;
//for (i = 0; i < pal->colors_count; i++)
// printf("%d: %d %d %d\n", i, pal->colors[i].r, pal->colors[i].g, pal->colors[i].b);
for
(
y
=
0
;
y
<
h
;
y
++
)
{
for
(
x
=
0
;
x
<
w
;
x
++
)
{
int
c
=
getpixel
(
f
->
bitmap_8_bit
,
x
,
y
);
if
(
c
!=
f
->
transparent_index
)
{
putpixel
(
bitmap
,
xpos
+
f
->
xoff
+
x
,
ypos
+
f
->
yoff
+
y
,
get_rgbcolor
(
&
pal
->
colors
[
c
]));
}
}
}
}
/* Registers gif as bitmap and datafile type. */
void
algif_init
(
void
)
{
register_bitmap_file_type
(
"gif"
,
load_gif
,
save_gif
);
register_datafile_object
(
DAT_GIF
,
(
void
*
(
*
)(
PACKFILE
*
,
long
))
load_object
,
(
void
(
*
)(
void
*
))
algif_destroy_raw_animation
);
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sun, Nov 15, 2:26 PM (1 d, 21 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
144001
Default Alt Text
gif.c (13 KB)
Attached To
Mode
R75 R-Tech1
Attached
Detach File
Event Timeline