blob: 7511cf2bb7d333e89b7ca7f1f34e612f041e4167 [file] [log] [blame]
// Copyright 2017 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "gif_lib.h"
int //
mimic_gif_read_func(GifFileType* f, GifByteType* ptr, int len) {
wuffs_base__io_buffer* src = (wuffs_base__io_buffer*)(f->UserData);
if (len < 0) {
return 0;
}
size_t n = (size_t)(len);
size_t num_src = src->meta.wi - src->meta.ri;
if (n > num_src) {
n = num_src;
}
memmove(ptr, src->data.ptr + src->meta.ri, n);
src->meta.ri += n;
return n;
}
const char* //
mimic_gif_decode(uint64_t* n_bytes_out,
wuffs_base__io_buffer* dst,
uint32_t wuffs_initialize_flags,
wuffs_base__pixel_format pixfmt,
uint32_t* quirks_ptr,
size_t quirks_len,
wuffs_base__io_buffer* src) {
const char* ret = NULL;
// http://giflib.sourceforge.net/gif_lib.html#compatibility says that "A few
// changes in behavior were introduced in 5.0:
//
// GIF file openers and closers - DGifOpenFileName(), DGifOpenFileHandle(),
// DGifOpen(), DGifClose(), EGifOpenFileName(), EGifOpenFileHandle(),
// EGifOpen(), and EGifClose() - all now take a final integer address
// argument. If non-null, this is used to pass back an error code when the
// function returns NULL."
#if defined(GIFLIB_MAJOR) && (GIFLIB_MAJOR >= 5)
GifFileType* f = DGifOpen(src, mimic_gif_read_func, NULL);
#else
GifFileType* f = DGifOpen(src, mimic_gif_read_func);
#endif
if (!f) {
ret = "DGifOpen failed";
goto cleanup0;
}
if (DGifSlurp(f) != GIF_OK) {
ret = "DGifSlurp failed";
goto cleanup1;
}
int i;
for (i = 0; i < f->ImageCount; i++) {
// Copy the pixel data from the GifFileType* f to the dst buffer, since the
// former is free'd at the end of this function.
//
// In theory, this mimic_gif_decode function might be faster overall if the
// DGifSlurp call above decoded the pixel data directly into dst instead of
// into an intermediate buffer that needed to be malloc'ed and then free'd.
// In practice, doing so did not seem to show a huge difference. (See
// commit ab7e0ae "Add a custom gif_mimic_DGifSlurp function.") It also
// further complicates supporting both versions 4 and 5 of giflib. That
// commit was therefore rolled back.
struct SavedImage* si = &f->SavedImages[i];
size_t num_src =
(size_t)(si->ImageDesc.Width) * (size_t)(si->ImageDesc.Height);
if (n_bytes_out) {
*n_bytes_out += num_src;
}
if (dst) {
size_t num_dst = dst->data.len - dst->meta.wi;
if (num_dst < num_src) {
ret = "GIF image's pixel data won't fit in the dst buffer";
goto cleanup1;
}
memmove(dst->data.ptr + dst->meta.wi, si->RasterBits, num_src);
dst->meta.wi += num_src;
}
}
cleanup1:;
#if defined(GIFLIB_MAJOR) && (GIFLIB_MAJOR >= 5)
int close_status = DGifCloseFile(f, NULL);
#else
int close_status = DGifCloseFile(f);
#endif
if ((close_status != GIF_OK) && !ret) {
ret = "DGifCloseFile failed";
}
cleanup0:;
return ret;
}