blob: 39ecc248a0f4b3810f57e9a70fb3c20ac61ac035 [file] [log] [blame]
Mike Doddd3b009a2015-08-11 11:16:59 -07001/*
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.
26typedef 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//
36class GifTranscoder {
37public:
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
50private:
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.
106class GifFilesCloser {
107public:
108 GifFilesCloser() {}
109 ~GifFilesCloser();
110
111 void setGifIn(GifFileType* gifIn);
112 void releaseGifIn();
113
114 void setGifOut(GifFileType* gifOut);
115 void releaseGifOut();
116
117private:
118 GifFileType* mGifIn = NULL;
119 GifFileType* mGifOut = NULL;
120};
121
122#endif // GIF_TRANSCODER_H