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