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