• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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