• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Wuffs Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "gif_lib.h"
16 
mimic_gif_read_func(GifFileType * f,GifByteType * ptr,int len)17 int mimic_gif_read_func(GifFileType* f, GifByteType* ptr, int len) {
18   wuffs_base__io_buffer* src = (wuffs_base__io_buffer*)(f->UserData);
19   if (len < 0) {
20     return 0;
21   }
22   size_t n = (size_t)(len);
23   size_t num_src = src->meta.wi - src->meta.ri;
24   if (n > num_src) {
25     n = num_src;
26   }
27   memmove(ptr, src->data.ptr + src->meta.ri, n);
28   src->meta.ri += n;
29   return n;
30 }
31 
mimic_gif_decode(wuffs_base__io_buffer * dst,uint32_t wuffs_initialize_flags,wuffs_base__pixel_format pixfmt,wuffs_base__io_buffer * src)32 const char* mimic_gif_decode(wuffs_base__io_buffer* dst,
33                              uint32_t wuffs_initialize_flags,
34                              wuffs_base__pixel_format pixfmt,
35                              wuffs_base__io_buffer* src) {
36   const char* ret = NULL;
37 
38   // http://giflib.sourceforge.net/gif_lib.html#compatibility says that "A few
39   // changes in behavior were introduced in 5.0:
40   //
41   // GIF file openers and closers - DGifOpenFileName(), DGifOpenFileHandle(),
42   // DGifOpen(), DGifClose(), EGifOpenFileName(), EGifOpenFileHandle(),
43   // EGifOpen(), and EGifClose() - all now take a final integer address
44   // argument. If non-null, this is used to pass back an error code when the
45   // function returns NULL."
46 #if defined(GIFLIB_MAJOR) && (GIFLIB_MAJOR >= 5)
47   GifFileType* f = DGifOpen(src, mimic_gif_read_func, NULL);
48 #else
49   GifFileType* f = DGifOpen(src, mimic_gif_read_func);
50 #endif
51   if (!f) {
52     ret = "DGifOpen failed";
53     goto cleanup0;
54   }
55   if (DGifSlurp(f) != GIF_OK) {
56     ret = "DGifSlurp failed";
57     goto cleanup1;
58   }
59 
60   int i;
61   for (i = 0; i < f->ImageCount; i++) {
62     // Copy the pixel data from the GifFileType* f to the dst buffer, since the
63     // former is free'd at the end of this function.
64     //
65     // In theory, this mimic_gif_decode function might be faster overall if the
66     // DGifSlurp call above decoded the pixel data directly into dst instead of
67     // into an intermediate buffer that needed to be malloc'ed and then free'd.
68     // In practice, doing so did not seem to show a huge difference. (See
69     // commit ab7e0ae "Add a custom gif_mimic_DGifSlurp function.") It also
70     // further complicates supporting both versions 4 and 5 of giflib. That
71     // commit was therefore rolled back.
72     struct SavedImage* si = &f->SavedImages[i];
73     size_t num_src =
74         (size_t)(si->ImageDesc.Width) * (size_t)(si->ImageDesc.Height);
75     size_t num_dst = dst->data.len - dst->meta.wi;
76     if (num_dst < num_src) {
77       ret = "GIF image's pixel data won't fit in the dst buffer";
78       goto cleanup1;
79     }
80     memmove(dst->data.ptr + dst->meta.wi, si->RasterBits, num_src);
81     dst->meta.wi += num_src;
82   }
83 
84 cleanup1:;
85 #if defined(GIFLIB_MAJOR) && (GIFLIB_MAJOR >= 5)
86   int close_status = DGifCloseFile(f, NULL);
87 #else
88   int close_status = DGifCloseFile(f);
89 #endif
90   if ((close_status != GIF_OK) && !ret) {
91     ret = "DGifCloseFile failed";
92   }
93 cleanup0:;
94   return ret;
95 }
96