/* * Copyright (C) 2015 The Android Open Source Project * * 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 * * http://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. */ #ifndef GIF_TRANSCODER_H #define GIF_TRANSCODER_H #include #include "gif_lib.h" // 24-bit color with alpha, stored in order: A, R, G, B. // The internal GIF render buffer stores pixels using this format. typedef uint32_t ColorARGB; // Compresses a GIF (probably animated) so it can be sent via MMS, which generally has a 1 MB limit // on attachments. GIF image data is already compressed (LZW), so to achieve further reduction in // file size, we reduce the image dimensions. // // Helpful GIF references: // GIF89A spec: http://www.w3.org/Graphics/GIF/spec-gif89a.txt // What's in a GIF: http://giflib.sourceforge.net/whatsinagif/index.html // class GifTranscoder { public: GifTranscoder() {} ~GifTranscoder() {} // Resizes a GIF's width and height to 50% of their original dimensions. The new file is // written to pathOut. // // The image is resized using a box filter, which averages the colors in each 2x2 box of pixels // in the source to generate the color of the pixel in the destination. // // Returns GIF_OK (1) on success, or GIF_ERROR (0) on failure. int transcode(const char* pathIn, const char* pathOut); private: // Implementation of the box filter algorithm. static bool resizeBoxFilter(GifFileType* gifIn, GifFileType* gifOut); // Reads the raster data for the current image of the GIF. static bool readImage(GifFileType* gifIn, GifByteType* rasterBits); // Renders the current image of the GIF into the supplied render buffer. static bool renderImage(GifFileType* gifIn, GifByteType* rasterBits, int imageIndex, int transparentColorIndex, ColorARGB* renderBuffer, ColorARGB bgColor, GifImageDesc prevImageDimens, int prevImageDisposalMode); // Fills a rectangle in the buffer with a solid color. static void fillRect(ColorARGB* renderBuffer, int imageWidth, int imageHeight, int left, int top, int width, int height, ColorARGB color); // Computes the color for the pixel (x,y) in the current image in the output GIF. static GifByteType computeNewColorIndex(GifFileType* gifIn, int transparentColorIndex, ColorARGB* renderBuffer, int x, int y); // Computes the average color (by averaging the per-channel (ARGB) values). static ColorARGB computeAverage(ColorARGB c1, ColorARGB c2, ColorARGB c3, ColorARGB c4); // Searches a color map for the color closest (Euclidean distance) to the target color. static GifByteType findBestColor(ColorMapObject* colorMap, int transparentColorIndex, ColorARGB targetColor); // Computes distance (squared) between 2 colors, considering each channel a separate dimension. static int computeDistance(ColorARGB c1, ColorARGB c2); // Returns the local color map of the current image (if any), or else the global color map. static ColorMapObject* getColorMap(GifFileType* gifIn); // Returns an indexed color from the color map. static ColorARGB getColorARGB(ColorMapObject* colorMap, int transparentColorIndex, GifByteType colorIndex); // Converts a 24-bit GIF color (RGB) to a 32-bit ARGB color. static ColorARGB gifColorToColorARGB(const GifColorType& color); }; // Wrapper class that automatically closes the GIF files when the wrapper goes out of scope. class GifFilesCloser { public: GifFilesCloser() {} ~GifFilesCloser(); void setGifIn(GifFileType* gifIn); void releaseGifIn(); void setGifOut(GifFileType* gifOut); void releaseGifOut(); private: GifFileType* mGifIn = NULL; GifFileType* mGifOut = NULL; }; #endif // GIF_TRANSCODER_H