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
16 #include "gif_decoder.h"
17
18 namespace OHOS {
19 namespace ImagePlugin {
20 using namespace OHOS::HiviewDFX;
21 using namespace MultimediaPlugin;
22 using namespace Media;
23 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "GifDecoder" };
24
25 namespace {
26 #if __BYTE_ORDER == __LITTLE_ENDIAN
27 constexpr uint8_t RGBA_R_SHIFT = 0;
28 constexpr uint8_t RGBA_G_SHIFT = 8;
29 constexpr uint8_t RGBA_B_SHIFT = 16;
30 constexpr uint8_t RGBA_A_SHIFT = 24;
31 #else
32 constexpr uint8_t RGBA_R_SHIFT = 24;
33 constexpr uint8_t RGBA_G_SHIFT = 16;
34 constexpr uint8_t RGBA_B_SHIFT = 8;
35 constexpr uint8_t RGBA_A_SHIFT = 0;
36 #endif
37 constexpr uint8_t NO_TRANSPARENT = 0xFF;
38 constexpr uint8_t DELAY_TIME_TO_MS_RATIO = 10;
39 constexpr uint8_t EXTENSION_LEN_INDEX = 0;
40 constexpr uint8_t EXTENSION_DATA_INDEX = 1;
41 constexpr int32_t INTERLACED_PASSES = 4;
42 constexpr int32_t INTERLACED_OFFSET[] = { 0, 4, 2, 1 };
43 constexpr int32_t INTERLACED_INTERVAL[] = { 8, 8, 4, 2 };
44 const std::string GIF_IMAGE_DELAY_TIME = "GIFDelayTime";
45 const std::string GIF_IMAGE_LOOP_COUNT = "GIFLoopCount";
46 constexpr int32_t NETSCAPE_EXTENSION_LENGTH = 11;
47 constexpr int32_t DELAY_TIME_LENGTH = 3;
48 constexpr int32_t DELAY_TIME_INDEX1 = 1;
49 constexpr int32_t DELAY_TIME_INDEX2 = 2;
50 constexpr int32_t DELAY_TIME_SHIFT = 8;
51 } // namespace
52
GifDecoder()53 GifDecoder::GifDecoder()
54 {}
55
~GifDecoder()56 GifDecoder::~GifDecoder()
57 {
58 Reset();
59 }
60
SetSource(InputDataStream & sourceStream)61 void GifDecoder::SetSource(InputDataStream &sourceStream)
62 {
63 Reset();
64 inputStreamPtr_ = &sourceStream;
65 }
66
67 // need decode all frame to get total number.
GetTopLevelImageNum(uint32_t & num)68 uint32_t GifDecoder::GetTopLevelImageNum(uint32_t &num)
69 {
70 if (inputStreamPtr_ == nullptr) {
71 HiLog::Error(LABEL, "[GetTopLevelImageNum]set source need firstly");
72 return ERR_IMAGE_DATA_ABNORMAL;
73 }
74 if (!inputStreamPtr_->IsStreamCompleted()) {
75 HiLog::Warn(LABEL, "[GetTopLevelImageNum]don't enough data to decode the frame number");
76 return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
77 }
78 uint32_t errorCode = CreateGifFileTypeIfNotExist();
79 if (errorCode != SUCCESS) {
80 HiLog::Error(LABEL, "[GetTopLevelImageNum]create GifFileType pointer failed %{public}u", errorCode);
81 return ERR_IMAGE_DECODE_ABNORMAL;
82 }
83 if (!isLoadAllFrame_) {
84 errorCode = UpdateGifFileType(INT_MAX);
85 if (errorCode != SUCCESS) {
86 HiLog::Error(LABEL, "[GetTopLevelImageNum]update GifFileType pointer failed %{public}u", errorCode);
87 return ERR_IMAGE_DECODE_ABNORMAL;
88 }
89 }
90 num = gifPtr_->ImageCount;
91 if (num <= 0) {
92 HiLog::Error(LABEL, "[GetTopLevelImageNum]image frame number must be larger than 0");
93 return ERR_IMAGE_DATA_ABNORMAL;
94 }
95 return SUCCESS;
96 }
97
98 // return background size but not specific frame size, cause of frame drawing on background.
GetImageSize(uint32_t index,PlSize & size)99 uint32_t GifDecoder::GetImageSize(uint32_t index, PlSize &size)
100 {
101 uint32_t errorCode = CheckIndex(index);
102 if (errorCode != SUCCESS) {
103 HiLog::Error(LABEL, "[GetImageSize]index %{public}u is invalid %{public}u", index, errorCode);
104 return errorCode;
105 }
106 const int32_t bgWidth = gifPtr_->SWidth;
107 const int32_t bgHeight = gifPtr_->SHeight;
108 if (bgWidth <= 0 || bgHeight <= 0) {
109 HiLog::Error(LABEL, "[GetImageSize]background size [%{public}d, %{public}d] is invalid", bgWidth, bgHeight);
110 return ERR_IMAGE_INVALID_PARAMETER;
111 }
112 size.width = bgWidth;
113 size.height = bgHeight;
114 return SUCCESS;
115 }
116
SetDecodeOptions(uint32_t index,const PixelDecodeOptions & opts,PlImageInfo & info)117 uint32_t GifDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info)
118 {
119 uint32_t errorCode = GetImageSize(index, info.size);
120 if (errorCode != SUCCESS) {
121 HiLog::Error(LABEL, "[SetDecodeOptions]get image size failed %{public}u", errorCode);
122 return errorCode;
123 }
124 info.alphaType = PlAlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
125 // only support RGBA pixel format for performance.
126 info.pixelFormat = PlPixelFormat::RGBA_8888;
127 return SUCCESS;
128 }
129
Decode(uint32_t index,DecodeContext & context)130 uint32_t GifDecoder::Decode(uint32_t index, DecodeContext &context)
131 {
132 PlSize imageSize;
133 uint32_t errorCode = GetImageSize(index, imageSize);
134 if (errorCode != SUCCESS) {
135 HiLog::Error(LABEL, "[Decode]index %{public}u is invalid %{public}u", index, errorCode);
136 return errorCode;
137 }
138 // compute start index and end index.
139 bool isOverlapped = false;
140 uint32_t startIndex = 0;
141 uint32_t endIndex = index;
142 int32_t acquiredIndex = static_cast<int32_t>(index);
143 if (acquiredIndex > lastPixelMapIndex_) {
144 startIndex = lastPixelMapIndex_ + 1;
145 } else if (acquiredIndex == lastPixelMapIndex_) {
146 isOverlapped = true;
147 }
148 // avoid local pixelmap buffer was reset, start with first frame again.
149 if (startIndex != 0 && localPixelMapBuffer_ == nullptr) {
150 startIndex = 0;
151 isOverlapped = false;
152 }
153 HiLog::Debug(LABEL, "[Decode]start frame: %{public}u, last frame: %{public}u,"
154 "last pixelMapIndex: %{public}d, isOverlapped: %{public}d",
155 startIndex, endIndex, lastPixelMapIndex_, isOverlapped);
156
157 if (!isOverlapped) {
158 errorCode = OverlapFrame(startIndex, endIndex);
159 if (errorCode != SUCCESS) {
160 HiLog::Error(LABEL, "[Decode]overlap frame failed %{public}u", errorCode);
161 return errorCode;
162 }
163 }
164 errorCode = RedirectOutputBuffer(context);
165 if (errorCode != SUCCESS) {
166 HiLog::Error(LABEL, "[Decode]redirect output stream failed %{public}u", errorCode);
167 return errorCode;
168 }
169 return SUCCESS;
170 }
171
PromoteIncrementalDecode(uint32_t index,ProgDecodeContext & context)172 uint32_t GifDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context)
173 {
174 uint32_t errorCode = Decode(index, context.decodeContext);
175 // get promote decode progress, in percentage: 0~100.
176 context.totalProcessProgress = (errorCode == SUCCESS ? 100 : 0);
177 return errorCode;
178 }
179
Reset()180 void GifDecoder::Reset()
181 {
182 if (gifPtr_ != nullptr) {
183 DGifCloseFile(gifPtr_, nullptr);
184 gifPtr_ = nullptr;
185 }
186 FreeLocalPixelMapBuffer(); // free local pixelmap buffer
187 inputStreamPtr_ = nullptr;
188 isLoadAllFrame_ = false;
189 lastPixelMapIndex_ = -1;
190 savedFrameIndex_ = -1;
191 bgColor_ = 0;
192 }
193
CreateGifFileTypeIfNotExist()194 uint32_t GifDecoder::CreateGifFileTypeIfNotExist()
195 {
196 if (gifPtr_ == nullptr) {
197 int32_t errorCode = Media::ERROR;
198 if (inputStreamPtr_ == nullptr) {
199 HiLog::Error(LABEL, "[CreateGifFileTypeIfNotExist]set source need firstly");
200 return ERR_IMAGE_GET_DATA_ABNORMAL;
201 }
202 // DGifOpen will create GifFileType pointer and set header and screen desc
203 gifPtr_ = DGifOpen(inputStreamPtr_, InputStreamReader, &errorCode);
204 if (gifPtr_ == nullptr) {
205 HiLog::Error(LABEL, "[CreateGifFileTypeIfNotExist]open image error, %{public}d", errorCode);
206 inputStreamPtr_->Seek(0);
207 savedFrameIndex_ = -1;
208 return ERR_IMAGE_SOURCE_DATA;
209 }
210 ParseBgColor();
211 }
212 return SUCCESS;
213 }
214
InputStreamReader(GifFileType * gif,GifByteType * bytes,int32_t size)215 int32_t GifDecoder::InputStreamReader(GifFileType *gif, GifByteType *bytes, int32_t size)
216 {
217 uint32_t dataSize = 0;
218 if (gif == nullptr) {
219 HiLog::Error(LABEL, "[InputStreamReader]GifFileType pointer is null");
220 return dataSize;
221 }
222 InputDataStream *inputStream = static_cast<InputDataStream *>(gif->UserData);
223 if (inputStream == nullptr) {
224 HiLog::Error(LABEL, "[InputStreamReader]set source need firstly");
225 return dataSize;
226 }
227 if (size <= 0) {
228 HiLog::Error(LABEL, "[InputStreamReader]callback size %{public}d is invalid", size);
229 return dataSize;
230 }
231 if (bytes == nullptr) {
232 HiLog::Error(LABEL, "[InputStreamReader]callback buffer is null");
233 return dataSize;
234 }
235 inputStream->Read(size, bytes, size, dataSize);
236 return dataSize;
237 }
238
CheckIndex(uint32_t index)239 uint32_t GifDecoder::CheckIndex(uint32_t index)
240 {
241 if (!inputStreamPtr_->IsStreamCompleted()) {
242 HiLog::Warn(LABEL, "[CheckIndex]don't enough data to decode the frame number");
243 return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
244 }
245 uint32_t errorCode = CreateGifFileTypeIfNotExist();
246 if (errorCode != SUCCESS) {
247 HiLog::Error(LABEL, "[CheckIndex]create GifFileType failed %{public}u", errorCode);
248 return errorCode;
249 }
250 int32_t updateFrameIndex = static_cast<int32_t>(index);
251 if (!isLoadAllFrame_ && updateFrameIndex > savedFrameIndex_) {
252 errorCode = UpdateGifFileType(updateFrameIndex);
253 if (errorCode != SUCCESS) {
254 HiLog::Error(LABEL, "[CheckIndex]update saved frame to index %{public}u failed", index);
255 return errorCode;
256 }
257 }
258 uint32_t frameNum = gifPtr_->ImageCount;
259 if (index >= frameNum) {
260 HiLog::Error(LABEL, "[CheckIndex]index %{public}u out of frame range %{public}u", index, frameNum);
261 return ERR_IMAGE_INVALID_PARAMETER;
262 }
263 return SUCCESS;
264 }
265
OverlapFrame(uint32_t startIndex,uint32_t endIndex)266 uint32_t GifDecoder::OverlapFrame(uint32_t startIndex, uint32_t endIndex)
267 {
268 for (uint32_t frameIndex = startIndex; frameIndex <= endIndex; frameIndex++) {
269 const SavedImage *savedImage = gifPtr_->SavedImages + frameIndex;
270 if (savedImage == nullptr) {
271 HiLog::Error(LABEL, "[OverlapFrame]image frame %{public}u data is invalid", frameIndex);
272 return ERR_IMAGE_DECODE_ABNORMAL;
273 }
274 // acquire the frame graphices control information
275 int32_t transColor = NO_TRANSPARENT_COLOR;
276 int32_t disposalMode = DISPOSAL_UNSPECIFIED;
277 GetTransparentAndDisposal(frameIndex, transColor, disposalMode);
278 HiLog::Debug(LABEL,
279 "[OverlapFrame]frameIndex = %{public}u, transColor = %{public}d, "
280 "disposalMode = %{public}d",
281 frameIndex, transColor, disposalMode);
282
283 if (frameIndex == 0 && AllocateLocalPixelMapBuffer() != SUCCESS) {
284 HiLog::Error(LABEL, "[OverlapFrame]first frame allocate local pixelmap buffer failed");
285 return ERR_IMAGE_DECODE_ABNORMAL;
286 }
287 if (localPixelMapBuffer_ == nullptr) {
288 HiLog::Error(LABEL, "[OverlapFrame]local pixelmap is null, next frame can't overlap");
289 return ERR_IMAGE_DECODE_ABNORMAL;
290 }
291 // current frame recover background
292 if (frameIndex != 0 && disposalMode == DISPOSE_BACKGROUND &&
293 DisposeBackground(frameIndex, savedImage) != SUCCESS) {
294 HiLog::Error(LABEL, "[OverlapFrame]dispose frame %{public}d background failed", frameIndex);
295 return ERR_IMAGE_DECODE_ABNORMAL;
296 }
297 if (disposalMode != DISPOSE_PREVIOUS &&
298 PaddingData(savedImage, transColor) != SUCCESS) {
299 HiLog::Error(LABEL, "[OverlapFrame]dispose frame %{public}u data color failed", frameIndex);
300 return ERR_IMAGE_DECODE_ABNORMAL;
301 }
302 }
303 lastPixelMapIndex_ = endIndex;
304 return SUCCESS;
305 }
306
DisposeBackground(uint32_t frameIndex,const SavedImage * curSavedImage)307 uint32_t GifDecoder::DisposeBackground(uint32_t frameIndex, const SavedImage *curSavedImage)
308 {
309 int32_t preTransColor = NO_TRANSPARENT_COLOR;
310 int32_t preDisposalMode = DISPOSAL_UNSPECIFIED;
311 GetTransparentAndDisposal(frameIndex - 1, preTransColor, preDisposalMode);
312 SavedImage *preSavedImage = gifPtr_->SavedImages + frameIndex - 1;
313 if (preDisposalMode == DISPOSE_BACKGROUND && IsFramePreviousCoveredCurrent(preSavedImage, curSavedImage)) {
314 return SUCCESS;
315 }
316 if (PaddingBgColor(curSavedImage) != SUCCESS) {
317 HiLog::Error(LABEL, "[DisposeBackground]padding frame %{public}u background color failed", frameIndex);
318 return ERR_IMAGE_DECODE_ABNORMAL;
319 }
320 return SUCCESS;
321 }
322
IsFramePreviousCoveredCurrent(const SavedImage * preSavedImage,const SavedImage * curSavedImage)323 bool GifDecoder::IsFramePreviousCoveredCurrent(const SavedImage *preSavedImage, const SavedImage *curSavedImage)
324 {
325 return ((preSavedImage->ImageDesc.Left <= curSavedImage->ImageDesc.Left) &&
326 (preSavedImage->ImageDesc.Left + preSavedImage->ImageDesc.Width >=
327 curSavedImage->ImageDesc.Left + curSavedImage->ImageDesc.Width) &&
328 (preSavedImage->ImageDesc.Top <= curSavedImage->ImageDesc.Top) &&
329 (preSavedImage->ImageDesc.Top + preSavedImage->ImageDesc.Height >=
330 curSavedImage->ImageDesc.Top + curSavedImage->ImageDesc.Height));
331 }
332
AllocateLocalPixelMapBuffer()333 uint32_t GifDecoder::AllocateLocalPixelMapBuffer()
334 {
335 if (localPixelMapBuffer_ == nullptr) {
336 int32_t bgWidth = gifPtr_->SWidth;
337 int32_t bgHeight = gifPtr_->SHeight;
338 uint64_t pixelMapBufferSize = static_cast<uint64_t>(bgWidth * bgHeight * sizeof(uint32_t));
339 // create local pixelmap buffer, next frame depends on the previous
340 if (pixelMapBufferSize > PIXEL_MAP_MAX_RAM_SIZE) {
341 HiLog::Error(LABEL, "[AllocateLocalPixelMapBuffer]pixelmap buffer size %{public}llu out of max size",
342 static_cast<unsigned long long>(pixelMapBufferSize));
343 return ERR_IMAGE_TOO_LARGE;
344 }
345 localPixelMapBuffer_ = reinterpret_cast<uint32_t *>(malloc(pixelMapBufferSize));
346 if (localPixelMapBuffer_ == nullptr) {
347 HiLog::Error(LABEL, "[AllocateLocalPixelMapBuffer]allocate local pixelmap buffer memory error");
348 return ERR_IMAGE_MALLOC_ABNORMAL;
349 }
350 #ifdef _WIN32
351 errno_t backRet = memset_s(localPixelMapBuffer_, bgColor_, pixelMapBufferSize);
352 if (backRet != EOK) {
353 HiLog::Error(LABEL, "[DisposeFirstPixelMap]memset local pixelmap buffer background failed", backRet);
354 FreeLocalPixelMapBuffer();
355 return ERR_IMAGE_MALLOC_ABNORMAL;
356 }
357 #else
358 if (memset_s(localPixelMapBuffer_, pixelMapBufferSize, bgColor_, pixelMapBufferSize) != EOK) {
359 HiLog::Error(LABEL, "[DisposeFirstPixelMap]memset local pixelmap buffer background failed");
360 FreeLocalPixelMapBuffer();
361 return ERR_IMAGE_MALLOC_ABNORMAL;
362 }
363 #endif
364 }
365 return SUCCESS;
366 }
367
FreeLocalPixelMapBuffer()368 void GifDecoder::FreeLocalPixelMapBuffer()
369 {
370 if (localPixelMapBuffer_ != nullptr) {
371 free(localPixelMapBuffer_);
372 localPixelMapBuffer_ = nullptr;
373 }
374 }
375
PaddingBgColor(const SavedImage * savedImage)376 uint32_t GifDecoder::PaddingBgColor(const SavedImage *savedImage)
377 {
378 int32_t bgWidth = gifPtr_->SWidth;
379 int32_t bgHeight = gifPtr_->SHeight;
380 int32_t frameLeft = savedImage->ImageDesc.Left;
381 int32_t frameTop = savedImage->ImageDesc.Top;
382 int32_t frameWidth = savedImage->ImageDesc.Width;
383 int32_t frameHeight = savedImage->ImageDesc.Height;
384 if (frameLeft + frameWidth > bgWidth) {
385 frameWidth = bgWidth - frameLeft;
386 }
387 if (frameTop + frameHeight > bgHeight) {
388 frameHeight = bgHeight - frameTop;
389 }
390 if (frameWidth < 0 || frameHeight < 0) {
391 HiLog::Error(LABEL, "[PaddingBgColor]frameWidth || frameHeight is abnormal,"
392 "bgWidth:%{public}d, bgHeight:%{public}d, "
393 "frameTop:%{public}d, frameLeft:%{public}d",
394 bgWidth, bgHeight, frameTop, frameLeft);
395 return ERR_IMAGE_DECODE_ABNORMAL;
396 }
397 uint32_t *dstPixelMapBuffer = localPixelMapBuffer_ + frameTop * bgWidth + frameLeft;
398 uint32_t lineBufferSize = frameWidth * sizeof(uint32_t);
399 for (int32_t row = 0; row < frameHeight; row++) {
400 #ifdef _WIN32
401 errno_t backRet = memset_s(dstPixelMapBuffer, bgColor_, lineBufferSize);
402 if (backRet != EOK) {
403 HiLog::Error(LABEL, "[PaddingBgColor]memset local pixelmap buffer failed", backRet);
404 return ERR_IMAGE_MALLOC_ABNORMAL;
405 }
406 #else
407 if (memset_s(dstPixelMapBuffer, lineBufferSize, bgColor_, lineBufferSize) != EOK) {
408 HiLog::Error(LABEL, "[PaddingBgColor]memset local pixelmap buffer failed");
409 return ERR_IMAGE_MALLOC_ABNORMAL;
410 }
411 #endif
412 dstPixelMapBuffer += bgWidth;
413 }
414 return SUCCESS;
415 }
416
PaddingData(const SavedImage * savedImage,int32_t transparentColor)417 uint32_t GifDecoder::PaddingData(const SavedImage *savedImage, int32_t transparentColor)
418 {
419 const ColorMapObject *colorMap = gifPtr_->SColorMap;
420 if (savedImage->ImageDesc.ColorMap != nullptr) {
421 colorMap = savedImage->ImageDesc.ColorMap; // local color map
422 }
423 if (colorMap == nullptr) {
424 HiLog::Error(LABEL, "[PaddingData]color map is null");
425 return ERR_IMAGE_DECODE_ABNORMAL;
426 }
427 int32_t colorCount = colorMap->ColorCount;
428 int32_t bitsPerPixel = colorMap->BitsPerPixel;
429 if ((bitsPerPixel < 0) || (colorCount != (1 << static_cast<uint32_t>(bitsPerPixel)))) {
430 HiLog::Error(LABEL, "[PaddingData]colormap is invalid, bitsPerPixel: %{public}d, colorCount: %{public}d",
431 bitsPerPixel, colorCount);
432 return ERR_IMAGE_DECODE_ABNORMAL;
433 }
434
435 int32_t bgWidth = gifPtr_->SWidth;
436 int32_t bgHeight = gifPtr_->SHeight;
437 int32_t frameLeft = savedImage->ImageDesc.Left;
438 int32_t frameTop = savedImage->ImageDesc.Top;
439 int32_t frameWidth = savedImage->ImageDesc.Width;
440 int32_t frameHeight = savedImage->ImageDesc.Height;
441 if (frameLeft + frameWidth > bgWidth) {
442 frameWidth = bgWidth - frameLeft;
443 }
444 if (frameTop + frameHeight > bgHeight) {
445 frameHeight = bgHeight - frameTop;
446 }
447 const GifByteType *srcFrame = savedImage->RasterBits;
448 uint32_t *dstPixelMapBuffer = localPixelMapBuffer_ + frameTop * bgWidth + frameLeft;
449 for (int32_t row = 0; row < frameHeight; row++) {
450 CopyLine(srcFrame, dstPixelMapBuffer, frameWidth, transparentColor, colorMap);
451 srcFrame += savedImage->ImageDesc.Width;
452 dstPixelMapBuffer += bgWidth;
453 }
454 return SUCCESS;
455 }
456
CopyLine(const GifByteType * srcFrame,uint32_t * dstPixelMapBuffer,int32_t frameWidth,int32_t transparentColor,const ColorMapObject * colorMap)457 void GifDecoder::CopyLine(const GifByteType *srcFrame, uint32_t *dstPixelMapBuffer, int32_t frameWidth,
458 int32_t transparentColor, const ColorMapObject *colorMap)
459 {
460 for (int32_t col = 0; col < frameWidth; col++, srcFrame++, dstPixelMapBuffer++) {
461 if ((*srcFrame != transparentColor) && (*srcFrame < colorMap->ColorCount)) {
462 const GifColorType &colorType = colorMap->Colors[*srcFrame];
463 *dstPixelMapBuffer = GetPixelColor(colorType.Red, colorType.Green, colorType.Blue, NO_TRANSPARENT);
464 }
465 }
466 }
467
GetTransparentAndDisposal(uint32_t index,int32_t & transparentColor,int32_t & disposalMode)468 void GifDecoder::GetTransparentAndDisposal(uint32_t index, int32_t &transparentColor, int32_t &disposalMode)
469 {
470 GraphicsControlBlock graphicsControlBlock = GetGraphicsControlBlock(index);
471 transparentColor = graphicsControlBlock.TransparentColor;
472 disposalMode = graphicsControlBlock.DisposalMode;
473 }
474
GetGraphicsControlBlock(uint32_t index)475 GraphicsControlBlock GifDecoder::GetGraphicsControlBlock(uint32_t index)
476 {
477 GraphicsControlBlock graphicsControlBlock = { DISPOSAL_UNSPECIFIED, false, 0, NO_TRANSPARENT_COLOR };
478 DGifSavedExtensionToGCB(gifPtr_, index, &graphicsControlBlock);
479 return graphicsControlBlock;
480 }
481
GetPixelColor(uint32_t red,uint32_t green,uint32_t blue,uint32_t alpha)482 uint32_t GifDecoder::GetPixelColor(uint32_t red, uint32_t green, uint32_t blue, uint32_t alpha)
483 {
484 return (red << RGBA_R_SHIFT) | (green << RGBA_G_SHIFT) | (blue << RGBA_B_SHIFT) | (alpha << RGBA_A_SHIFT);
485 }
486
ParseBgColor()487 void GifDecoder::ParseBgColor()
488 {
489 const int32_t bgColorIndex = gifPtr_->SBackGroundColor;
490 if (bgColorIndex < 0) {
491 HiLog::Warn(LABEL, "[ParseBgColor]bgColor index %{public}d is invalid, use default bgColor", bgColorIndex);
492 return;
493 }
494 const ColorMapObject *bgColorMap = gifPtr_->SColorMap;
495 if ((bgColorMap != nullptr) && (bgColorIndex < bgColorMap->ColorCount)) {
496 const GifColorType bgColorType = bgColorMap->Colors[bgColorIndex];
497 bgColor_ = GetPixelColor(bgColorType.Red, bgColorType.Green, bgColorType.Blue, NO_TRANSPARENT);
498 }
499 }
500
RedirectOutputBuffer(DecodeContext & context)501 uint32_t GifDecoder::RedirectOutputBuffer(DecodeContext &context)
502 {
503 if (localPixelMapBuffer_ == nullptr) {
504 HiLog::Error(LABEL, "[RedirectOutputBuffer]local pixelmap buffer is null, redirect failed");
505 return ERR_IMAGE_DECODE_ABNORMAL;
506 }
507 int32_t bgWidth = gifPtr_->SWidth;
508 int32_t bgHeight = gifPtr_->SHeight;
509 uint64_t imageBufferSize = static_cast<uint64_t>(bgWidth * bgHeight * sizeof(uint32_t));
510
511 if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) {
512 if (context.pixelsBuffer.buffer == nullptr) {
513 #if !defined(_WIN32) && !defined(_APPLE)
514 int fd = AshmemCreate("GIF RawData", imageBufferSize);
515 if (fd < 0) {
516 return ERR_SHAMEM_DATA_ABNORMAL;
517 }
518 int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE);
519 if (result < 0) {
520 ::close(fd);
521 return ERR_SHAMEM_DATA_ABNORMAL;
522 }
523 void* ptr = ::mmap(nullptr, imageBufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
524 if (ptr == MAP_FAILED) {
525 ::close(fd);
526 return ERR_SHAMEM_DATA_ABNORMAL;
527 }
528 context.pixelsBuffer.buffer = ptr;
529 void *fdBuffer = new int32_t();
530 if (fdBuffer == nullptr) {
531 HiLog::Error(LABEL, "new fdBuffer fail");
532 ::munmap(ptr, imageBufferSize);
533 ::close(fd);
534 context.pixelsBuffer.buffer = nullptr;
535 return ERR_SHAMEM_DATA_ABNORMAL;
536 }
537 *static_cast<int32_t *>(fdBuffer) = fd;
538 context.pixelsBuffer.context = fdBuffer;
539 context.pixelsBuffer.bufferSize = imageBufferSize;
540 context.pixelsBuffer.dataSize = imageBufferSize;
541 context.allocatorType = AllocatorType::SHARE_MEM_ALLOC;
542 context.freeFunc = nullptr;
543 #endif
544 }
545 } else {
546 bool isPluginAllocateMemory = false;
547 if (context.pixelsBuffer.buffer == nullptr) {
548 // outer manage the buffer.
549 void *outputBuffer = malloc(imageBufferSize);
550 if (outputBuffer == nullptr) {
551 HiLog::Error(LABEL, "[RedirectOutputBuffer]alloc output buffer size %{public}llu failed",
552 static_cast<unsigned long long>(imageBufferSize));
553 return ERR_IMAGE_MALLOC_ABNORMAL;
554 }
555 context.pixelsBuffer.buffer = outputBuffer;
556 context.pixelsBuffer.bufferSize = imageBufferSize;
557 isPluginAllocateMemory = true;
558 }
559 if (memcpy_s(context.pixelsBuffer.buffer, context.pixelsBuffer.bufferSize,
560 localPixelMapBuffer_, imageBufferSize) != 0) {
561 HiLog::Error(LABEL, "[RedirectOutputBuffer]memory copy size %{public}llu failed",
562 static_cast<unsigned long long>(imageBufferSize));
563 if (isPluginAllocateMemory) {
564 context.pixelsBuffer.bufferSize = 0;
565 free(context.pixelsBuffer.buffer);
566 context.pixelsBuffer.buffer = nullptr;
567 }
568 return ERR_IMAGE_DECODE_ABNORMAL;
569 }
570 context.pixelsBuffer.dataSize = imageBufferSize;
571 context.allocatorType = AllocatorType::HEAP_ALLOC;
572 }
573 return SUCCESS;
574 }
575
GetImageDelayTime(uint32_t index,int32_t & value)576 uint32_t GifDecoder::GetImageDelayTime(uint32_t index, int32_t &value)
577 {
578 uint32_t errorCode = CheckIndex(index);
579 if (errorCode != SUCCESS) {
580 HiLog::Error(LABEL, "[GetImageDelayTime]index %{public}u is invalid", index);
581 return errorCode;
582 }
583
584 GraphicsControlBlock graphicsControlBlock = GetGraphicsControlBlock(index);
585 // 0.01 sec in standard, update to ms
586 value = graphicsControlBlock.DelayTime * DELAY_TIME_TO_MS_RATIO;
587 return SUCCESS;
588 }
589
GetImageLoopCount(uint32_t index,int32_t & value)590 uint32_t GifDecoder::GetImageLoopCount(uint32_t index, int32_t &value)
591 {
592 for (int i = 0; i < gifPtr_->SavedImages[index].ExtensionBlockCount; i++) {
593 ExtensionBlock *ep = &gifPtr_->SavedImages[index].ExtensionBlocks[i];
594 if (ep == nullptr) {
595 continue;
596 }
597 if ((ep->Function == APPLICATION_EXT_FUNC_CODE) && (ep->ByteCount >= NETSCAPE_EXTENSION_LENGTH) &&
598 (memcmp(ep->Bytes, "NETSCAPE2.0", NETSCAPE_EXTENSION_LENGTH) == 0)) {
599 ep++;
600 if (ep->ByteCount >= DELAY_TIME_LENGTH) {
601 unsigned char *params = ep->Bytes;
602 value = params[DELAY_TIME_INDEX1] | (params[DELAY_TIME_INDEX2] << DELAY_TIME_SHIFT);
603 return SUCCESS;
604 }
605 }
606 }
607 return ERR_IMAGE_PROPERTY_NOT_EXIST;
608 }
609
GetImagePropertyInt(uint32_t index,const std::string & key,int32_t & value)610 uint32_t GifDecoder::GetImagePropertyInt(uint32_t index, const std::string &key, int32_t &value)
611 {
612 HiLog::Error(LABEL, "[GetImagePropertyInt] enter gif plugin, key:%{public}s", key.c_str());
613 uint32_t errorCode = CheckIndex(0);
614 if (errorCode != SUCCESS) {
615 HiLog::Error(LABEL, "[GetImagePropertyInt]index %{public}u is invalid", index);
616 return errorCode;
617 }
618
619 if (key == GIF_IMAGE_DELAY_TIME) {
620 errorCode = GetImageDelayTime(index, value);
621 } else if (key == GIF_IMAGE_LOOP_COUNT) {
622 errorCode = GetImageLoopCount(0, value);
623 } else {
624 HiLog::Error(LABEL, "[GetImagePropertyInt]key(%{public}s) not supported", key.c_str());
625 return ERR_IMAGE_INVALID_PARAMETER;
626 }
627
628 return errorCode;
629 }
630
ParseFrameDetail()631 uint32_t GifDecoder::ParseFrameDetail()
632 {
633 if (DGifGetImageDesc(gifPtr_) == GIF_ERROR) {
634 HiLog::Error(LABEL, "[ParseFrameDetail]parse frame desc to gif pointer failed %{public}d", gifPtr_->Error);
635 return ERR_IMAGE_DECODE_ABNORMAL;
636 }
637 // DGifGetImageDesc use malloc or reallocarray allocate savedImages memory and increase imageCount.
638 // If error, we don't free the memory, next time decode will retry the allocated memory.
639 // The total memory free will be called DGifCloseFile.
640 int32_t frameIndex = gifPtr_->ImageCount - 1;
641 SavedImage *saveImagePtr = &gifPtr_->SavedImages[frameIndex];
642 int32_t imageWidth = saveImagePtr->ImageDesc.Width;
643 int32_t imageHeight = saveImagePtr->ImageDesc.Height;
644 uint64_t imageSize = static_cast<uint64_t>(imageWidth * imageHeight);
645 if (imageWidth <= 0 || imageHeight <= 0 || imageSize > SIZE_MAX) {
646 HiLog::Error(LABEL, "[ParseFrameDetail]check frame size[%{public}d, %{public}d] failed", imageWidth,
647 imageHeight);
648 // if error, imageCount go back and next time DGifGetImageDesc will retry.
649 gifPtr_->ImageCount--;
650 return ERR_IMAGE_DECODE_ABNORMAL;
651 }
652 // set savedImage extension
653 if (gifPtr_->ExtensionBlocks != nullptr) {
654 saveImagePtr->ExtensionBlocks = gifPtr_->ExtensionBlocks;
655 saveImagePtr->ExtensionBlockCount = gifPtr_->ExtensionBlockCount;
656 gifPtr_->ExtensionBlocks = nullptr;
657 gifPtr_->ExtensionBlockCount = 0;
658 }
659 // set savedImage rasterBits
660 if (SetSavedImageRasterBits(saveImagePtr, frameIndex, imageSize, imageWidth, imageHeight) != SUCCESS) {
661 HiLog::Error(LABEL, "[ParseFrameDetail] set saved image data failed");
662 GifFreeExtensions(&saveImagePtr->ExtensionBlockCount, &saveImagePtr->ExtensionBlocks);
663 return ERR_IMAGE_DECODE_ABNORMAL;
664 }
665 return SUCCESS;
666 }
667
SetSavedImageRasterBits(SavedImage * saveImagePtr,int32_t frameIndex,uint64_t imageSize,int32_t imageWidth,int32_t imageHeight)668 uint32_t GifDecoder::SetSavedImageRasterBits(SavedImage *saveImagePtr, int32_t frameIndex, uint64_t imageSize,
669 int32_t imageWidth, int32_t imageHeight)
670 {
671 if (saveImagePtr->RasterBits == nullptr) {
672 if (imageSize == 0 || imageSize > PIXEL_MAP_MAX_RAM_SIZE) {
673 HiLog::Error(LABEL, "[SetSavedImageData]malloc frame %{public}d failed for invalid imagesize", frameIndex);
674 return ERR_IMAGE_MALLOC_ABNORMAL;
675 }
676 saveImagePtr->RasterBits = static_cast<GifPixelType *>(malloc(imageSize * sizeof(GifPixelType)));
677 if (saveImagePtr->RasterBits == nullptr) {
678 HiLog::Error(LABEL, "[SetSavedImageData]malloc frame %{public}d rasterBits failed", frameIndex);
679 return ERR_IMAGE_MALLOC_ABNORMAL;
680 }
681 }
682 // if error next time will retry the rasterBits and the pointer free will be called DGifCloseFile.
683 if (saveImagePtr->ImageDesc.Interlace) {
684 for (int32_t i = 0; i < INTERLACED_PASSES; i++) {
685 for (int32_t j = INTERLACED_OFFSET[i]; j < imageHeight; j += INTERLACED_INTERVAL[i]) {
686 if (DGifGetLine(gifPtr_, saveImagePtr->RasterBits + j * imageWidth, imageWidth) == GIF_ERROR) {
687 HiLog::Error(LABEL, "[SetSavedImageData]interlace set frame %{public}d bits failed %{public}d",
688 frameIndex, gifPtr_->Error);
689 return ERR_IMAGE_DECODE_ABNORMAL;
690 }
691 }
692 }
693 } else {
694 if (DGifGetLine(gifPtr_, saveImagePtr->RasterBits, imageSize) == GIF_ERROR) {
695 HiLog::Error(LABEL, "[SetSavedImageData]normal set frame %{public}d bits failed %{public}d", frameIndex,
696 gifPtr_->Error);
697 return ERR_IMAGE_DECODE_ABNORMAL;
698 }
699 }
700 return SUCCESS;
701 }
702
ParseFrameExtension()703 uint32_t GifDecoder::ParseFrameExtension()
704 {
705 GifByteType *extData = nullptr;
706 int32_t extFunc = 0;
707 if (DGifGetExtension(gifPtr_, &extFunc, &extData) == GIF_ERROR) {
708 HiLog::Error(LABEL, "[ParseFrameExtension]get extension failed %{public}d", gifPtr_->Error);
709 return ERR_IMAGE_DECODE_ABNORMAL;
710 }
711 if (extData == nullptr) {
712 return SUCCESS;
713 }
714
715 HiLog::Debug(LABEL, "[ParseFrameExtension] get extension:0x%{public}x", extFunc);
716
717 if (GifAddExtensionBlock(&gifPtr_->ExtensionBlockCount, &gifPtr_->ExtensionBlocks, extFunc,
718 extData[EXTENSION_LEN_INDEX], &extData[EXTENSION_DATA_INDEX]) == GIF_ERROR) {
719 HiLog::Error(LABEL, "[ParseFrameExtension]set extension to gif pointer failed");
720 // GifAddExtensionBlock will allocate memory, if error, free extension ready to retry
721 GifFreeExtensions(&gifPtr_->ExtensionBlockCount, &gifPtr_->ExtensionBlocks);
722 return ERR_IMAGE_DECODE_ABNORMAL;
723 }
724 while (true) {
725 if (DGifGetExtensionNext(gifPtr_, &extData) == GIF_ERROR) {
726 HiLog::Error(LABEL, "[ParseFrameExtension]get next extension failed %{public}d", gifPtr_->Error);
727 return ERR_IMAGE_DECODE_ABNORMAL;
728 }
729 if (extData == nullptr) {
730 return SUCCESS;
731 }
732
733 if (GifAddExtensionBlock(&gifPtr_->ExtensionBlockCount, &gifPtr_->ExtensionBlocks, CONTINUE_EXT_FUNC_CODE,
734 extData[EXTENSION_LEN_INDEX], &extData[EXTENSION_DATA_INDEX]) == GIF_ERROR) {
735 HiLog::Error(LABEL, "[ParseFrameExtension]set next extension to gif pointer failed");
736 GifFreeExtensions(&gifPtr_->ExtensionBlockCount, &gifPtr_->ExtensionBlocks);
737 return ERR_IMAGE_DECODE_ABNORMAL;
738 }
739 }
740 return SUCCESS;
741 }
742
UpdateGifFileType(int32_t updateFrameIndex)743 uint32_t GifDecoder::UpdateGifFileType(int32_t updateFrameIndex)
744 {
745 HiLog::Debug(LABEL, "[UpdateGifFileType]update %{public}d to %{public}d", savedFrameIndex_, updateFrameIndex);
746 uint32_t startPosition = inputStreamPtr_->Tell();
747 GifRecordType recordType;
748 gifPtr_->ExtensionBlocks = nullptr;
749 gifPtr_->ExtensionBlockCount = 0;
750 do {
751 if (DGifGetRecordType(gifPtr_, &recordType) == GIF_ERROR) {
752 HiLog::Error(LABEL, "[UpdateGifFileType]parse file record type failed %{public}d", gifPtr_->Error);
753 inputStreamPtr_->Seek(startPosition);
754 return ERR_IMAGE_DECODE_ABNORMAL;
755 }
756
757 switch (recordType) {
758 case EXTENSION_RECORD_TYPE:
759 if (ParseFrameExtension() != SUCCESS) {
760 HiLog::Error(LABEL, "[UpdateGifFileType]parse frame extension failed");
761 inputStreamPtr_->Seek(startPosition);
762 return ERR_IMAGE_DECODE_ABNORMAL;
763 }
764 break;
765 case IMAGE_DESC_RECORD_TYPE:
766 if (ParseFrameDetail() != SUCCESS) {
767 HiLog::Error(LABEL, "[UpdateGifFileType]parse frame detail failed");
768 inputStreamPtr_->Seek(startPosition);
769 return ERR_IMAGE_DECODE_ABNORMAL;
770 }
771 savedFrameIndex_ = gifPtr_->ImageCount - 1;
772 startPosition = inputStreamPtr_->Tell();
773 break;
774 case TERMINATE_RECORD_TYPE:
775 HiLog::Debug(LABEL, "[UpdateGifFileType]parse gif completed");
776 isLoadAllFrame_ = true;
777 break;
778 default:
779 break;
780 }
781
782 if (isLoadAllFrame_ || savedFrameIndex_ == updateFrameIndex) {
783 break;
784 }
785 } while (recordType != TERMINATE_RECORD_TYPE);
786
787 if (gifPtr_->ImageCount <= 0) {
788 gifPtr_->Error = D_GIF_ERR_NO_IMAG_DSCR;
789 HiLog::Error(LABEL, "[UpdateGifFileType]has no frame in gif block");
790 return ERR_IMAGE_DECODE_ABNORMAL;
791 }
792 return SUCCESS;
793 }
794 } // namespace ImagePlugin
795 } // namespace OHOS
796