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