• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 "ext_encoder.h"
17 #include <algorithm>
18 #include <map>
19 
20 #include "SkBitmap.h"
21 #include "SkImageEncoder.h"
22 #ifdef IMAGE_COLORSPACE_FLAG
23 #include "color_space.h"
24 #endif
25 #if !defined(IOS_PLATFORM) && !defined(A_PLATFORM)
26 #include "astc_codec.h"
27 #endif
28 #include "ext_pixel_convert.h"
29 #include "ext_wstream.h"
30 #include "image_log.h"
31 #include "image_type_converter.h"
32 #include "image_utils.h"
33 #include "media_errors.h"
34 #include "string_ex.h"
35 #if !defined(IOS_PLATFORM) && !defined(A_PLATFORM)
36 #include "surface_buffer.h"
37 #endif
38 
39 #undef LOG_DOMAIN
40 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_PLUGIN
41 
42 #undef LOG_TAG
43 #define LOG_TAG "ExtEncoder"
44 
45 namespace OHOS {
46 namespace ImagePlugin {
47 using namespace Media;
48 
49 static const std::map<SkEncodedImageFormat, std::string> FORMAT_NAME = {
50     {SkEncodedImageFormat::kBMP, "image/bmp"},
51     {SkEncodedImageFormat::kGIF, "image/gif"},
52     {SkEncodedImageFormat::kICO, "image/ico"},
53     {SkEncodedImageFormat::kJPEG, "image/jpeg"},
54     {SkEncodedImageFormat::kPNG, "image/png"},
55     {SkEncodedImageFormat::kWBMP, "image/bmp"},
56     {SkEncodedImageFormat::kWEBP, "image/webp"},
57     {SkEncodedImageFormat::kPKM, ""},
58     {SkEncodedImageFormat::kKTX, ""},
59     {SkEncodedImageFormat::kASTC, ""},
60     {SkEncodedImageFormat::kDNG, ""},
61     {SkEncodedImageFormat::kHEIF, "image/heif"},
62 };
63 
ExtEncoder()64 ExtEncoder::ExtEncoder()
65 {
66 }
67 
~ExtEncoder()68 ExtEncoder::~ExtEncoder()
69 {
70 }
71 
StartEncode(OutputDataStream & outputStream,PlEncodeOptions & option)72 uint32_t ExtEncoder::StartEncode(OutputDataStream &outputStream, PlEncodeOptions &option)
73 {
74     output_ = &outputStream;
75     opts_ = option;
76     return SUCCESS;
77 }
78 
AddImage(Media::PixelMap & pixelMap)79 uint32_t ExtEncoder::AddImage(Media::PixelMap &pixelMap)
80 {
81     pixelmap_ = &pixelMap;
82     return SUCCESS;
83 }
84 
85 struct TmpBufferHolder {
86     std::unique_ptr<uint8_t[]> buf = nullptr;
87 };
88 
ToSkInfo(Media::PixelMap * pixelMap)89 static SkImageInfo ToSkInfo(Media::PixelMap *pixelMap)
90 {
91     ImageInfo info;
92     pixelMap->GetImageInfo(info);
93     SkColorType colorType = ImageTypeConverter::ToSkColorType(info.pixelFormat);
94     SkAlphaType alphaType = ImageTypeConverter::ToSkAlphaType(info.alphaType);
95     sk_sp<SkColorSpace> colorSpace = nullptr;
96 #ifdef IMAGE_COLORSPACE_FLAG
97     if (pixelMap->InnerGetGrColorSpacePtr() != nullptr) {
98         colorSpace = pixelMap->InnerGetGrColorSpacePtr()->ToSkColorSpace();
99     }
100 #endif
101     return SkImageInfo::Make(info.size.width, info.size.height, colorType, alphaType, colorSpace);
102 }
103 
RGBToRGBx(Media::PixelMap * pixelMap,SkImageInfo & skInfo,TmpBufferHolder & holder)104 static uint32_t RGBToRGBx(Media::PixelMap *pixelMap, SkImageInfo &skInfo, TmpBufferHolder &holder)
105 {
106     holder.buf = std::make_unique<uint8_t[]>(skInfo.computeMinByteSize());
107     ExtPixels src = {
108         static_cast<uint8_t*>(pixelMap->GetWritablePixels()),
109         pixelMap->GetCapacity(), pixelMap->GetWidth()*pixelMap->GetHeight(),
110     };
111     ExtPixels dst = {
112         holder.buf.get(), skInfo.computeMinByteSize(), skInfo.width()*skInfo.height(),
113     };
114     return ExtPixelConvert::RGBToRGBx(src, dst);
115 }
116 
BuildSkBitmap(Media::PixelMap * pixelMap,SkBitmap & bitmap,SkEncodedImageFormat format,TmpBufferHolder & holder)117 static uint32_t BuildSkBitmap(Media::PixelMap *pixelMap, SkBitmap &bitmap,
118     SkEncodedImageFormat format, TmpBufferHolder &holder)
119 {
120     uint32_t res = SUCCESS;
121     SkImageInfo skInfo = ToSkInfo(pixelMap);
122     auto pixels = pixelMap->GetWritablePixels();
123     if (format == SkEncodedImageFormat::kJPEG &&
124         skInfo.colorType() == SkColorType::kRGB_888x_SkColorType &&
125         pixelMap->GetCapacity() < skInfo.computeMinByteSize()) {
126         res = RGBToRGBx(pixelMap, skInfo, holder);
127         if (res != SUCCESS) {
128             IMAGE_LOGE("ExtEncoder::BuildSkBitmap pixel convert failed %{public}d", res);
129             return res;
130         }
131         pixels = holder.buf.get();
132         skInfo = skInfo.makeColorType(SkColorType::kRGBA_8888_SkColorType);
133     }
134 
135     uint64_t rowStride = skInfo.minRowBytes64();
136 
137 #if !defined(IOS_PLATFORM) && !defined(A_PLATFORM)
138     if (pixelMap->GetAllocatorType() == Media::AllocatorType::DMA_ALLOC) {
139         SurfaceBuffer* sbBuffer = reinterpret_cast<SurfaceBuffer*> (pixelMap->GetFd());
140         rowStride = sbBuffer->GetStride();
141     }
142 #endif
143 
144     if (!bitmap.installPixels(skInfo, pixels, rowStride)) {
145         IMAGE_LOGE("ExtEncoder::BuildSkBitmap to skbitmap failed");
146         return ERR_IMAGE_INVALID_PARAMETER;
147     }
148     return res;
149 }
150 
IsAstc(const std::string & format)151 bool IsAstc(const std::string &format)
152 {
153     return format.find("image/astc") == 0;
154 }
155 
FinalizeEncode()156 uint32_t ExtEncoder::FinalizeEncode()
157 {
158     if (pixelmap_ == nullptr || output_ == nullptr) {
159         return ERR_IMAGE_INVALID_PARAMETER;
160     }
161 #if !defined(IOS_PLATFORM) && !defined(A_PLATFORM)
162     if (IsAstc(opts_.format)) {
163         AstcCodec astcEncoder;
164         astcEncoder.SetAstcEncode(output_, opts_, pixelmap_);
165         return astcEncoder.ASTCEncode();
166     }
167 #endif
168     auto iter = std::find_if(FORMAT_NAME.begin(), FORMAT_NAME.end(),
169         [this](const std::map<SkEncodedImageFormat, std::string>::value_type item) {
170             return IsSameTextStr(item.second, opts_.format);
171     });
172     if (iter == FORMAT_NAME.end()) {
173         IMAGE_LOGE("ExtEncoder::FinalizeEncode unsupported format %{public}s", opts_.format.c_str());
174         return ERR_IMAGE_INVALID_PARAMETER;
175     }
176     auto encodeFormat = iter->first;
177     SkBitmap bitmap;
178     TmpBufferHolder holder;
179     auto errorCode = BuildSkBitmap(pixelmap_, bitmap, encodeFormat, holder);
180     if (errorCode != SUCCESS) {
181         IMAGE_LOGE("ExtEncoder::FinalizeEncode BuildSkBitmap failed");
182         return errorCode;
183     }
184     ExtWStream wStream(output_);
185     if (!SkEncodeImage(&wStream, bitmap, iter->first, opts_.quality)) {
186         IMAGE_LOGE("ExtEncoder::FinalizeEncode encode failed");
187         return ERR_IMAGE_ENCODE_FAILED;
188     }
189     return SUCCESS;
190 }
191 } // namespace ImagePlugin
192 } // namespace OHOS
193