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