Home | History | Annotate | Download | only in gif
      1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
      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     http://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 
     16 // Functions to read images in GIF format.
     17 
     18 #include "tensorflow/core/lib/gif/gif_io.h"
     19 #include <algorithm>
     20 #include "tensorflow/core/lib/gtl/cleanup.h"
     21 #include "tensorflow/core/lib/strings/strcat.h"
     22 #include "tensorflow/core/platform/gif.h"
     23 #include "tensorflow/core/platform/logging.h"
     24 #include "tensorflow/core/platform/mem.h"
     25 #include "tensorflow/core/platform/types.h"
     26 
     27 namespace tensorflow {
     28 namespace gif {
     29 
     30 struct InputBufferInfo {
     31   const uint8_t* buf;
     32   int bytes_left;
     33 };
     34 
     35 int input_callback(GifFileType* gif_file, GifByteType* buf, int size) {
     36   InputBufferInfo* const info =
     37       reinterpret_cast<InputBufferInfo*>(gif_file->UserData);
     38   if (info != nullptr) {
     39     if (size > info->bytes_left) size = info->bytes_left;
     40     memcpy(buf, info->buf, size);
     41     info->buf += size;
     42     info->bytes_left -= size;
     43     return size;
     44   }
     45   return 0;
     46 }
     47 
     48 static const char* GifErrorStringNonNull(int error_code) {
     49   const char* error_string = GifErrorString(error_code);
     50   if (error_string == nullptr) {
     51     return "Unknown error";
     52   }
     53   return error_string;
     54 }
     55 
     56 uint8* Decode(const void* srcdata, int datasize,
     57               const std::function<uint8*(int, int, int, int)>& allocate_output,
     58               string* error_string) {
     59   int error_code = D_GIF_SUCCEEDED;
     60   InputBufferInfo info = {reinterpret_cast<const uint8*>(srcdata), datasize};
     61   GifFileType* gif_file =
     62       DGifOpen(static_cast<void*>(&info), &input_callback, &error_code);
     63   const auto cleanup = gtl::MakeCleanup([gif_file]() {
     64     int error_code = D_GIF_SUCCEEDED;
     65     if (gif_file && DGifCloseFile(gif_file, &error_code) != GIF_OK) {
     66       LOG(WARNING) << "Fail to close gif file, reason: "
     67                    << GifErrorStringNonNull(error_code);
     68     }
     69   });
     70   if (error_code != D_GIF_SUCCEEDED) {
     71     *error_string = strings::StrCat("failed to open gif file: ",
     72                                     GifErrorStringNonNull(error_code));
     73     return nullptr;
     74   }
     75   if (DGifSlurp(gif_file) != GIF_OK) {
     76     *error_string = strings::StrCat("failed to slurp gif file: ",
     77                                     GifErrorStringNonNull(gif_file->Error));
     78     return nullptr;
     79   }
     80   if (gif_file->ImageCount <= 0) {
     81     *error_string = strings::StrCat("gif file does not contain any image");
     82     return nullptr;
     83   }
     84 
     85   const int num_frames = gif_file->ImageCount;
     86   const int width = gif_file->SWidth;
     87   const int height = gif_file->SHeight;
     88   const int channel = 3;
     89 
     90   uint8* const dstdata = allocate_output(num_frames, width, height, channel);
     91   if (!dstdata) return nullptr;
     92   for (int k = 0; k < num_frames; k++) {
     93     uint8* this_dst = dstdata + k * width * channel * height;
     94 
     95     SavedImage* this_image = &gif_file->SavedImages[k];
     96     GifImageDesc* img_desc = &this_image->ImageDesc;
     97 
     98     int imgLeft = img_desc->Left;
     99     int imgTop = img_desc->Top;
    100     int imgRight = img_desc->Left + img_desc->Width;
    101     int imgBottom = img_desc->Top + img_desc->Height;
    102 
    103     if (img_desc->Left != 0 || img_desc->Top != 0 || img_desc->Width != width ||
    104         img_desc->Height != height) {
    105       // If the first frame does not fill the entire canvas then return error.
    106       if (k == 0) {
    107         *error_string =
    108             strings::StrCat("the first frame does not fill the canvas");
    109         return nullptr;
    110       }
    111       // Otherwise previous frame will be reused to fill the unoccupied canvas.
    112       imgLeft = std::max(imgLeft, 0);
    113       imgTop = std::max(imgTop, 0);
    114       imgRight = std::min(imgRight, width);
    115       imgBottom = std::min(imgBottom, height);
    116 
    117       uint8* last_dst = dstdata + (k - 1) * width * channel * height;
    118       for (int i = 0; i < height; ++i) {
    119         uint8* p_dst = this_dst + i * width * channel;
    120         uint8* l_dst = last_dst + i * width * channel;
    121         for (int j = 0; j < width; ++j) {
    122           p_dst[j * channel + 0] = l_dst[j * channel + 0];
    123           p_dst[j * channel + 1] = l_dst[j * channel + 1];
    124           p_dst[j * channel + 2] = l_dst[j * channel + 2];
    125         }
    126       }
    127     }
    128 
    129     ColorMapObject* color_map = this_image->ImageDesc.ColorMap
    130                                     ? this_image->ImageDesc.ColorMap
    131                                     : gif_file->SColorMap;
    132 
    133     for (int i = imgTop; i < imgBottom; ++i) {
    134       uint8* p_dst = this_dst + i * width * channel;
    135       for (int j = imgLeft; j < imgRight; ++j) {
    136         GifByteType color_index =
    137             this_image->RasterBits[(i - img_desc->Top) * (img_desc->Width) +
    138                                    (j - img_desc->Left)];
    139         const GifColorType& gif_color = color_map->Colors[color_index];
    140         p_dst[j * channel + 0] = gif_color.Red;
    141         p_dst[j * channel + 1] = gif_color.Green;
    142         p_dst[j * channel + 2] = gif_color.Blue;
    143       }
    144     }
    145   }
    146 
    147   return dstdata;
    148 }
    149 
    150 }  // namespace gif
    151 }  // namespace tensorflow
    152