• 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;
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     coordinate->next = NULL;
434 }
435 
buildOutputColorMap(ColorSubdivMap * colorSubdivMap,uint32_t colorSubdivMapSize,ColorType * outputColorMap)436 void buildOutputColorMap(ColorSubdivMap *colorSubdivMap, uint32_t colorSubdivMapSize, ColorType *outputColorMap)
437 {
438     for (int i = 0; i < static_cast<int>(colorSubdivMapSize); i++) {
439         if (colorSubdivMap[i].colorNum > 0) {
440             ColorCoordinate *coordinate = colorSubdivMap[i].coordinate;
441             uint64_t red = 0;
442             uint64_t green = 0;
443             uint64_t blue = 0;
444             while (coordinate) {
445                 red += coordinate->rgb[R_IN_RGB];
446                 green += coordinate->rgb[G_IN_RGB];
447                 blue += coordinate->rgb[B_IN_RGB];
448                 coordinate->newColorIndex = i;
449                 coordinate = coordinate->next;
450             }
451             outputColorMap[i].red = (red << (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) / colorSubdivMap[i].colorNum;
452             outputColorMap[i].green = (green << (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) / colorSubdivMap[i].colorNum;
453             outputColorMap[i].blue = (blue << (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) / colorSubdivMap[i].colorNum;
454         }
455     }
456 }
457 
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)458 uint32_t GifEncoder::doColorQuantize(uint16_t width, uint16_t height,
459                                      const uint8_t *redInput, const uint8_t *greenInput,
460                                      const uint8_t *blueInput, const uint8_t *alphaInput,
461                                      uint8_t *outputBuffer, ColorType *outputColorMap)
462 {
463     uint32_t colorSubdivMapSize = 1;
464     ColorSubdivMap colorSubdivMap[COLOR_OF_GIF];
465     ColorCoordinate *colorCoordinate = (ColorCoordinate *)malloc(sizeof(ColorCoordinate) * COLOR_ARRAY_SIZE);
466     if (colorCoordinate == NULL) {
467         return ERR_IMAGE_ENCODE_FAILED;
468     }
469     ColorInput colorInput;
470     colorInput.redInput = redInput;
471     colorInput.greenInput = greenInput;
472     colorInput.blueInput = blueInput;
473     InitColorCube(colorCoordinate, width, height, &colorInput);
474     InitColorSubdivMap(colorSubdivMap, COLOR_OF_GIF, width, height);
475     InitForQuantize(colorCoordinate, colorSubdivMap);
476     if (BuildColorSubdivMap(colorSubdivMap, &colorSubdivMapSize)) {
477         free(colorCoordinate);
478         return ERR_IMAGE_ENCODE_FAILED;
479     }
480     if (colorSubdivMapSize < COLOR_MAP_SIZE) {
481         memset_s(outputColorMap, sizeof(ColorType) * COLOR_MAP_SIZE, 0, sizeof(ColorType) * COLOR_MAP_SIZE);
482     }
483     buildOutputColorMap(colorSubdivMap, colorSubdivMapSize, outputColorMap);
484     for (int i = 0; i < ((long)width) * height; i++) {
485         uint32_t index = ((redInput[i] >> (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) << RED_COORDINATE) +
486             ((greenInput[i] >> (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) << GREEN_COORDINATE) +
487             ((blueInput[i] >> (BITS_IN_BYTE - BITS_PER_PRIM_COLOR)) << BLUE_COORDINATE);
488         if (alphaInput[i] == 0) {
489             outputBuffer[i] = COLOR_OF_GIF - 1;
490         } else {
491             outputBuffer[i] = colorCoordinate[index].newColorIndex;
492         }
493     }
494     free(colorCoordinate);
495     return SUCCESS;
496 }
497 
SortCmpRtn(const void * inEntry1,const void * inEntry2)498 int32_t SortCmpRtn(const void *inEntry1, const void *inEntry2)
499 {
500     ColorCoordinate *entry1 = (*((ColorCoordinate **)inEntry1));
501     ColorCoordinate *entry2 = (*((ColorCoordinate **)inEntry2));
502     int32_t hash1 = 0;
503     int32_t hash2 = 0;
504     if (g_sortRGBAxis >= 0 && g_sortRGBAxis < NUM_OF_RGB) {
505         hash1 = entry1->rgb[(g_sortRGBAxis + R_IN_RGB)] * COLOR_OF_GIF * COLOR_OF_GIF +
506                     entry1->rgb[(g_sortRGBAxis + G_IN_RGB) % NUM_OF_RGB] * COLOR_OF_GIF +
507                     entry1->rgb[(g_sortRGBAxis + B_IN_RGB) % NUM_OF_RGB];
508         hash2 = entry2->rgb[(g_sortRGBAxis + R_IN_RGB)] * COLOR_OF_GIF * COLOR_OF_GIF +
509                     entry2->rgb[(g_sortRGBAxis + G_IN_RGB) % NUM_OF_RGB] * COLOR_OF_GIF +
510                     entry2->rgb[(g_sortRGBAxis + B_IN_RGB) % NUM_OF_RGB];
511     }
512     return (hash1 - hash2);
513 }
514 
515 
PrepareSort(ColorSubdivMap * colorSubdivMap,uint32_t colorSubdivMapSize)516 int32_t PrepareSort(ColorSubdivMap *colorSubdivMap, uint32_t colorSubdivMapSize)
517 {
518     int maxSize = -1;
519     int index = -1;
520     for (int i = 0; i < static_cast<int>(colorSubdivMapSize); i++) {
521         for (int j = 0; j < NUM_OF_RGB; j++) {
522             if ((static_cast<int>(colorSubdivMap[i].rgbWidth[j]) > maxSize) && (colorSubdivMap[i].colorNum > 1)) {
523                 maxSize = colorSubdivMap[i].rgbWidth[j];
524                 index = i;
525                 g_sortRGBAxis = j;
526             }
527         }
528     }
529     return index;
530 }
531 
doSort(ColorCoordinate ** sortArray,ColorSubdivMap * colorSubdivMap,uint32_t index)532 void doSort(ColorCoordinate **sortArray, ColorSubdivMap *colorSubdivMap, uint32_t index)
533 {
534     int i;
535     ColorCoordinate *colorCoordinate = nullptr;
536     for (i = 0, colorCoordinate = colorSubdivMap[index].coordinate;
537          i < static_cast<int>(colorSubdivMap[index].colorNum) && colorCoordinate != NULL;
538          i++, colorCoordinate = colorCoordinate->next) {
539         sortArray[i] = colorCoordinate;
540     }
541     qsort(sortArray, colorSubdivMap[index].colorNum, sizeof(ColorCoordinate *), SortCmpRtn);
542 }
543 
SubdivColorByPartition(ColorCoordinate * colorCoordinate,ColorSubdivMap * colorSubdivMap,uint32_t colorSubdivMapSize,int index)544 void SubdivColorByPartition(ColorCoordinate *colorCoordinate, ColorSubdivMap *colorSubdivMap,
545     uint32_t colorSubdivMapSize, int index)
546 {
547     long sum =
548         static_cast<long>(static_cast<uint64_t>(colorSubdivMap[index].pixelNum) >> 1) - colorCoordinate->pixelNum;
549     uint32_t colorNum = 1;
550     long pixelNum = colorCoordinate->pixelNum;
551     while (colorCoordinate->next != NULL && sum >= 0 && colorCoordinate->next->next != NULL) {
552         colorCoordinate = colorCoordinate->next;
553         colorNum++;
554         pixelNum += colorCoordinate->pixelNum;
555         sum -= colorCoordinate->next->pixelNum;
556     }
557     if (g_sortRGBAxis >= 0 && g_sortRGBAxis < NUM_OF_RGB) {
558         uint32_t maxColor = colorCoordinate->rgb[g_sortRGBAxis] << (BITS_IN_BYTE - BITS_PER_PRIM_COLOR);
559         uint32_t minColor = colorCoordinate->next->rgb[g_sortRGBAxis] << (BITS_IN_BYTE - BITS_PER_PRIM_COLOR);
560         colorSubdivMap[colorSubdivMapSize].coordinate = colorCoordinate->next;
561         colorCoordinate->next = NULL;
562         colorSubdivMap[colorSubdivMapSize].pixelNum = colorSubdivMap[index].pixelNum - pixelNum;
563         colorSubdivMap[index].pixelNum = pixelNum;
564         colorSubdivMap[colorSubdivMapSize].colorNum = colorSubdivMap[index].colorNum - colorNum;
565         colorSubdivMap[index].colorNum = colorNum;
566         for (int i = 0; i < NUM_OF_RGB; i++) {
567             colorSubdivMap[colorSubdivMapSize].rgbMin[i] = colorSubdivMap[index].rgbMin[i];
568             colorSubdivMap[colorSubdivMapSize].rgbWidth[i] = colorSubdivMap[index].rgbWidth[i];
569         }
570         colorSubdivMap[colorSubdivMapSize].rgbWidth[g_sortRGBAxis] =
571             colorSubdivMap[colorSubdivMapSize].rgbMin[g_sortRGBAxis] +
572             colorSubdivMap[colorSubdivMapSize].rgbWidth[g_sortRGBAxis] - minColor;
573         colorSubdivMap[colorSubdivMapSize].rgbMin[g_sortRGBAxis] = minColor;
574         colorSubdivMap[index].rgbWidth[g_sortRGBAxis] = maxColor - colorSubdivMap[index].rgbMin[g_sortRGBAxis];
575     }
576 }
577 
BuildColorSubdivMap(ColorSubdivMap * colorSubdivMap,uint32_t * colorSubdivMapSize)578 uint32_t GifEncoder::BuildColorSubdivMap(ColorSubdivMap *colorSubdivMap, uint32_t *colorSubdivMapSize)
579 {
580     int index = 0;
581     ColorCoordinate **sortArray;
582 
583     while (*colorSubdivMapSize < COLOR_MAP_SIZE - 1) {
584         index = PrepareSort(colorSubdivMap, *colorSubdivMapSize);
585         if (index < 0) {
586             return SUCCESS;
587         }
588         sortArray = (ColorCoordinate **)malloc(sizeof(ColorCoordinate *) * colorSubdivMap[index].colorNum);
589         if (sortArray == NULL) {
590             return ERR_IMAGE_ENCODE_FAILED;
591         }
592         doSort(sortArray, colorSubdivMap, static_cast<uint32_t>(index));
593 
594         for (int i = 0; i < static_cast<int>(colorSubdivMap[index].colorNum - 1); i++) {
595             sortArray[i]->next = sortArray[i + 1];
596         }
597         sortArray[colorSubdivMap[index].colorNum - 1]->next = NULL;
598         colorSubdivMap[index].coordinate = sortArray[0];
599         ColorCoordinate *colorCoordinate = sortArray[0];
600         free(sortArray);
601         SubdivColorByPartition(colorCoordinate, colorSubdivMap, *colorSubdivMapSize, index);
602         (*colorSubdivMapSize)++;
603     }
604 
605     return SUCCESS;
606 }
607 
InitDictionary()608 void GifEncoder::InitDictionary()
609 {
610     lastCode_ = FIRST_CODE;
611     clearCode_ = CLEAR_CODE;
612     eofCode_ = clearCode_ + 1;
613     runningCode_ = eofCode_ + 1;
614     runningBits_ = BITS_IN_BYTE + 1;
615     maxCode_ = 1 << runningBits_;
616     crntShiftState_ = 0;
617     crntShiftDWord_ = 0;
618     memset_s(dictionary_, sizeof(uint32_t) * DICTIONARY_SIZE, 0xFF, sizeof(uint32_t) * DICTIONARY_SIZE);
619 }
620 
IsInDictionary(uint32_t Key)621 int GifEncoder::IsInDictionary(uint32_t Key)
622 {
623     int key = ((Key >> LZ_BITS) ^ Key) & 0x1FFF;
624     uint32_t DKey;
625     while ((DKey = (dictionary_[key] >> LZ_BITS)) != 0xFFFFFL) {
626         if (Key == DKey) {
627             return (dictionary_[key] & 0x0FFF);
628         }
629         key = static_cast<uint32_t>(key + 1) & 0x1FFF;
630     }
631     return -1;
632 }
633 
AddToDictionary(uint32_t Key,int Code)634 void GifEncoder::AddToDictionary(uint32_t Key, int Code)
635 {
636     int key = ((Key >> LZ_BITS) ^ Key) & 0x1FFF;
637     while ((dictionary_[key] >> LZ_BITS) != 0xFFFFFL) {
638         key = static_cast<uint32_t>(key + 1) & 0x1FFF;
639     }
640     dictionary_[key] = (Key << LZ_BITS) | (static_cast<uint32_t>(Code) & 0x0FFF);
641 }
642 
LZWEncodeFrame(uint8_t * outputBuffer,uint16_t width,uint16_t height)643 uint32_t GifEncoder::LZWEncodeFrame(uint8_t *outputBuffer, uint16_t width, uint16_t height)
644 {
645     uint8_t *pTmp = outputBuffer;
646     uint8_t bitsPerPixel = BITS_IN_BYTE;
647     Write((const uint8_t*)&bitsPerPixel, 1);
648     LZWWriteOut(clearCode_);
649     for (int j = 0; j < height; j++) {
650         if (LZWEncode(pTmp, width)) {
651             IMAGE_LOGE("Failed to encode, aborted.");
652             return ERR_IMAGE_ENCODE_FAILED;
653         }
654         pTmp += width;
655     }
656     if (LZWWriteOut(lastCode_)) {
657         IMAGE_LOGE("Failed to write lastCode, aborted.");
658         return ERR_IMAGE_ENCODE_FAILED;
659     }
660     if (LZWWriteOut(eofCode_)) {
661         IMAGE_LOGE("Failed to write EOFCode, aborted.");
662         return ERR_IMAGE_ENCODE_FAILED;
663     }
664     if (LZWWriteOut(FLUSH_OUTPUT)) {
665         IMAGE_LOGE("Failed to write flushCode, aborted.");
666         return ERR_IMAGE_ENCODE_FAILED;
667     }
668     return SUCCESS;
669 }
670 
LZWEncode(uint8_t * buffer,int length)671 uint32_t GifEncoder::LZWEncode(uint8_t *buffer, int length)
672 {
673     int i = 0;
674     int curChar;
675     if (lastCode_ == FIRST_CODE) {
676         curChar = buffer[i++];
677     } else {
678         curChar = lastCode_;
679     }
680     while (i < length) {
681         uint8_t Pixel = buffer[i++];
682         int newChar;
683         uint32_t newKey = (((uint32_t)curChar) << BITS_IN_BYTE) + Pixel;
684         if ((newChar = IsInDictionary(newKey)) >= 0) {
685             curChar = newChar;
686             continue;
687         }
688         if (LZWWriteOut(curChar)) {
689             IMAGE_LOGE("Failed to write.");
690             return ERR_IMAGE_ENCODE_FAILED;
691         }
692         curChar = Pixel;
693         if (runningCode_ >= LZ_MAX_CODE) {
694             if (LZWWriteOut(clearCode_)) {
695                 IMAGE_LOGE("Failed to write.");
696                 return ERR_IMAGE_ENCODE_FAILED;
697             }
698             runningCode_ = eofCode_ + 1;
699             runningBits_ = BITS_IN_BYTE + 1;
700             maxCode_ = 1 << runningBits_;
701             memset_s(dictionary_, sizeof(uint32_t) * DICTIONARY_SIZE, 0xFF, sizeof(uint32_t) * DICTIONARY_SIZE);
702         } else {
703             AddToDictionary(newKey, runningCode_++);
704         }
705     }
706     lastCode_ = curChar;
707     return SUCCESS;
708 }
709 
LZWWriteOut(int Code)710 uint32_t GifEncoder::LZWWriteOut(int Code)
711 {
712     uint32_t ret = SUCCESS;
713     if (Code == FLUSH_OUTPUT) {
714         while (crntShiftState_ > 0) {
715             if (LZWBufferOutput(crntShiftDWord_ & 0xFF)) {
716                 ret = ERROR;
717             }
718             crntShiftDWord_ >>= BITS_IN_BYTE;
719             crntShiftState_ -= BITS_IN_BYTE;
720         }
721         crntShiftState_ = 0;
722         if (LZWBufferOutput(FLUSH_OUTPUT)) {
723             ret = ERROR;
724         }
725     } else {
726         crntShiftDWord_ |= static_cast<uint64_t>(Code) << crntShiftState_;
727         crntShiftState_ += runningBits_;
728         while (crntShiftState_ >= BITS_IN_BYTE) {
729             if (LZWBufferOutput(crntShiftDWord_ & 0xFF)) {
730                 ret = ERROR;
731             }
732             crntShiftDWord_ >>= BITS_IN_BYTE;
733             crntShiftState_ -= BITS_IN_BYTE;
734         }
735     }
736     if (runningCode_ >= maxCode_ && Code <= LZ_MAX_CODE) {
737         maxCode_ = 1 << ++runningBits_;
738     }
739     return ret;
740 }
741 
LZWBufferOutput(int character)742 uint32_t GifEncoder::LZWBufferOutput(int character)
743 {
744     if (character == FLUSH_OUTPUT) {
745         if (outputLZWBuffer_[0] != 0 && !Write(outputLZWBuffer_, outputLZWBuffer_[0] + 1)) {
746             return ERR_IMAGE_ENCODE_FAILED;
747         }
748         outputLZWBuffer_[0] = 0;
749         if (!Write(outputLZWBuffer_, 1)) {
750             return ERR_IMAGE_ENCODE_FAILED;
751         }
752     } else {
753         if (outputLZWBuffer_[0] == 0xFF) {
754             if (!Write(outputLZWBuffer_, outputLZWBuffer_[0] + 1)) {
755                 return ERR_IMAGE_ENCODE_FAILED;
756             }
757             outputLZWBuffer_[0] = 0;
758         }
759         outputLZWBuffer_[++outputLZWBuffer_[0]] = character;
760     }
761     return SUCCESS;
762 }
763 
Write(const uint8_t * data,size_t data_size)764 bool GifEncoder::Write(const uint8_t* data, size_t data_size)
765 {
766     return outputStream_->Write(data, data_size);
767 }
768 
769 } // namespace ImagePlugin
770 } // namespace OHOS