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