1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef GIF_TRANSCODER_H 18 #define GIF_TRANSCODER_H 19 20 #include <sys/types.h> 21 22 #include "gif_lib.h" 23 24 // 24-bit color with alpha, stored in order: A, R, G, B. 25 // The internal GIF render buffer stores pixels using this format. 26 typedef uint32_t ColorARGB; 27 28 // Compresses a GIF (probably animated) so it can be sent via MMS, which generally has a 1 MB limit 29 // on attachments. GIF image data is already compressed (LZW), so to achieve further reduction in 30 // file size, we reduce the image dimensions. 31 // 32 // Helpful GIF references: 33 // GIF89A spec: http://www.w3.org/Graphics/GIF/spec-gif89a.txt 34 // What's in a GIF: http://giflib.sourceforge.net/whatsinagif/index.html 35 // 36 class GifTranscoder { 37 public: 38 GifTranscoder() {} 39 ~GifTranscoder() {} 40 41 // Resizes a GIF's width and height to 50% of their original dimensions. The new file is 42 // written to pathOut. 43 // 44 // The image is resized using a box filter, which averages the colors in each 2x2 box of pixels 45 // in the source to generate the color of the pixel in the destination. 46 // 47 // Returns GIF_OK (1) on success, or GIF_ERROR (0) on failure. 48 int transcode(const char* pathIn, const char* pathOut); 49 50 private: 51 // Implementation of the box filter algorithm. 52 static bool resizeBoxFilter(GifFileType* gifIn, GifFileType* gifOut); 53 54 // Reads the raster data for the current image of the GIF. 55 static bool readImage(GifFileType* gifIn, GifByteType* rasterBits); 56 57 // Renders the current image of the GIF into the supplied render buffer. 58 static bool renderImage(GifFileType* gifIn, 59 GifByteType* rasterBits, 60 int imageIndex, 61 int transparentColorIndex, 62 ColorARGB* renderBuffer, 63 ColorARGB bgColor, 64 GifImageDesc prevImageDimens, 65 int prevImageDisposalMode); 66 67 // Fills a rectangle in the buffer with a solid color. 68 static void fillRect(ColorARGB* renderBuffer, 69 int imageWidth, 70 int imageHeight, 71 int left, 72 int top, 73 int width, 74 int height, 75 ColorARGB color); 76 77 // Computes the color for the pixel (x,y) in the current image in the output GIF. 78 static GifByteType computeNewColorIndex(GifFileType* gifIn, 79 int transparentColorIndex, 80 ColorARGB* renderBuffer, 81 int x, 82 int y); 83 84 // Computes the average color (by averaging the per-channel (ARGB) values). 85 static ColorARGB computeAverage(ColorARGB c1, ColorARGB c2, ColorARGB c3, ColorARGB c4); 86 87 // Searches a color map for the color closest (Euclidean distance) to the target color. 88 static GifByteType findBestColor(ColorMapObject* colorMap, int transparentColorIndex, 89 ColorARGB targetColor); 90 91 // Computes distance (squared) between 2 colors, considering each channel a separate dimension. 92 static int computeDistance(ColorARGB c1, ColorARGB c2); 93 94 // Returns the local color map of the current image (if any), or else the global color map. 95 static ColorMapObject* getColorMap(GifFileType* gifIn); 96 97 // Returns an indexed color from the color map. 98 static ColorARGB getColorARGB(ColorMapObject* colorMap, int transparentColorIndex, 99 GifByteType colorIndex); 100 101 // Converts a 24-bit GIF color (RGB) to a 32-bit ARGB color. 102 static ColorARGB gifColorToColorARGB(const GifColorType& color); 103 }; 104 105 // Wrapper class that automatically closes the GIF files when the wrapper goes out of scope. 106 class GifFilesCloser { 107 public: 108 GifFilesCloser() {} 109 ~GifFilesCloser(); 110 111 void setGifIn(GifFileType* gifIn); 112 void releaseGifIn(); 113 114 void setGifOut(GifFileType* gifOut); 115 void releaseGifOut(); 116 117 private: 118 GifFileType* mGifIn = NULL; 119 GifFileType* mGifOut = NULL; 120 }; 121 122 #endif // GIF_TRANSCODER_H 123