Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
itdan3344
stb
提交
1b9689cf
S
stb
项目概览
itdan3344
/
stb
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
stb
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
1b9689cf
编写于
1月 29, 2018
作者:
S
Sean Barrett
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'feature/gif_frames' of
https://github.com/tocchan/stb
上级
f9d78c05
de75509b
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
218 addition
and
80 deletion
+218
-80
stb_image.h
stb_image.h
+218
-80
未找到文件。
stb_image.h
浏览文件 @
1b9689cf
...
...
@@ -75,7 +75,7 @@ RECENT REVISION HISTORY:
Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
github:urraka (animated gif) Junggon Kim (PNM comments)
Daniel Gibson (16-bit TGA)
github:tocchan (animated gif)
Daniel Gibson (16-bit TGA)
socks-the-fox (16-bit PNG)
Jeremy Sawicki (handle all ImageNet JPGs)
Optimizations & bugfixes Mikhail Morozov (1-bit BMP)
...
...
@@ -355,6 +355,10 @@ typedef struct
STBIDEF
stbi_uc
*
stbi_load_from_memory
(
stbi_uc
const
*
buffer
,
int
len
,
int
*
x
,
int
*
y
,
int
*
channels_in_file
,
int
desired_channels
);
STBIDEF
stbi_uc
*
stbi_load_from_callbacks
(
stbi_io_callbacks
const
*
clbk
,
void
*
user
,
int
*
x
,
int
*
y
,
int
*
channels_in_file
,
int
desired_channels
);
#ifndef STBI_NO_GIF
STBIDEF
stbi_uc
*
stbi_load_gif_from_memory
(
stbi_uc
const
*
buffer
,
int
len
,
int
**
delays
,
int
*
x
,
int
*
y
,
int
*
z
,
int
*
comp
,
int
req_comp
);
#endif
#ifndef STBI_NO_STDIO
STBIDEF
stbi_uc
*
stbi_load
(
char
const
*
filename
,
int
*
x
,
int
*
y
,
int
*
channels_in_file
,
int
desired_channels
);
...
...
@@ -826,6 +830,7 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);
#ifndef STBI_NO_GIF
static
int
stbi__gif_test
(
stbi__context
*
s
);
static
void
*
stbi__gif_load
(
stbi__context
*
s
,
int
*
x
,
int
*
y
,
int
*
comp
,
int
req_comp
,
stbi__result_info
*
ri
);
static
void
*
stbi__load_gif_main
(
stbi__context
*
s
,
int
**
delays
,
int
*
x
,
int
*
y
,
int
*
z
,
int
*
comp
,
int
req_comp
);
static
int
stbi__gif_info
(
stbi__context
*
s
,
int
*
x
,
int
*
y
,
int
*
comp
);
#endif
...
...
@@ -1065,6 +1070,18 @@ static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel)
}
}
static
void
stbi__vertical_flip_slices
(
void
*
image
,
int
w
,
int
h
,
int
z
,
int
bytes_per_pixel
)
{
int
slice
;
int
slice_size
=
w
*
h
*
bytes_per_pixel
;
stbi_uc
*
bytes
=
(
stbi_uc
*
)
image
;
for
(
slice
=
0
;
slice
<
z
;
++
slice
)
{
stbi__vertical_flip
(
bytes
,
w
,
h
,
bytes_per_pixel
);
bytes
+=
slice_size
;
}
}
static
unsigned
char
*
stbi__load_and_postprocess_8bit
(
stbi__context
*
s
,
int
*
x
,
int
*
y
,
int
*
comp
,
int
req_comp
)
{
stbi__result_info
ri
;
...
...
@@ -1216,6 +1233,21 @@ STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *u
return
stbi__load_and_postprocess_8bit
(
&
s
,
x
,
y
,
comp
,
req_comp
);
}
#ifndef STBI_NO_GIF
STBIDEF
stbi_uc
*
stbi_load_gif_from_memory
(
stbi_uc
const
*
buffer
,
int
len
,
int
**
delays
,
int
*
x
,
int
*
y
,
int
*
z
,
int
*
comp
,
int
req_comp
)
{
stbi__context
s
;
stbi__start_mem
(
&
s
,
buffer
,
len
);
unsigned
char
*
result
=
(
unsigned
char
*
)
stbi__load_gif_main
(
&
s
,
delays
,
x
,
y
,
z
,
comp
,
req_comp
);
if
(
stbi__vertically_flip_on_load
)
{
stbi__vertical_flip_slices
(
result
,
*
x
,
*
y
,
*
z
,
*
comp
);
}
return
result
;
}
#endif
#ifndef STBI_NO_LINEAR
static
float
*
stbi__loadf_main
(
stbi__context
*
s
,
int
*
x
,
int
*
y
,
int
*
comp
,
int
req_comp
)
{
...
...
@@ -6085,11 +6117,13 @@ typedef struct
typedef
struct
{
int
w
,
h
;
stbi_uc
*
out
,
*
old_out
;
// output buffer (always 4 components)
int
flags
,
bgindex
,
ratio
,
transparent
,
eflags
,
delay
;
stbi_uc
*
out
;
// output buffer (always 4 components)
stbi_uc
*
background
;
// The current "background" as far as a gif is concerned
stbi_uc
*
history
;
int
flags
,
bgindex
,
ratio
,
transparent
,
eflags
;
stbi_uc
pal
[
256
][
4
];
stbi_uc
lpal
[
256
][
4
];
stbi__gif_lzw
codes
[
4096
];
stbi__gif_lzw
codes
[
8192
];
stbi_uc
*
color_table
;
int
parse
,
step
;
int
lflags
;
...
...
@@ -6097,6 +6131,7 @@ typedef struct
int
max_x
,
max_y
;
int
cur_x
,
cur_y
;
int
line_size
;
int
delay
;
}
stbi__gif
;
static
int
stbi__gif_test_raw
(
stbi__context
*
s
)
...
...
@@ -6172,6 +6207,7 @@ static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)
static
void
stbi__out_gif_code
(
stbi__gif
*
g
,
stbi__uint16
code
)
{
stbi_uc
*
p
,
*
c
;
int
idx
;
// recurse to decode the prefixes, since the linked-list is backwards,
// and working backwards through an interleaved image would be nasty
...
...
@@ -6180,10 +6216,12 @@ static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
if
(
g
->
cur_y
>=
g
->
max_y
)
return
;
p
=
&
g
->
out
[
g
->
cur_x
+
g
->
cur_y
];
c
=
&
g
->
color_table
[
g
->
codes
[
code
].
suffix
*
4
];
idx
=
g
->
cur_x
+
g
->
cur_y
;
p
=
&
g
->
out
[
idx
];
g
->
history
[
idx
/
4
]
=
1
;
if
(
c
[
3
]
>=
128
)
{
c
=
&
g
->
color_table
[
g
->
codes
[
code
].
suffix
*
4
];
if
(
c
[
3
]
>
128
)
{
// don't render transparent pixels;
p
[
0
]
=
c
[
2
];
p
[
1
]
=
c
[
1
];
p
[
2
]
=
c
[
0
];
...
...
@@ -6257,11 +6295,16 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
stbi__skip
(
s
,
len
);
return
g
->
out
;
}
else
if
(
code
<=
avail
)
{
if
(
first
)
return
stbi__errpuc
(
"no clear code"
,
"Corrupt GIF"
);
if
(
first
)
{
return
stbi__errpuc
(
"no clear code"
,
"Corrupt GIF"
);
}
if
(
oldcode
>=
0
)
{
p
=
&
g
->
codes
[
avail
++
];
if
(
avail
>
4096
)
return
stbi__errpuc
(
"too many codes"
,
"Corrupt GIF"
);
if
(
avail
>
8192
)
{
return
stbi__errpuc
(
"too many codes"
,
"Corrupt GIF"
);
}
p
->
prefix
=
(
stbi__int16
)
oldcode
;
p
->
first
=
g
->
codes
[
oldcode
].
first
;
p
->
suffix
=
(
code
==
avail
)
?
p
->
first
:
g
->
codes
[
code
].
first
;
...
...
@@ -6283,62 +6326,72 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
}
}
static
void
stbi__fill_gif_background
(
stbi__gif
*
g
,
int
x0
,
int
y0
,
int
x1
,
int
y1
)
{
int
x
,
y
;
stbi_uc
*
c
=
g
->
pal
[
g
->
bgindex
];
for
(
y
=
y0
;
y
<
y1
;
y
+=
4
*
g
->
w
)
{
for
(
x
=
x0
;
x
<
x1
;
x
+=
4
)
{
stbi_uc
*
p
=
&
g
->
out
[
y
+
x
];
p
[
0
]
=
c
[
2
];
p
[
1
]
=
c
[
1
];
p
[
2
]
=
c
[
0
];
p
[
3
]
=
0
;
}
}
}
// this function is designed to support animated gifs, although stb_image doesn't support it
static
stbi_uc
*
stbi__gif_load_next
(
stbi__context
*
s
,
stbi__gif
*
g
,
int
*
comp
,
int
req_comp
)
{
int
i
;
stbi_uc
*
prev_out
=
0
;
if
(
g
->
out
==
0
&&
!
stbi__gif_header
(
s
,
g
,
comp
,
0
))
return
0
;
// stbi__g_failure_reason set by stbi__gif_header
if
(
!
stbi__mad3sizes_valid
(
g
->
w
,
g
->
h
,
4
,
0
))
return
stbi__errpuc
(
"too large"
,
"GIF too large"
);
// two back is the image from two frames ago, used for a very specific disposal format
static
stbi_uc
*
stbi__gif_load_next
(
stbi__context
*
s
,
stbi__gif
*
g
,
int
*
comp
,
int
req_comp
,
stbi_uc
*
two_back
)
{
int
dispose
;
int
first_frame
;
int
pi
;
int
pcount
;
// on first frame, any non-written pixels get the background colour (non-transparent)
first_frame
=
0
;
if
(
g
->
out
==
0
)
{
if
(
!
stbi__gif_header
(
s
,
g
,
comp
,
0
))
return
0
;
// stbi__g_failure_reason set by stbi__gif_header
g
->
out
=
(
stbi_uc
*
)
stbi__malloc
(
4
*
g
->
w
*
g
->
h
);
g
->
background
=
(
stbi_uc
*
)
stbi__malloc
(
4
*
g
->
w
*
g
->
h
);
g
->
history
=
(
stbi_uc
*
)
stbi__malloc
(
g
->
w
*
g
->
h
);
if
(
g
->
out
==
0
)
return
stbi__errpuc
(
"outofmem"
,
"Out of memory"
);
// image is treated as "tranparent" at the start - ie, nothing overwrites the current background;
// background colour is only used for pixels that are not rendered first frame, after that "background"
// color refers to teh color that was there the previous frame.
memset
(
g
->
out
,
0x00
,
4
*
g
->
w
*
g
->
h
);
memset
(
g
->
background
,
0x00
,
4
*
g
->
w
*
g
->
h
);
// state of the background (starts transparent)
memset
(
g
->
history
,
0x00
,
g
->
w
*
g
->
h
);
// pixels that were affected previous frame
first_frame
=
1
;
}
else
{
// second frame - how do we dispoase of the previous one?
dispose
=
(
g
->
eflags
&
0x1C
)
>>
2
;
pcount
=
g
->
w
*
g
->
h
;
prev_out
=
g
->
out
;
g
->
out
=
(
stbi_uc
*
)
stbi__malloc_mad3
(
4
,
g
->
w
,
g
->
h
,
0
);
if
(
g
->
out
==
0
)
return
stbi__errpuc
(
"outofmem"
,
"Out of memory"
);
if
((
dispose
==
3
)
&&
(
two_back
==
0
))
{
dispose
=
2
;
// if I don't have an image to revert back to, default to the old background
}
switch
((
g
->
eflags
&
0x1C
)
>>
2
)
{
case
0
:
// unspecified (also always used on 1st frame)
stbi__fill_gif_background
(
g
,
0
,
0
,
4
*
g
->
w
,
4
*
g
->
w
*
g
->
h
);
break
;
case
1
:
// do not dispose
if
(
prev_out
)
memcpy
(
g
->
out
,
prev_out
,
4
*
g
->
w
*
g
->
h
);
g
->
old_out
=
prev_out
;
break
;
case
2
:
// dispose to background
if
(
prev_out
)
memcpy
(
g
->
out
,
prev_out
,
4
*
g
->
w
*
g
->
h
);
stbi__fill_gif_background
(
g
,
g
->
start_x
,
g
->
start_y
,
g
->
max_x
,
g
->
max_y
);
break
;
case
3
:
// dispose to previous
if
(
g
->
old_out
)
{
for
(
i
=
g
->
start_y
;
i
<
g
->
max_y
;
i
+=
4
*
g
->
w
)
memcpy
(
&
g
->
out
[
i
+
g
->
start_x
],
&
g
->
old_out
[
i
+
g
->
start_x
],
g
->
max_x
-
g
->
start_x
);
if
(
dispose
==
3
)
{
// use previous graphic
for
(
pi
=
0
;
pi
<
pcount
;
++
pi
)
{
if
(
g
->
history
[
pi
])
{
memcpy
(
&
g
->
out
[
pi
*
4
],
&
two_back
[
pi
*
4
],
4
);
}
}
break
;
}
else
if
(
dispose
==
2
)
{
// restore what was changed last frame to background before that frame;
for
(
pi
=
0
;
pi
<
pcount
;
++
pi
)
{
if
(
g
->
history
[
pi
])
{
memcpy
(
&
g
->
out
[
pi
*
4
],
&
g
->
background
[
pi
*
4
],
4
);
}
}
}
else
{
// This is a non-disposal case eithe way, so just
// leave the pixels as is, and they will become the new background
// 1: do not dispose
// 0: not specified.
}
// background is what out is after the undoing of the previou frame;
memcpy
(
g
->
background
,
g
->
out
,
4
*
g
->
w
*
g
->
h
);
}
// clear my history;
memset
(
g
->
history
,
0x00
,
g
->
w
*
g
->
h
);
// pixels that were affected previous frame
for
(;;)
{
switch
(
stbi__get8
(
s
))
{
int
tag
=
stbi__get8
(
s
);
switch
(
tag
)
{
case
0x2C
:
/* Image Descriptor */
{
int
prev_trans
=
-
1
;
stbi__int32
x
,
y
,
w
,
h
;
stbi_uc
*
o
;
...
...
@@ -6371,19 +6424,24 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
stbi__gif_parse_colortable
(
s
,
g
->
lpal
,
2
<<
(
g
->
lflags
&
7
),
g
->
eflags
&
0x01
?
g
->
transparent
:
-
1
);
g
->
color_table
=
(
stbi_uc
*
)
g
->
lpal
;
}
else
if
(
g
->
flags
&
0x80
)
{
if
(
g
->
transparent
>=
0
&&
(
g
->
eflags
&
0x01
))
{
prev_trans
=
g
->
pal
[
g
->
transparent
][
3
];
g
->
pal
[
g
->
transparent
][
3
]
=
0
;
}
g
->
color_table
=
(
stbi_uc
*
)
g
->
pal
;
}
else
return
stbi__errpuc
(
"missing color table"
,
"Corrupt GIF"
);
return
stbi__errpuc
(
"missing color table"
,
"Corrupt GIF"
);
o
=
stbi__process_gif_raster
(
s
,
g
);
if
(
o
==
NULL
)
return
NULL
;
if
(
prev_trans
!=
-
1
)
g
->
pal
[
g
->
transparent
][
3
]
=
(
stbi_uc
)
prev_trans
;
// if this was the first frame,
pcount
=
g
->
w
*
g
->
h
;
if
(
first_frame
&&
(
g
->
bgindex
>
0
))
{
// if first frame, any pixel not drawn to gets the background color
for
(
pi
=
0
;
pi
<
pcount
;
++
pi
)
{
if
(
g
->
history
[
pi
]
==
0
)
{
g
->
pal
[
g
->
bgindex
][
3
]
=
255
;
// just in case it was made transparent, undo that; It will be reset next frame if need be;
memcpy
(
&
g
->
out
[
pi
*
4
],
&
g
->
pal
[
g
->
bgindex
],
4
);
}
}
}
return
o
;
}
...
...
@@ -6391,19 +6449,35 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
case
0x21
:
// Comment Extension.
{
int
len
;
if
(
stbi__get8
(
s
)
==
0xF9
)
{
// Graphic Control Extension.
int
ext
=
stbi__get8
(
s
);
if
(
ext
==
0xF9
)
{
// Graphic Control Extension.
len
=
stbi__get8
(
s
);
if
(
len
==
4
)
{
g
->
eflags
=
stbi__get8
(
s
);
g
->
delay
=
stbi__get16le
(
s
);
g
->
transparent
=
stbi__get8
(
s
);
g
->
delay
=
10
*
stbi__get16le
(
s
);
// delay - 1/100th of a second, saving as 1/1000ths.
// unset old transparent
if
(
g
->
transparent
>=
0
)
{
g
->
pal
[
g
->
transparent
][
3
]
=
255
;
}
if
(
g
->
eflags
&
0x01
)
{
g
->
transparent
=
stbi__get8
(
s
);
if
(
g
->
transparent
>=
0
)
{
g
->
pal
[
g
->
transparent
][
3
]
=
0
;
}
}
else
{
// don't need transparent
stbi__skip
(
s
,
1
);
g
->
transparent
=
-
1
;
}
}
else
{
stbi__skip
(
s
,
len
);
break
;
}
}
while
((
len
=
stbi__get8
(
s
))
!=
0
)
}
while
((
len
=
stbi__get8
(
s
))
!=
0
)
{
stbi__skip
(
s
,
len
);
}
break
;
}
...
...
@@ -6414,28 +6488,92 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
return
stbi__errpuc
(
"unknown code"
,
"Corrupt GIF"
);
}
}
}
static
void
*
stbi__load_gif_main
(
stbi__context
*
s
,
int
**
delays
,
int
*
x
,
int
*
y
,
int
*
z
,
int
*
comp
,
int
req_comp
)
{
if
(
stbi__gif_test
(
s
))
{
int
layers
=
0
;
stbi_uc
*
u
=
0
;
stbi_uc
*
out
=
0
;
stbi_uc
*
two_back
=
0
;
stbi__gif
g
;
int
stride
;
memset
(
&
g
,
0
,
sizeof
(
g
));
if
(
delays
)
{
*
delays
=
0
;
}
STBI_NOTUSED
(
req_comp
);
do
{
u
=
stbi__gif_load_next
(
s
,
&
g
,
comp
,
req_comp
,
two_back
);
if
(
u
==
(
stbi_uc
*
)
s
)
u
=
0
;
// end of animated gif marker
if
(
u
)
{
*
x
=
g
.
w
;
*
y
=
g
.
h
;
++
layers
;
stride
=
g
.
w
*
g
.
h
*
4
;
if
(
out
)
{
out
=
(
stbi_uc
*
)
STBI_REALLOC
(
out
,
layers
*
stride
);
if
(
delays
)
{
*
delays
=
(
int
*
)
STBI_REALLOC
(
*
delays
,
sizeof
(
int
)
*
layers
);
}
}
else
{
out
=
(
stbi_uc
*
)
stbi__malloc
(
layers
*
stride
);
if
(
delays
)
{
*
delays
=
(
int
*
)
stbi__malloc
(
layers
*
sizeof
(
int
)
);
}
}
memcpy
(
out
+
((
layers
-
1
)
*
stride
),
u
,
stride
);
if
(
layers
>=
2
)
{
two_back
=
out
-
2
*
stride
;
}
if
(
delays
)
{
(
*
delays
)[
layers
-
1U
]
=
g
.
delay
;
}
}
}
while
(
u
!=
0
);
// free temp buffer;
STBI_FREE
(
g
.
out
);
STBI_FREE
(
g
.
history
);
STBI_FREE
(
g
.
background
);
// do the final conversion after loading everything;
if
(
req_comp
&&
req_comp
!=
4
)
out
=
stbi__convert_format
(
out
,
4
,
req_comp
,
layers
*
g
.
w
,
g
.
h
);
*
z
=
layers
;
return
out
;
}
else
{
return
stbi__errpuc
(
"not GIF"
,
"Image was not as a gif type."
);
}
}
static
void
*
stbi__gif_load
(
stbi__context
*
s
,
int
*
x
,
int
*
y
,
int
*
comp
,
int
req_comp
,
stbi__result_info
*
ri
)
{
stbi_uc
*
u
=
0
;
stbi__gif
*
g
=
(
stbi__gif
*
)
stbi__malloc
(
sizeof
(
stbi__gif
));
memset
(
g
,
0
,
sizeof
(
*
g
));
STBI_NOTUSED
(
ri
);
stbi__gif
g
;
memset
(
&
g
,
0
,
sizeof
(
g
));
u
=
stbi__gif_load_next
(
s
,
g
,
comp
,
req_comp
);
u
=
stbi__gif_load_next
(
s
,
&
g
,
comp
,
req_comp
,
0
);
if
(
u
==
(
stbi_uc
*
)
s
)
u
=
0
;
// end of animated gif marker
if
(
u
)
{
*
x
=
g
->
w
;
*
y
=
g
->
h
;
*
x
=
g
.
w
;
*
y
=
g
.
h
;
// moved conversion to after successful load so that the same
// can be done for multiple frames.
if
(
req_comp
&&
req_comp
!=
4
)
u
=
stbi__convert_format
(
u
,
4
,
req_comp
,
g
->
w
,
g
->
h
);
u
=
stbi__convert_format
(
u
,
4
,
req_comp
,
g
.
w
,
g
.
h
);
}
else
if
(
g
->
out
)
STBI_FREE
(
g
->
out
);
STBI_FREE
(
g
);
// free buffers needed for multiple frame loading;
STBI_FREE
(
g
.
history
);
STBI_FREE
(
g
.
background
);
return
u
;
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录