• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 DISPOSAL_METHOD_SHIFT_BIT = 2;
53 const uint32_t DEFAULT_DELAY_TIME = 100;
54 const uint32_t DEFAULT_DISPOSAL_TYPE = 1;
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 COMMON_ERR_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 < static_cast<int>(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 = 0x01;
245     gce.packedFields |= (((index < static_cast<int>(encodeOpts_.disposalTypes.size()) ?
246         encodeOpts_.disposalTypes[index] : DEFAULT_DISPOSAL_TYPE) & 0x07) << DISPOSAL_METHOD_SHIFT_BIT);
247     gce.delayTime = index < static_cast<int>(encodeOpts_.delayTimes.size()) ?
248         encodeOpts_.delayTimes[index] : DEFAULT_DELAY_TIME;
249     gce.transparentColorIndex = 0xFF;
250     gce.blockTerminator = 0x00;
251     if (!Write((const uint8_t*)&gce, sizeof(GraphicControlExtension))) {
252         IMAGE_LOGE("Write to buffer error.");
253         return ERR_IMAGE_ENCODE_FAILED;
254     }
255 
256     ImageDescriptor id;
257     memset_s(&id, sizeof(ImageDescriptor), 0, sizeof(ImageDescriptor));
258     id.imageSeparator = IMAGE_SEPARATOR;
259     id.imageLeftPosition = 0x0000;
260     id.imageTopPosition = 0x0000;
261     id.imageWidth = static_cast<uint16_t>(pixelMaps_[index]->GetWidth());
262     id.imageHeight = static_cast<uint16_t>(pixelMaps_[index]->GetHeight());
263     id.packedFields = 0x87;
264     if (!Write((const uint8_t*)&id, sizeof(ImageDescriptor))) {
265         IMAGE_LOGE("Write to buffer error.");
266         return ERR_IMAGE_ENCODE_FAILED;
267     }
268 
269     return SUCCESS;
270 }
271 
processFrame(int index)272 uint32_t GifEncoder::processFrame(int index)
273 {
274     ColorType *colorMap = (ColorType *)malloc(sizeof(ColorType) * COLOR_MAP_SIZE);
275     if (colorMap == NULL) {
276         IMAGE_LOGE("Failed to allocate memory.");
277         return ERR_IMAGE_ENCODE_FAILED;
278     }
279     uint16_t width = static_cast<uint16_t>(pixelMaps_[index]->GetWidth());
280     uint16_t height = static_cast<uint16_t>(pixelMaps_[index]->GetHeight());
281     uint64_t frameSize = width * height;
282     uint8_t *colorBuffer = (uint8_t *)malloc(frameSize);
283     if (colorBuffer == NULL) {
284         IMAGE_LOGE("Failed to allocate memory.");
285         free(colorMap);
286         return ERR_IMAGE_ENCODE_FAILED;
287     }
288     if (colorQuantize(index, width, height, colorBuffer, colorMap)) {
289         IMAGE_LOGE("Failed to quantize color.");
290         free(colorBuffer);
291         free(colorMap);
292         return ERR_IMAGE_ENCODE_FAILED;
293     }
294     for (int j = 0; j < COLOR_MAP_SIZE; j++) {
295         Write(&(colorMap[j].red), 1);
296         Write(&(colorMap[j].green), 1);
297         Write(&(colorMap[j].blue), 1);
298     }
299 
300     if (LZWEncodeFrame(colorBuffer, width, height)) {
301         IMAGE_LOGE("Failed to encode frame.");
302         free(colorBuffer);
303         free(colorMap);
304         return ERR_IMAGE_ENCODE_FAILED;
305     }
306 
307     free(colorBuffer);
308     free(colorMap);
309 
310     return SUCCESS;
311 }
312 
colorQuantize(int index,uint16_t width,uint16_t height,uint8_t * outputBuffer,ColorType * outputColorMap)313 uint32_t GifEncoder::colorQuantize(int index, uint16_t width, uint16_t height,
314                                    uint8_t *outputBuffer, ColorType *outputColorMap)
315 {
316     uint8_t *redBuffer = NULL;
317     uint8_t *greenBuffer = NULL;
318     uint8_t *blueBuffer = NULL;
319     uint8_t *alphaBuffer = NULL;
320     uint64_t frameSize = width * height;
321     redBuffer = (uint8_t *)malloc(frameSize);
322     greenBuffer = (uint8_t *)malloc(frameSize);
323     blueBuffer = (uint8_t *)malloc(frameSize);
324     alphaBuffer = (uint8_t *)malloc(frameSize);
325     if (redBuffer == NULL || greenBuffer == NULL || blueBuffer == NULL || alphaBuffer == NULL) {
326         free(redBuffer);
327         free(greenBuffer);
328         free(blueBuffer);
329         free(alphaBuffer);
330         IMAGE_LOGE("Failed to allocate memory.");
331         return ERR_IMAGE_ENCODE_FAILED;
332     }
333 
334     if (separateRGBA(index, width, height, redBuffer, greenBuffer, blueBuffer, alphaBuffer)) {
335         IMAGE_LOGE("Failed to separate RGB, aborted.");
336         free(redBuffer);
337         free(greenBuffer);
338         free(blueBuffer);
339         free(alphaBuffer);
340         return ERR_IMAGE_ENCODE_FAILED;
341     }
342 
343     if (doColorQuantize(width, height, redBuffer, greenBuffer, blueBuffer, alphaBuffer, outputBuffer, outputColorMap)) {
344         IMAGE_LOGE("Failed to quantize buffer, aborted.");
345         free(redBuffer);
346         free(greenBuffer);
347         free(blueBuffer);
348         free(alphaBuffer);
349         return ERR_IMAGE_ENCODE_FAILED;
350     }
351 
352     free(redBuffer);
353     free(greenBuffer);
354     free(blueBuffer);
355     free(alphaBuffer);
356     return SUCCESS;
357 }
358 
separateRGBA(int index,uint16_t width,uint16_t height,uint8_t * redBuffer,uint8_t * greenBuffer,uint8_t * blueBuffer,uint8_t * alphaBuffer)359 uint32_t GifEncoder::separateRGBA(int index, uint16_t width, uint16_t height,
360                                   uint8_t *redBuffer, uint8_t *greenBuffer, uint8_t *blueBuffer, uint8_t *alphaBuffer)
361 {
362     for (int y = 0; y < height; y++) {
363         for (int x = 0; x < width; x++) {
364             uint32_t pixelColor;
365             if (!pixelMaps_[index]->GetARGB32Color(x, y, pixelColor)) {
366                 IMAGE_LOGE("Failed to get rgb value.");
367                 return ERR_IMAGE_ENCODE_FAILED;
368             }
369             redBuffer[y * width + x] = pixelMaps_[index]->GetARGB32ColorR(pixelColor);
370             greenBuffer[y * width + x] = pixelMaps_[index]->GetARGB32ColorG(pixelColor);
371             blueBuffer[y * width + x] = pixelMaps_[index]->GetARGB32ColorB(pixelColor);
372             alphaBuffer[y * width + x] = pixelMaps_[index]->GetARGB32ColorA(pixelColor);
373         }
374     }
375 
376     return SUCCESS;
377 }
378 
InitColorCube(ColorCoordinate * colorCoordinate,uint16_t width,uint16_t height,ColorInput * colorInput)379 void InitColorCube(ColorCoordinate *colorCoordinate, uint16_t width, uint16_t height,
380                    ColorInput *colorInput)
381 {
382     for (int i = 0; i < COLOR_ARRAY_SIZE; i++) {
383         colorCoordinate[i].rgb[R_IN_RGB] = (static_cast<uint32_t>(i) >> RED_COORDINATE) & 0x1F;
384         colorCoordinate[i].rgb[G_IN_RGB] = (static_cast<uint32_t>(i) >> GREEN_COORDINATE) & 0x1F;
385         colorCoordinate[i].rgb[B_IN_RGB] = (static_cast<uint32_t>(i) >> BLUE_COORDINATE) & 0x1F;
386         colorCoordinate[i].pixelNum = 0;
387     }
388     int imageSize = static_cast<int>(width * height);
389     if (imageSize < 0) {
390         return;
391     }
392     for (int i = 0; i < imageSize; i++) {
393         uint16_t index = ((colorInput->redInput[i] >> (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) << RED_COORDINATE) +
394                  ((colorInput->greenInput[i] >> (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) << GREEN_COORDINATE) +
395                  ((colorInput->blueInput[i] >> (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) << BLUE_COORDINATE);
396         colorCoordinate[index].pixelNum++;
397     }
398 }
399 
InitColorSubdivMap(ColorSubdivMap * colorSubdivMap,int32_t colorSubdivMapSize,uint16_t width,uint16_t height)400 void InitColorSubdivMap(ColorSubdivMap* colorSubdivMap, int32_t colorSubdivMapSize, uint16_t width, uint16_t height)
401 {
402     if (colorSubdivMapSize < 0 || colorSubdivMapSize > COLOR_OF_GIF) {
403         return;
404     }
405     for (int i = 0; i < colorSubdivMapSize; i++) {
406         for (int j = 0; j < NUM_OF_RGB; j++) {
407             colorSubdivMap[i].rgbMin[j] = 0;
408             colorSubdivMap[i].rgbWidth[j] = 0xFF;
409         }
410         colorSubdivMap[i].coordinate = NULL;
411         colorSubdivMap[i].pixelNum = 0;
412         colorSubdivMap[i].colorNum = 0;
413     }
414     colorSubdivMap[0].pixelNum = ((long)width) * height;
415 }
416 
InitForQuantize(ColorCoordinate * colorCoordinate,ColorSubdivMap * colorSubdivMap)417 void InitForQuantize(ColorCoordinate *colorCoordinate, ColorSubdivMap* colorSubdivMap)
418 {
419     ColorCoordinate* coordinate = nullptr;
420     for (int i = 0; i < COLOR_ARRAY_SIZE; i++) {
421         if (colorCoordinate[i].pixelNum > 0) {
422             if (colorSubdivMap[0].colorNum == 0) {
423                 coordinate = &colorCoordinate[i];
424                 colorSubdivMap[0].coordinate = &colorCoordinate[i];
425                 colorSubdivMap[0].colorNum++;
426             } else {
427                 coordinate->next = &colorCoordinate[i];
428                 coordinate = &colorCoordinate[i];
429                 colorSubdivMap[0].colorNum++;
430             }
431         }
432     }
433     if (coordinate != nullptr) {
434         coordinate->next = NULL;
435     }
436 }
437 
buildOutputColorMap(ColorSubdivMap * colorSubdivMap,uint32_t colorSubdivMapSize,ColorType * outputColorMap)438 void buildOutputColorMap(ColorSubdivMap *colorSubdivMap, uint32_t colorSubdivMapSize, ColorType *outputColorMap)
439 {
440     for (int i = 0; i < static_cast<int>(colorSubdivMapSize); i++) {
441         if (colorSubdivMap[i].colorNum > 0) {
442             ColorCoordinate *coordinate = colorSubdivMap[i].coordinate;
443             uint64_t red = 0;
444             uint64_t green = 0;
445             uint64_t blue = 0;
446             while (coordinate) {
447                 red += coordinate->rgb[R_IN_RGB];
448                 green += coordinate->rgb[G_IN_RGB];
449                 blue += coordinate->rgb[B_IN_RGB];
450                 coordinate->newColorIndex = i;
451                 coordinate = coordinate->next;
452             }
453             outputColorMap[i].red = (red << (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) / colorSubdivMap[i].colorNum;
454             outputColorMap[i].green = (green << (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) / colorSubdivMap[i].colorNum;
455             outputColorMap[i].blue = (blue << (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) / colorSubdivMap[i].colorNum;
456         }
457     }
458 }
459 
doColorQuantize(uint16_t width,uint16_t height,const uint8_t * redInput,const uint8_t * greenInput,const uint8_t * blueInput,const uint8_t * alphaInput,uint8_t * outputBuffer,ColorType * outputColorMap)460 uint32_t GifEncoder::doColorQuantize(uint16_t width, uint16_t height,
461                                      const uint8_t *redInput, const uint8_t *greenInput,
462                                      const uint8_t *blueInput, const uint8_t *alphaInput,
463                                      uint8_t *outputBuffer, ColorType *outputColorMap)
464 {
465     uint32_t colorSubdivMapSize = 1;
466     ColorSubdivMap colorSubdivMap[COLOR_OF_GIF];
467     ColorCoordinate *colorCoordinate = (ColorCoordinate *)malloc(sizeof(ColorCoordinate) * COLOR_ARRAY_SIZE);
468     if (colorCoordinate == NULL) {
469         return ERR_IMAGE_ENCODE_FAILED;
470     }
471     ColorInput colorInput;
472     colorInput.redInput = redInput;
473     colorInput.greenInput = greenInput;
474     colorInput.blueInput = blueInput;
475     InitColorCube(colorCoordinate, width, height, &colorInput);
476     InitColorSubdivMap(colorSubdivMap, COLOR_OF_GIF, width, height);
477     InitForQuantize(colorCoordinate, colorSubdivMap);
478     if (BuildColorSubdivMap(colorSubdivMap, &colorSubdivMapSize)) {
479         free(colorCoordinate);
480         return ERR_IMAGE_ENCODE_FAILED;
481     }
482     if (colorSubdivMapSize < COLOR_MAP_SIZE) {
483         memset_s(outputColorMap, sizeof(ColorType) * COLOR_MAP_SIZE, 0, sizeof(ColorType) * COLOR_MAP_SIZE);
484     }
485     buildOutputColorMap(colorSubdivMap, colorSubdivMapSize, outputColorMap);
486     for (int i = 0; i < ((long)width) * height; i++) {
487         uint32_t index = ((redInput[i] >> (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) << RED_COORDINATE) +
488             ((greenInput[i] >> (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) << GREEN_COORDINATE) +
489             ((blueInput[i] >> (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) << BLUE_COORDINATE);
490         if (alphaInput[i] == 0) {
491             outputBuffer[i] = COLOR_OF_GIF - 1;
492         } else {
493             outputBuffer[i] = colorCoordinate[index].newColorIndex;
494         }
495     }
496     free(colorCoordinate);
497     return SUCCESS;
498 }
499 
SortCmpRtn(const void * inEntry1,const void * inEntry2)500 int32_t SortCmpRtn(const void *inEntry1, const void *inEntry2)
501 {
502     ColorCoordinate *entry1 = (*((ColorCoordinate **)inEntry1));
503     ColorCoordinate *entry2 = (*((ColorCoordinate **)inEntry2));
504     int32_t hash1 = 0;
505     int32_t hash2 = 0;
506     if (g_sortRGBAxis >= 0 && g_sortRGBAxis < NUM_OF_RGB) {
507         hash1 = entry1->rgb[(g_sortRGBAxis + R_IN_RGB)] * COLOR_OF_GIF * COLOR_OF_GIF +
508                     entry1->rgb[(g_sortRGBAxis + G_IN_RGB) % NUM_OF_RGB] * COLOR_OF_GIF +
509                     entry1->rgb[(g_sortRGBAxis + B_IN_RGB) % NUM_OF_RGB];
510         hash2 = entry2->rgb[(g_sortRGBAxis + R_IN_RGB)] * COLOR_OF_GIF * COLOR_OF_GIF +
511                     entry2->rgb[(g_sortRGBAxis + G_IN_RGB) % NUM_OF_RGB] * COLOR_OF_GIF +
512                     entry2->rgb[(g_sortRGBAxis + B_IN_RGB) % NUM_OF_RGB];
513     }
514     return (hash1 - hash2);
515 }
516 
517 
PrepareSort(ColorSubdivMap * colorSubdivMap,uint32_t colorSubdivMapSize)518 int32_t PrepareSort(ColorSubdivMap *colorSubdivMap, uint32_t colorSubdivMapSize)
519 {
520     int maxSize = -1;
521     int index = -1;
522     for (int i = 0; i < static_cast<int>(colorSubdivMapSize); i++) {
523         for (int j = 0; j < NUM_OF_RGB; j++) {
524             if ((static_cast<int>(colorSubdivMap[i].rgbWidth[j]) > maxSize) && (colorSubdivMap[i].colorNum > 1)) {
525                 maxSize = colorSubdivMap[i].rgbWidth[j];
526                 index = i;
527                 g_sortRGBAxis = j;
528             }
529         }
530     }
531     return index;
532 }
533 
doSort(ColorCoordinate ** sortArray,ColorSubdivMap * colorSubdivMap,uint32_t index)534 void doSort(ColorCoordinate **sortArray, ColorSubdivMap *colorSubdivMap, uint32_t index)
535 {
536     int i;
537     ColorCoordinate *colorCoordinate = nullptr;
538     for (i = 0, colorCoordinate = colorSubdivMap[index].coordinate;
539          i < static_cast<int>(colorSubdivMap[index].colorNum) && colorCoordinate != NULL;
540          i++, colorCoordinate = colorCoordinate->next) {
541         sortArray[i] = colorCoordinate;
542     }
543     qsort(sortArray, colorSubdivMap[index].colorNum, sizeof(ColorCoordinate *), SortCmpRtn);
544 }
545 
SubdivColorByPartition(ColorCoordinate * colorCoordinate,ColorSubdivMap * colorSubdivMap,uint32_t colorSubdivMapSize,int index)546 void SubdivColorByPartition(ColorCoordinate *colorCoordinate, ColorSubdivMap *colorSubdivMap,
547     uint32_t colorSubdivMapSize, int index)
548 {
549     long sum =
550         static_cast<long>(static_cast<uint64_t>(colorSubdivMap[index].pixelNum) >> 1) - colorCoordinate->pixelNum;
551     uint32_t colorNum = 1;
552     long pixelNum = colorCoordinate->pixelNum;
553     while (colorCoordinate->next != NULL && sum >= 0 && colorCoordinate->next->next != NULL) {
554         colorCoordinate = colorCoordinate->next;
555         colorNum++;
556         pixelNum += colorCoordinate->pixelNum;
557         sum -= colorCoordinate->next->pixelNum;
558     }
559     if (g_sortRGBAxis >= 0 && g_sortRGBAxis < NUM_OF_RGB) {
560         uint32_t maxColor = colorCoordinate->rgb[g_sortRGBAxis] << (BITS_IN_BYTE - BITS_PER_PRIM_COLOR);
561         uint32_t minColor = colorCoordinate->next->rgb[g_sortRGBAxis] << (BITS_IN_BYTE - BITS_PER_PRIM_COLOR);
562         colorSubdivMap[colorSubdivMapSize].coordinate = colorCoordinate->next;
563         colorCoordinate->next = NULL;
564         colorSubdivMap[colorSubdivMapSize].pixelNum = colorSubdivMap[index].pixelNum - pixelNum;
565         colorSubdivMap[index].pixelNum = pixelNum;
566         colorSubdivMap[colorSubdivMapSize].colorNum = colorSubdivMap[index].colorNum - colorNum;
567         colorSubdivMap[index].colorNum = colorNum;
568         for (int i = 0; i < NUM_OF_RGB; i++) {
569             colorSubdivMap[colorSubdivMapSize].rgbMin[i] = colorSubdivMap[index].rgbMin[i];
570             colorSubdivMap[colorSubdivMapSize].rgbWidth[i] = colorSubdivMap[index].rgbWidth[i];
571         }
572         colorSubdivMap[colorSubdivMapSize].rgbWidth[g_sortRGBAxis] =
573             colorSubdivMap[colorSubdivMapSize].rgbMin[g_sortRGBAxis] +
574             colorSubdivMap[colorSubdivMapSize].rgbWidth[g_sortRGBAxis] - minColor;
575         colorSubdivMap[colorSubdivMapSize].rgbMin[g_sortRGBAxis] = minColor;
576         colorSubdivMap[index].rgbWidth[g_sortRGBAxis] = maxColor - colorSubdivMap[index].rgbMin[g_sortRGBAxis];
577     }
578 }
579 
BuildColorSubdivMap(ColorSubdivMap * colorSubdivMap,uint32_t * colorSubdivMapSize)580 uint32_t GifEncoder::BuildColorSubdivMap(ColorSubdivMap *colorSubdivMap, uint32_t *colorSubdivMapSize)
581 {
582     int index = 0;
583     ColorCoordinate **sortArray;
584 
585     while (*colorSubdivMapSize < COLOR_MAP_SIZE - 1) {
586         index = PrepareSort(colorSubdivMap, *colorSubdivMapSize);
587         if (index < 0) {
588             return SUCCESS;
589         }
590         sortArray = (ColorCoordinate **)malloc(sizeof(ColorCoordinate *) * colorSubdivMap[index].colorNum);
591         if (sortArray == NULL) {
592             return ERR_IMAGE_ENCODE_FAILED;
593         }
594         doSort(sortArray, colorSubdivMap, static_cast<uint32_t>(index));
595 
596         for (int i = 0; i < static_cast<int>(colorSubdivMap[index].colorNum - 1); i++) {
597             sortArray[i]->next = sortArray[i + 1];
598         }
599         sortArray[colorSubdivMap[index].colorNum - 1]->next = NULL;
600         colorSubdivMap[index].coordinate = sortArray[0];
601         ColorCoordinate *colorCoordinate = sortArray[0];
602         free(sortArray);
603         SubdivColorByPartition(colorCoordinate, colorSubdivMap, *colorSubdivMapSize, index);
604         (*colorSubdivMapSize)++;
605     }
606 
607     return SUCCESS;
608 }
609 
InitDictionary()610 void GifEncoder::InitDictionary()
611 {
612     lastCode_ = FIRST_CODE;
613     clearCode_ = CLEAR_CODE;
614     eofCode_ = clearCode_ + 1;
615     runningCode_ = eofCode_ + 1;
616     runningBits_ = BITS_IN_BYTE + 1;
617     maxCode_ = 1 << runningBits_;
618     crntShiftState_ = 0;
619     crntShiftDWord_ = 0;
620     memset_s(dictionary_, sizeof(uint32_t) * DICTIONARY_SIZE, 0xFF, sizeof(uint32_t) * DICTIONARY_SIZE);
621 }
622 
IsInDictionary(uint32_t Key)623 int GifEncoder::IsInDictionary(uint32_t Key)
624 {
625     int key = ((Key >> LZ_BITS) ^ Key) & 0x1FFF;
626     uint32_t DKey;
627     while ((DKey = (dictionary_[key] >> LZ_BITS)) != 0xFFFFFL) {
628         if (Key == DKey) {
629             return (dictionary_[key] & 0x0FFF);
630         }
631         key = static_cast<uint32_t>(key + 1) & 0x1FFF;
632     }
633     return -1;
634 }
635 
AddToDictionary(uint32_t Key,int Code)636 void GifEncoder::AddToDictionary(uint32_t Key, int Code)
637 {
638     int key = ((Key >> LZ_BITS) ^ Key) & 0x1FFF;
639     while ((dictionary_[key] >> LZ_BITS) != 0xFFFFFL) {
640         key = static_cast<uint32_t>(key + 1) & 0x1FFF;
641     }
642     dictionary_[key] = (Key << LZ_BITS) | (static_cast<uint32_t>(Code) & 0x0FFF);
643 }
644 
LZWEncodeFrame(uint8_t * outputBuffer,uint16_t width,uint16_t height)645 uint32_t GifEncoder::LZWEncodeFrame(uint8_t *outputBuffer, uint16_t width, uint16_t height)
646 {
647     uint8_t *pTmp = outputBuffer;
648     uint8_t bitsPerPixel = BITS_IN_BYTE;
649     Write((const uint8_t*)&bitsPerPixel, 1);
650     LZWWriteOut(clearCode_);
651     for (int j = 0; j < height; j++) {
652         if (LZWEncode(pTmp, width)) {
653             IMAGE_LOGE("Failed to encode, aborted.");
654             return ERR_IMAGE_ENCODE_FAILED;
655         }
656         pTmp += width;
657     }
658     if (LZWWriteOut(lastCode_)) {
659         IMAGE_LOGE("Failed to write lastCode, aborted.");
660         return ERR_IMAGE_ENCODE_FAILED;
661     }
662     if (LZWWriteOut(eofCode_)) {
663         IMAGE_LOGE("Failed to write EOFCode, aborted.");
664         return ERR_IMAGE_ENCODE_FAILED;
665     }
666     if (LZWWriteOut(FLUSH_OUTPUT)) {
667         IMAGE_LOGE("Failed to write flushCode, aborted.");
668         return ERR_IMAGE_ENCODE_FAILED;
669     }
670     return SUCCESS;
671 }
672 
LZWEncode(uint8_t * buffer,int length)673 uint32_t GifEncoder::LZWEncode(uint8_t *buffer, int length)
674 {
675     int i = 0;
676     int curChar;
677     if (lastCode_ == FIRST_CODE) {
678         curChar = buffer[i++];
679     } else {
680         curChar = lastCode_;
681     }
682     while (i < length) {
683         uint8_t Pixel = buffer[i++];
684         int newChar;
685         uint32_t newKey = (((uint32_t)curChar) << BITS_IN_BYTE) + Pixel;
686         if ((newChar = IsInDictionary(newKey)) >= 0) {
687             curChar = newChar;
688             continue;
689         }
690         if (LZWWriteOut(curChar)) {
691             IMAGE_LOGE("Failed to write.");
692             return ERR_IMAGE_ENCODE_FAILED;
693         }
694         curChar = Pixel;
695         if (runningCode_ >= LZ_MAX_CODE) {
696             CHECK_ERROR_RETURN_RET_LOG(LZWWriteOut(clearCode_), ERR_IMAGE_ENCODE_FAILED, "Failed to write.");
697             runningCode_ = eofCode_ + 1;
698             runningBits_ = BITS_IN_BYTE + 1;
699             maxCode_ = 1 << runningBits_;
700             memset_s(dictionary_, sizeof(uint32_t) * DICTIONARY_SIZE, 0xFF, sizeof(uint32_t) * DICTIONARY_SIZE);
701         } else {
702             AddToDictionary(newKey, runningCode_++);
703         }
704     }
705     lastCode_ = curChar;
706     return SUCCESS;
707 }
708 
LZWWriteOut(int Code)709 uint32_t GifEncoder::LZWWriteOut(int Code)
710 {
711     uint32_t ret = SUCCESS;
712     if (Code == FLUSH_OUTPUT) {
713         while (crntShiftState_ > 0) {
714             if (LZWBufferOutput(crntShiftDWord_ & 0xFF)) {
715                 ret = ERROR;
716             }
717             crntShiftDWord_ >>= BITS_IN_BYTE;
718             crntShiftState_ -= BITS_IN_BYTE;
719         }
720         crntShiftState_ = 0;
721         if (LZWBufferOutput(FLUSH_OUTPUT)) {
722             ret = ERROR;
723         }
724     } else {
725         crntShiftDWord_ |= static_cast<uint64_t>(Code) << crntShiftState_;
726         crntShiftState_ += runningBits_;
727         while (crntShiftState_ >= BITS_IN_BYTE) {
728             if (LZWBufferOutput(crntShiftDWord_ & 0xFF)) {
729                 ret = ERROR;
730             }
731             crntShiftDWord_ >>= BITS_IN_BYTE;
732             crntShiftState_ -= BITS_IN_BYTE;
733         }
734     }
735     if (runningCode_ >= maxCode_ && Code <= LZ_MAX_CODE) {
736         maxCode_ = 1 << ++runningBits_;
737     }
738     return ret;
739 }
740 
LZWBufferOutput(int character)741 uint32_t GifEncoder::LZWBufferOutput(int character)
742 {
743     if (character == FLUSH_OUTPUT) {
744         if (outputLZWBuffer_[0] != 0 && !Write(outputLZWBuffer_, outputLZWBuffer_[0] + 1)) {
745             return ERR_IMAGE_ENCODE_FAILED;
746         }
747         outputLZWBuffer_[0] = 0;
748         if (!Write(outputLZWBuffer_, 1)) {
749             return ERR_IMAGE_ENCODE_FAILED;
750         }
751     } else {
752         if (outputLZWBuffer_[0] == 0xFF) {
753             if (!Write(outputLZWBuffer_, outputLZWBuffer_[0] + 1)) {
754                 return ERR_IMAGE_ENCODE_FAILED;
755             }
756             outputLZWBuffer_[0] = 0;
757         }
758         outputLZWBuffer_[++outputLZWBuffer_[0]] = character;
759     }
760     return SUCCESS;
761 }
762 
Write(const uint8_t * data,size_t data_size)763 bool GifEncoder::Write(const uint8_t* data, size_t data_size)
764 {
765     return outputStream_->Write(data, data_size);
766 }
767 
768 } // namespace ImagePlugin
769 } // namespace OHOS