1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
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 #include "gif_encoder.h"
16 #include "image_log.h"
17 #include "image_trace.h"
18 #include "media_errors.h"
19 #include "securec.h"
20 #include <iostream>
21 #undef LOG_DOMAIN
22 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_PLUGIN
23 
24 #undef LOG_TAG
25 #define LOG_TAG "GifEncoder"
26 
27 namespace OHOS {
28 namespace ImagePlugin {
29 using namespace MultimediaPlugin;
30 using namespace Media;
31 
32 const int BITS_IN_BYTE = 8;
33 const int BITS_PER_PRIM_COLOR = 5;
34 const int RED_COORDINATE = 10;
35 const int GREEN_COORDINATE = 5;
36 const int BLUE_COORDINATE = 0;
37 const int R_IN_RGB = 0;
38 const int G_IN_RGB = 1;
39 const int B_IN_RGB = 2;
40 const int COLOR_OF_GIF = 256;
41 const int COLOR_MAP_SIZE = 256;
42 const int COLOR_ARRAY_SIZE = 32768;
43 const int EXTENSION_INTRODUCER = 0x21;
44 const int APPLICATION_EXTENSION_LABEL = 0xFF;
45 const int GRAPHIC_CONTROL_LABEL = 0xF9;
46 const int IMAGE_SEPARATOR = 0x2C;
47 const int LZ_BITS = 12;
48 const int CLEAR_CODE = 256;
49 const int LZ_MAX_CODE = 4095;
50 const int FLUSH_OUTPUT = 4096;
51 const int FIRST_CODE = 4097;
52 const int DEFAULT_DELAY_TIME = 100;
53 const int DEFAULT_DISPOSAL_TYPE = 1;
54 const int DISPOSAL_METHOD_SHIFT_BIT = 2;
55 
56 const uint8_t GIF89_STAMP[] = {0x47, 0x49, 0x46, 0x38, 0x39, 0x61};
57 const uint8_t APPLICATION_IDENTIFIER[] = {0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45};
58 const uint8_t APPLICATION_AUTENTICATION_CODE[] = {0x32, 0x2E, 0x30};
59 
60 static int g_sortRGBAxis = 0;
61 
62 #pragma pack(1)
63 typedef struct LogicalScreenDescriptor {
64     uint16_t logicalScreenWidth;
65     uint16_t logicalScreenHeight;
66     uint8_t packedFields;
67     uint8_t backgroundColorIndex;
68     uint8_t pixelAspectRatio;
69 } LogicalScreenDescriptor;
70 
71 typedef struct ApplicationExtension {
72     uint8_t extensionIntroducer;
73     uint8_t extensionLabel;
74     uint8_t blockSize;
75     uint8_t applicationIdentifier[8];
76     uint8_t applicationAuthenticationCode[3];
77     uint8_t applicationDataSize;
78     uint8_t applicationDataIndex;
79     uint16_t loopTime;
80     uint8_t blockTerminator;
81 } ApplicationExtension;
82 
83 typedef struct GraphicControlExtension {
84     uint8_t extensionIntroducer;
85     uint8_t graphicControlLabel;
86     uint8_t blockSize;
87     uint8_t packedFields;
88     uint16_t delayTime;
89     uint8_t transparentColorIndex;
90     uint8_t blockTerminator;
91 } GraphicControlExtension;
92 
93 typedef struct ImageDescriptor {
94     uint8_t imageSeparator;
95     uint16_t imageLeftPosition;
96     uint16_t imageTopPosition;
97     uint16_t imageWidth;
98     uint16_t imageHeight;
99     uint8_t packedFields;
100 } ImageDescriptor;
101 
102 typedef struct ColorInput {
103     const uint8_t *redInput;
104     const uint8_t *greenInput;
105     const uint8_t *blueInput;
106 } ColorInput;
107 #pragma pack()
108 
GifEncoder()109 GifEncoder::GifEncoder()
110 {
111     IMAGE_LOGD("create IN");
112 
113     IMAGE_LOGD("create OUT");
114 }
115 
~GifEncoder()116 GifEncoder::~GifEncoder()
117 {
118     IMAGE_LOGD("release IN");
119 
120     pixelMaps_.clear();
121 
122     IMAGE_LOGD("release OUT");
123 }
124 
StartEncode(OutputDataStream & outputStream,PlEncodeOptions & option)125 uint32_t GifEncoder::StartEncode(OutputDataStream &outputStream, PlEncodeOptions &option)
126 {
127     IMAGE_LOGD("StartEncode IN, quality=%{public}u, numberHint=%{public}u",
128         option.quality, option.numberHint);
129 
130     pixelMaps_.clear();
131     outputStream_ = &outputStream;
132     encodeOpts_ = option;
133 
134     IMAGE_LOGD("StartEncode OUT");
135     return SUCCESS;
136 }
137 
AddImage(Media::PixelMap & pixelMap)138 uint32_t GifEncoder::AddImage(Media::PixelMap &pixelMap)
139 {
140     IMAGE_LOGD("AddImage IN");
141 
142     if (pixelMap.GetPixels() == nullptr) {
143         IMAGE_LOGE("AddImage failed, invalid pixelMap.");
144         return ERR_IMAGE_ENCODE_FAILED;
145     }
146 
147     pixelMaps_.push_back(&pixelMap);
148     IMAGE_LOGD("AddImage OUT");
149     return SUCCESS;
150 }
151 
AddPicture(Media::Picture & picture)152 uint32_t GifEncoder::AddPicture(Media::Picture &picture)
153 {
154     ImageTrace imageTrace("GifEncoder::AddPicture");
155     return ERR_IMAGE_ENCODE_FAILED;
156 }
157 
FinalizeEncode()158 uint32_t GifEncoder::FinalizeEncode()
159 {
160     ImageTrace imageTrace("GifEncoder::FinalizeEncode");
161     IMAGE_LOGD("FinalizeEncode IN");
162 
163     if (pixelMaps_.empty()) {
164         IMAGE_LOGE("FinalizeEncode, no pixel map input.");
165         return ERR_IMAGE_INVALID_PARAMETER;
166     }
167 
168     uint32_t errorCode = ERROR;
169     errorCode = DoEncode();
170     if (errorCode != SUCCESS) {
171         IMAGE_LOGE("FinalizeEncode, encode failed=%{public}u.", errorCode);
172     }
173 
174     IMAGE_LOGD("FinalizeEncode OUT");
175     return errorCode;
176 }
177 
DoEncode()178 uint32_t GifEncoder::DoEncode()
179 {
180     IMAGE_LOGD("DoEncode IN");
181 
182     WriteFileInfo();
183 
184     for (int index = 0; index < pixelMaps_.size(); index++) {
185         InitDictionary();
186         WriteFrameInfo(index);
187         processFrame(index);
188     }
189 
190     IMAGE_LOGD("DoEncode OUT");
191     return SUCCESS;
192 }
193 
WriteFileInfo()194 uint32_t GifEncoder::WriteFileInfo()
195 {
196     if (!Write(GIF89_STAMP, sizeof(GIF89_STAMP))) {
197         IMAGE_LOGE("Write to buffer error.");
198         return ERR_IMAGE_ENCODE_FAILED;
199     }
200 
201     LogicalScreenDescriptor lsd;
202     memset_s(&lsd, sizeof(LogicalScreenDescriptor), 0, sizeof(LogicalScreenDescriptor));
203     for (auto pixelMap : pixelMaps_) {
204         if (lsd.logicalScreenWidth < static_cast<uint16_t>(pixelMap->GetWidth())) {
205             lsd.logicalScreenWidth = static_cast<uint16_t>(pixelMap->GetWidth());
206         }
207         if (lsd.logicalScreenHeight < static_cast<uint16_t>(pixelMap->GetHeight())) {
208             lsd.logicalScreenHeight = static_cast<uint16_t>(pixelMap->GetHeight());
209         }
210     }
211     if (!Write((const uint8_t*)&lsd, sizeof(LogicalScreenDescriptor))) {
212         IMAGE_LOGE("Write to buffer error.");
213         return ERR_IMAGE_ENCODE_FAILED;
214     }
215 
216     ApplicationExtension ae;
217     memset_s(&ae, sizeof(ApplicationExtension), 0, sizeof(ApplicationExtension));
218     ae.extensionIntroducer = EXTENSION_INTRODUCER;
219     ae.extensionLabel = APPLICATION_EXTENSION_LABEL;
220     ae.blockSize = 0x0B;
221     memcpy_s(&ae.applicationIdentifier, sizeof(ae.applicationIdentifier),
222              &APPLICATION_IDENTIFIER, sizeof(ae.applicationIdentifier));
223     memcpy_s(&ae.applicationAuthenticationCode, sizeof(ae.applicationIdentifier),
224              &APPLICATION_AUTENTICATION_CODE, sizeof(ae.applicationAuthenticationCode));
225     ae.applicationDataSize = 0x03;
226     ae.applicationDataIndex = 0x01;
227     ae.loopTime = encodeOpts_.loop;
228     ae.blockTerminator = 0x00;
229     if (!Write((const uint8_t*)&ae, sizeof(ApplicationExtension))) {
230         IMAGE_LOGE("Write to buffer error.");
231         return ERR_IMAGE_ENCODE_FAILED;
232     }
233 
234     return SUCCESS;
235 }
236 
WriteFrameInfo(int index)237 uint32_t GifEncoder::WriteFrameInfo(int index)
238 {
239     GraphicControlExtension gce;
240     memset_s(&gce, sizeof(GraphicControlExtension), 0, sizeof(GraphicControlExtension));
241     gce.extensionIntroducer = EXTENSION_INTRODUCER;
242     gce.graphicControlLabel = GRAPHIC_CONTROL_LABEL;
243     gce.blockSize = 0x04;
244     gce.packedFields = 0x00;
245     gce.packedFields |= (((index < encodeOpts_.disposalTypes.size() ?
246         encodeOpts_.disposalTypes[index] : DEFAULT_DISPOSAL_TYPE) & 0x07) << DISPOSAL_METHOD_SHIFT_BIT);
247     gce.delayTime = index < encodeOpts_.delayTimes.size() ? encodeOpts_.delayTimes[index] : DEFAULT_DELAY_TIME;
248     gce.transparentColorIndex = 0x00;
249     gce.blockTerminator = 0x00;
250     if (!Write((const uint8_t*)&gce, sizeof(GraphicControlExtension))) {
251         IMAGE_LOGE("Write to buffer error.");
252         return ERR_IMAGE_ENCODE_FAILED;
253     }
254 
255     ImageDescriptor id;
256     memset_s(&id, sizeof(ImageDescriptor), 0, sizeof(ImageDescriptor));
257     id.imageSeparator = IMAGE_SEPARATOR;
258     id.imageLeftPosition = 0x0000;
259     id.imageTopPosition = 0x0000;
260     id.imageWidth = static_cast<uint16_t>(pixelMaps_[index]->GetWidth());
261     id.imageHeight = static_cast<uint16_t>(pixelMaps_[index]->GetHeight());
262     id.packedFields = 0x87;
263     if (!Write((const uint8_t*)&id, sizeof(ImageDescriptor))) {
264         IMAGE_LOGE("Write to buffer error.");
265         return ERR_IMAGE_ENCODE_FAILED;
266     }
267 
268     return SUCCESS;
269 }
270 
processFrame(int index)271 uint32_t GifEncoder::processFrame(int index)
272 {
273     ColorType *colorMap = (ColorType *)malloc(sizeof(ColorType) * COLOR_MAP_SIZE);
274     if (colorMap == NULL) {
275         IMAGE_LOGE("Failed to allocate memory.");
276         return ERR_IMAGE_ENCODE_FAILED;
277     }
278     uint16_t width = static_cast<uint16_t>(pixelMaps_[index]->GetWidth());
279     uint16_t height = static_cast<uint16_t>(pixelMaps_[index]->GetHeight());
280     uint64_t frameSize = width * height;
281     uint8_t *colorBuffer = (uint8_t *)malloc(frameSize);
282     if (colorBuffer == NULL) {
283         IMAGE_LOGE("Failed to allocate memory.");
284         free(colorMap);
285         return ERR_IMAGE_ENCODE_FAILED;
286     }
287     if (colorQuantize(index, width, height, colorBuffer, colorMap)) {
288         IMAGE_LOGE("Failed to quantize color.");
289         free(colorBuffer);
290         free(colorMap);
291         return ERR_IMAGE_ENCODE_FAILED;
292     }
293     for (int j = 0; j < COLOR_MAP_SIZE; j++) {
294         Write(&(colorMap[j].red), 1);
295         Write(&(colorMap[j].green), 1);
296         Write(&(colorMap[j].blue), 1);
297     }
298 
299     if (LZWEncodeFrame(colorBuffer, width, height)) {
300         IMAGE_LOGE("Failed to encode frame.");
301         free(colorBuffer);
302         free(colorMap);
303         return ERR_IMAGE_ENCODE_FAILED;
304     }
305 
306     free(colorBuffer);
307     free(colorMap);
308 
309     return SUCCESS;
310 }
311 
colorQuantize(int index,uint16_t width,uint16_t height,uint8_t * outputBuffer,ColorType * outputColorMap)312 uint32_t GifEncoder::colorQuantize(int index, uint16_t width, uint16_t height,
313                                    uint8_t *outputBuffer, ColorType *outputColorMap)
314 {
315     uint8_t *redBuffer = NULL;
316     uint8_t *greenBuffer = NULL;
317     uint8_t *blueBuffer = NULL;
318     uint64_t frameSize = width * height;
319     if ((redBuffer = (uint8_t *)malloc(frameSize)) == NULL ||
320         (greenBuffer = (uint8_t *)malloc(frameSize)) == NULL ||
321         (blueBuffer = (uint8_t *)malloc(frameSize)) == NULL) {
322         IMAGE_LOGE("Failed to allocate memory.");
323         return ERR_IMAGE_ENCODE_FAILED;
324     }
325 
326     if (separateRGB(index, width, height, redBuffer, greenBuffer, blueBuffer)) {
327         IMAGE_LOGE("Failed to separate RGB, aborted.");
328         free(redBuffer);
329         free(greenBuffer);
330         free(blueBuffer);
331         return ERR_IMAGE_ENCODE_FAILED;
332     }
333 
334     if (doColorQuantize(width, height, redBuffer, greenBuffer, blueBuffer, outputBuffer, outputColorMap)) {
335         IMAGE_LOGE("Failed to quantize buffer, aborted.");
336         free(redBuffer);
337         free(greenBuffer);
338         free(blueBuffer);
339         return ERR_IMAGE_ENCODE_FAILED;
340     }
341 
342     free(redBuffer);
343     free(greenBuffer);
344     free(blueBuffer);
345 
346     return SUCCESS;
347 }
348 
separateRGB(int index,uint16_t width,uint16_t height,uint8_t * redBuffer,uint8_t * greenBuffer,uint8_t * blueBuffer)349 uint32_t GifEncoder::separateRGB(int index, uint16_t width, uint16_t height,
350                                  uint8_t *redBuffer, uint8_t *greenBuffer, uint8_t *blueBuffer)
351 {
352     for (int y = 0; y < height; y++) {
353         for (int x = 0; x < width; x++) {
354             uint32_t pixelColor;
355             if (!pixelMaps_[index]->GetARGB32Color(x, y, pixelColor)) {
356                 IMAGE_LOGE("Failed to get rgb value.");
357                 return ERR_IMAGE_ENCODE_FAILED;
358             }
359             redBuffer[y * width + x] = pixelMaps_[index]->GetARGB32ColorR(pixelColor);
360             greenBuffer[y * width + x] = pixelMaps_[index]->GetARGB32ColorG(pixelColor);
361             blueBuffer[y * width + x] = pixelMaps_[index]->GetARGB32ColorB(pixelColor);
362         }
363     }
364 
365     return SUCCESS;
366 }
367 
InitColorCube(ColorCoordinate * colorCoordinate,uint16_t width,uint16_t height,ColorInput * colorInput)368 void InitColorCube(ColorCoordinate *colorCoordinate, uint16_t width, uint16_t height,
369                    ColorInput *colorInput)
370 {
371     for (int i = 0; i < COLOR_ARRAY_SIZE; i++) {
372         colorCoordinate[i].rgb[R_IN_RGB] = (i >> RED_COORDINATE) & 0x1F;
373         colorCoordinate[i].rgb[G_IN_RGB] = (i >> GREEN_COORDINATE) & 0x1F;
374         colorCoordinate[i].rgb[B_IN_RGB] = (i >> BLUE_COORDINATE) & 0x1F;
375         colorCoordinate[i].pixelNum = 0;
376     }
377 
378     for (int i = 0; i < static_cast<int>(width * height); i++) {
379         uint16_t index = ((colorInput->redInput[i] >> (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) << RED_COORDINATE) +
380                  ((colorInput->greenInput[i] >> (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) << GREEN_COORDINATE) +
381                  ((colorInput->blueInput[i] >> (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) << BLUE_COORDINATE);
382         colorCoordinate[index].pixelNum++;
383     }
384 }
385 
InitColorSubdivMap(ColorSubdivMap * colorSubdivMap,uint16_t width,uint16_t height)386 void InitColorSubdivMap(ColorSubdivMap* colorSubdivMap, uint16_t width, uint16_t height)
387 {
388     for (int i = 0; i < COLOR_OF_GIF; i++) {
389         for (int j = 0; j < NUM_OF_RGB; j++) {
390             colorSubdivMap[i].rgbMin[j] = 0;
391             colorSubdivMap[i].rgbWidth[j] = 0xFF;
392         }
393         colorSubdivMap[i].coordinate = NULL;
394         colorSubdivMap[i].pixelNum = 0;
395         colorSubdivMap[i].colorNum = 0;
396     }
397     colorSubdivMap[0].pixelNum = ((long)width) * height;
398 }
399 
InitForQuantize(ColorCoordinate * colorCoordinate,ColorSubdivMap * colorSubdivMap)400 void InitForQuantize(ColorCoordinate *colorCoordinate, ColorSubdivMap* colorSubdivMap)
401 {
402     ColorCoordinate* coordinate;
403     for (int i = 0; i < COLOR_ARRAY_SIZE; i++) {
404         if (colorCoordinate[i].pixelNum > 0) {
405             if (colorSubdivMap[0].colorNum == 0) {
406                 coordinate = &colorCoordinate[i];
407                 colorSubdivMap[0].coordinate = &colorCoordinate[i];
408                 colorSubdivMap[0].colorNum++;
409             } else {
410                 coordinate->next = &colorCoordinate[i];
411                 coordinate = &colorCoordinate[i];
412                 colorSubdivMap[0].colorNum++;
413             }
414         }
415     }
416     coordinate->next = NULL;
417 }
418 
doColorQuantize(uint16_t width,uint16_t height,const uint8_t * redInput,const uint8_t * greenInput,const uint8_t * blueInput,uint8_t * outputBuffer,ColorType * outputColorMap)419 uint32_t GifEncoder::doColorQuantize(uint16_t width, uint16_t height,
420                                      const uint8_t *redInput, const uint8_t *greenInput, const uint8_t *blueInput,
421                                      uint8_t *outputBuffer, ColorType *outputColorMap)
422 {
423     uint32_t colorSubdivMapSize = 1;
424     ColorSubdivMap colorSubdivMap[COLOR_OF_GIF];
425 
426     ColorCoordinate *colorCoordinate = (ColorCoordinate *)malloc(sizeof(ColorCoordinate) * COLOR_ARRAY_SIZE);
427     if (colorCoordinate == NULL) {
428         return ERR_IMAGE_ENCODE_FAILED;
429     }
430 
431     ColorInput colorInput;
432     colorInput.redInput = redInput;
433     colorInput.greenInput = greenInput;
434     colorInput.blueInput = blueInput;
435     InitColorCube(colorCoordinate, width, height, &colorInput);
436     InitColorSubdivMap(colorSubdivMap, width, height);
437     InitForQuantize(colorCoordinate, colorSubdivMap);
438 
439     if (BuildColorSubdivMap(colorSubdivMap, &colorSubdivMapSize)) {
440         free(colorCoordinate);
441         return ERR_IMAGE_ENCODE_FAILED;
442     }
443     if (colorSubdivMapSize < COLOR_MAP_SIZE) {
444         memset_s(outputColorMap, sizeof(ColorType) * COLOR_MAP_SIZE, 0, sizeof(ColorType) * COLOR_MAP_SIZE);
445     }
446 
447     for (int i = 0; i < colorSubdivMapSize; i++) {
448         if (colorSubdivMap[i].colorNum > 0) {
449             ColorCoordinate *coordinate = colorSubdivMap[i].coordinate;
450             long red = 0;
451             long green = 0;
452             long blue = 0;
453             while (coordinate) {
454                 red += coordinate->rgb[R_IN_RGB];
455                 green += coordinate->rgb[G_IN_RGB];
456                 blue += coordinate->rgb[B_IN_RGB];
457                 coordinate->newColorIndex = i;
458                 coordinate = coordinate->next;
459             }
460             outputColorMap[i].red = (red << (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) / colorSubdivMap[i].colorNum;
461             outputColorMap[i].green = (green << (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) / colorSubdivMap[i].colorNum;
462             outputColorMap[i].blue = (blue << (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) / colorSubdivMap[i].colorNum;
463         }
464     }
465     for (int i = 0; i < ((long)width) * height; i++) {
466         uint32_t index = ((redInput[i] >> (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) << RED_COORDINATE) +
467             ((greenInput[i] >> (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) << GREEN_COORDINATE) +
468             ((blueInput[i] >> (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) << BLUE_COORDINATE);
469         outputBuffer[i] = colorCoordinate[index].newColorIndex;
470     }
471 
472     free(colorCoordinate);
473 
474     return SUCCESS;
475 }
476 
SortCmpRtn(const void * inEntry1,const void * inEntry2)477 int32_t SortCmpRtn(const void *inEntry1, const void *inEntry2)
478 {
479     ColorCoordinate *entry1 = (*((ColorCoordinate **)inEntry1));
480     ColorCoordinate *entry2 = (*((ColorCoordinate **)inEntry2));
481 
482     int32_t hash1 = entry1->rgb[(g_sortRGBAxis + R_IN_RGB)] * COLOR_OF_GIF * COLOR_OF_GIF +
483                 entry1->rgb[(g_sortRGBAxis + G_IN_RGB) % NUM_OF_RGB] * COLOR_OF_GIF +
484                 entry1->rgb[(g_sortRGBAxis + B_IN_RGB) % NUM_OF_RGB];
485     int32_t hash2 = entry2->rgb[(g_sortRGBAxis + R_IN_RGB)] * COLOR_OF_GIF * COLOR_OF_GIF +
486                 entry2->rgb[(g_sortRGBAxis + G_IN_RGB) % NUM_OF_RGB] * COLOR_OF_GIF +
487                 entry2->rgb[(g_sortRGBAxis + B_IN_RGB) % NUM_OF_RGB];
488 
489     return (hash1 - hash2);
490 }
491 
492 
PrepareSort(ColorSubdivMap * colorSubdivMap,uint32_t colorSubdivMapSize)493 uint32_t PrepareSort(ColorSubdivMap *colorSubdivMap, uint32_t colorSubdivMapSize)
494 {
495     int maxSize = -1;
496     int index = -1;
497     for (int i = 0; i < colorSubdivMapSize; i++) {
498         for (int j = 0; j < NUM_OF_RGB; j++) {
499             if ((static_cast<int>(colorSubdivMap[i].rgbWidth[j]) > maxSize) && (colorSubdivMap[i].colorNum > 1)) {
500                 maxSize = colorSubdivMap[i].rgbWidth[j];
501                 index = i;
502                 g_sortRGBAxis = j;
503             }
504         }
505     }
506     return index;
507 }
508 
doSort(ColorCoordinate ** sortArray,ColorSubdivMap * colorSubdivMap,uint32_t index)509 void doSort(ColorCoordinate **sortArray, ColorSubdivMap *colorSubdivMap, uint32_t index)
510 {
511     int i;
512     ColorCoordinate *colorCoordinate = nullptr;
513     for (i = 0, colorCoordinate = colorSubdivMap[index].coordinate;
514          i < colorSubdivMap[index].colorNum && colorCoordinate != NULL;
515          i++, colorCoordinate = colorCoordinate->next) {
516         sortArray[i] = colorCoordinate;
517     }
518     qsort(sortArray, colorSubdivMap[index].colorNum, sizeof(ColorCoordinate *), SortCmpRtn);
519 }
520 
SubdivColorByPartition(ColorCoordinate * colorCoordinate,ColorSubdivMap * colorSubdivMap,uint32_t colorSubdivMapSize,int index)521 void SubdivColorByPartition(ColorCoordinate *colorCoordinate, ColorSubdivMap *colorSubdivMap,
522     uint32_t colorSubdivMapSize, int index)
523 {
524     long sum = (colorSubdivMap[index].pixelNum >> 1) - colorCoordinate->pixelNum;
525     uint32_t colorNum = 1;
526     long pixelNum = colorCoordinate->pixelNum;
527     while (colorCoordinate->next != NULL &&
528         (sum -= colorCoordinate->next->pixelNum) >= 0 &&
529            colorCoordinate->next->next != NULL) {
530         colorCoordinate = colorCoordinate->next;
531         colorNum++;
532         pixelNum += colorCoordinate->pixelNum;
533     }
534     uint32_t maxColor = colorCoordinate->rgb[g_sortRGBAxis] << (BITS_IN_BYTE - BITS_PER_PRIM_COLOR);
535     uint32_t minColor = colorCoordinate->next->rgb[g_sortRGBAxis] << (BITS_IN_BYTE - BITS_PER_PRIM_COLOR);
536     colorSubdivMap[colorSubdivMapSize].coordinate = colorCoordinate->next;
537     colorCoordinate->next = NULL;
538     colorSubdivMap[colorSubdivMapSize].pixelNum = colorSubdivMap[index].pixelNum - pixelNum;
539     colorSubdivMap[index].pixelNum = pixelNum;
540     colorSubdivMap[colorSubdivMapSize].colorNum = colorSubdivMap[index].colorNum - colorNum;
541     colorSubdivMap[index].colorNum = colorNum;
542     for (int i = 0; i < NUM_OF_RGB; i++) {
543         colorSubdivMap[colorSubdivMapSize].rgbMin[i] = colorSubdivMap[index].rgbMin[i];
544         colorSubdivMap[colorSubdivMapSize].rgbWidth[i] = colorSubdivMap[index].rgbWidth[i];
545     }
546     colorSubdivMap[colorSubdivMapSize].rgbWidth[g_sortRGBAxis] =
547         colorSubdivMap[colorSubdivMapSize].rgbMin[g_sortRGBAxis] +
548         colorSubdivMap[colorSubdivMapSize].rgbWidth[g_sortRGBAxis] - minColor;
549     colorSubdivMap[colorSubdivMapSize].rgbMin[g_sortRGBAxis] = minColor;
550     colorSubdivMap[index].rgbWidth[g_sortRGBAxis] = maxColor - colorSubdivMap[index].rgbMin[g_sortRGBAxis];
551 }
552 
BuildColorSubdivMap(ColorSubdivMap * colorSubdivMap,uint32_t * colorSubdivMapSize)553 uint32_t GifEncoder::BuildColorSubdivMap(ColorSubdivMap *colorSubdivMap, uint32_t *colorSubdivMapSize)
554 {
555     int index = 0;
556     ColorCoordinate **sortArray;
557 
558     while (*colorSubdivMapSize < COLOR_MAP_SIZE) {
559         index = PrepareSort(colorSubdivMap, *colorSubdivMapSize);
560         if (index < 0) {
561             return SUCCESS;
562         }
563         sortArray = (ColorCoordinate **)malloc(sizeof(ColorCoordinate *) * colorSubdivMap[index].colorNum);
564         if (sortArray == NULL) {
565             return ERR_IMAGE_ENCODE_FAILED;
566         }
567         doSort(sortArray, colorSubdivMap, index);
568 
569         for (int i = 0; i < colorSubdivMap[index].colorNum - 1; i++) {
570             sortArray[i]->next = sortArray[i + 1];
571         }
572         sortArray[colorSubdivMap[index].colorNum - 1]->next = NULL;
573         colorSubdivMap[index].coordinate = sortArray[0];
574         ColorCoordinate *colorCoordinate = sortArray[0];
575         free(sortArray);
576         SubdivColorByPartition(colorCoordinate, colorSubdivMap, *colorSubdivMapSize, index);
577         (*colorSubdivMapSize)++;
578     }
579 
580     return SUCCESS;
581 }
582 
InitDictionary()583 void GifEncoder::InitDictionary()
584 {
585     lastCode_ = FIRST_CODE;
586     clearCode_ = CLEAR_CODE;
587     eofCode_ = clearCode_ + 1;
588     runningCode_ = eofCode_ + 1;
589     runningBits_ = BITS_IN_BYTE + 1;
590     maxCode_ = 1 << runningBits_;
591     crntShiftState_ = 0;
592     crntShiftDWord_ = 0;
593     memset_s(dictionary_, sizeof(uint32_t) * DICTIONARY_SIZE, 0xFF, sizeof(uint32_t) * DICTIONARY_SIZE);
594 }
595 
IsInDictionary(uint32_t Key)596 int GifEncoder::IsInDictionary(uint32_t Key)
597 {
598     int key = ((Key >> LZ_BITS) ^ Key) & 0x1FFF;
599     uint32_t DKey;
600     while ((DKey = (dictionary_[key] >> LZ_BITS)) != 0xFFFFFL) {
601         if (Key == DKey) {
602             return (dictionary_[key] & 0x0FFF);
603         }
604         key = (key + 1) & 0x1FFF;
605     }
606     return -1;
607 }
608 
AddToDictionary(uint32_t Key,int Code)609 void GifEncoder::AddToDictionary(uint32_t Key, int Code)
610 {
611     int key = ((Key >> LZ_BITS) ^ Key) & 0x1FFF;
612     while ((dictionary_[key] >> LZ_BITS) != 0xFFFFFL) {
613         key = (key + 1) & 0x1FFF;
614     }
615     dictionary_[key] = (Key << LZ_BITS) | (Code & 0x0FFF);
616 }
617 
LZWEncodeFrame(uint8_t * outputBuffer,uint16_t width,uint16_t height)618 uint32_t GifEncoder::LZWEncodeFrame(uint8_t *outputBuffer, uint16_t width, uint16_t height)
619 {
620     uint8_t *pTmp = outputBuffer;
621     uint8_t bitsPerPixel = BITS_IN_BYTE;
622     Write((const uint8_t*)&bitsPerPixel, 1);
623     LZWWriteOut(clearCode_);
624     for (int j = 0; j < height; j++) {
625         if (LZWEncode(pTmp, width)) {
626             IMAGE_LOGE("Failed to encode, aborted.");
627             return ERR_IMAGE_ENCODE_FAILED;
628         }
629         pTmp += width;
630     }
631     if (LZWWriteOut(lastCode_)) {
632         IMAGE_LOGE("Failed to write lastCode, aborted.");
633         return ERR_IMAGE_ENCODE_FAILED;
634     }
635     if (LZWWriteOut(eofCode_)) {
636         IMAGE_LOGE("Failed to write EOFCode, aborted.");
637         return ERR_IMAGE_ENCODE_FAILED;
638     }
639     if (LZWWriteOut(FLUSH_OUTPUT)) {
640         IMAGE_LOGE("Failed to write flushCode, aborted.");
641         return ERR_IMAGE_ENCODE_FAILED;
642     }
643     return SUCCESS;
644 }
645 
LZWEncode(uint8_t * buffer,int length)646 uint32_t GifEncoder::LZWEncode(uint8_t *buffer, int length)
647 {
648     int i = 0;
649     int curChar;
650     if (lastCode_ == FIRST_CODE) {
651         curChar = buffer[i++];
652     } else {
653         curChar = lastCode_;
654     }
655     while (i < length) {
656         uint8_t Pixel = buffer[i++];
657         int newChar;
658         uint32_t newKey = (((uint32_t)curChar) << BITS_IN_BYTE) + Pixel;
659         if ((newChar = IsInDictionary(newKey)) >= 0) {
660             curChar = newChar;
661             continue;
662         }
663         if (LZWWriteOut(curChar)) {
664             IMAGE_LOGE("Failed to write.");
665             return ERR_IMAGE_ENCODE_FAILED;
666         }
667         curChar = Pixel;
668         if (runningCode_ >= LZ_MAX_CODE) {
669             if (LZWWriteOut(clearCode_)) {
670                 IMAGE_LOGE("Failed to write.");
671                 return ERR_IMAGE_ENCODE_FAILED;
672             }
673             runningCode_ = eofCode_ + 1;
674             runningBits_ = BITS_IN_BYTE + 1;
675             maxCode_ = 1 << runningBits_;
676             memset_s(dictionary_, sizeof(uint32_t) * DICTIONARY_SIZE, 0xFF, sizeof(uint32_t) * DICTIONARY_SIZE);
677         } else {
678             AddToDictionary(newKey, runningCode_++);
679         }
680     }
681     lastCode_ = curChar;
682     return SUCCESS;
683 }
684 
LZWWriteOut(int Code)685 uint32_t GifEncoder::LZWWriteOut(int Code)
686 {
687     uint32_t ret = SUCCESS;
688     if (Code == FLUSH_OUTPUT) {
689         while (crntShiftState_ > 0) {
690             if (LZWBufferOutput(crntShiftDWord_ & 0xFF)) {
691                 ret = ERROR;
692             }
693             crntShiftDWord_ >>= BITS_IN_BYTE;
694             crntShiftState_ -= BITS_IN_BYTE;
695         }
696         crntShiftState_ = 0;
697         if (LZWBufferOutput(FLUSH_OUTPUT)) {
698             ret = ERROR;
699         }
700     } else {
701         crntShiftDWord_ |= ((long)Code) << crntShiftState_;
702         crntShiftState_ += runningBits_;
703         while (crntShiftState_ >= BITS_IN_BYTE) {
704             if (LZWBufferOutput(crntShiftDWord_ & 0xFF)) {
705                 ret = ERROR;
706             }
707             crntShiftDWord_ >>= BITS_IN_BYTE;
708             crntShiftState_ -= BITS_IN_BYTE;
709         }
710     }
711     if (runningCode_ >= maxCode_ && Code <= LZ_MAX_CODE) {
712         maxCode_ = 1 << ++runningBits_;
713     }
714     return ret;
715 }
716 
LZWBufferOutput(int character)717 uint32_t GifEncoder::LZWBufferOutput(int character)
718 {
719     if (character == FLUSH_OUTPUT) {
720         if (outputLZWBuffer_[0] != 0 && !Write(outputLZWBuffer_, outputLZWBuffer_[0] + 1)) {
721             return ERR_IMAGE_ENCODE_FAILED;
722         }
723         outputLZWBuffer_[0] = 0;
724         if (!Write(outputLZWBuffer_, 1)) {
725             return ERR_IMAGE_ENCODE_FAILED;
726         }
727     } else {
728         if (outputLZWBuffer_[0] == 0xFF) {
729             if (!Write(outputLZWBuffer_, outputLZWBuffer_[0] + 1)) {
730                 return ERR_IMAGE_ENCODE_FAILED;
731             }
732             outputLZWBuffer_[0] = 0;
733         }
734         outputLZWBuffer_[++outputLZWBuffer_[0]] = character;
735     }
736     return SUCCESS;
737 }
738 
Write(const uint8_t * data,size_t data_size)739 bool GifEncoder::Write(const uint8_t* data, size_t data_size)
740 {
741     return outputStream_->Write(data, data_size);
742 }
743 
744 } // namespace ImagePlugin
745 } // namespace OHOS