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