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 "core/components_ng/render/adapter/skia_image.h"
17
18 #include <utility>
19
20 #include "image_painter_utils.h"
21 #include "include/core/SkGraphics.h"
22
23 #include "base/image/pixel_map.h"
24 #include "core/components_ng/render/drawing.h"
25 #include "core/image/sk_image_cache.h"
26 #ifdef ENABLE_ROSEN_BACKEND
27 #include "pipeline/rs_recording_canvas.h"
28 #endif
29
30 namespace OHOS::Ace::NG {
31 namespace {
CloneSkPixmap(SkPixmap & srcPixmap,const std::unique_ptr<uint8_t[]> & dstPixels)32 SkPixmap CloneSkPixmap(SkPixmap& srcPixmap, const std::unique_ptr<uint8_t[]>& dstPixels)
33 {
34 // Media::PixelMap::Create only accepts BGRA ColorType pixmap, have to clone and change ColorType.
35 SkImageInfo dstImageInfo = SkImageInfo::Make(srcPixmap.info().width(), srcPixmap.info().height(),
36 SkColorType::kBGRA_8888_SkColorType, srcPixmap.alphaType());
37 SkPixmap dstPixmap(dstImageInfo, dstPixels.get(), srcPixmap.rowBytes());
38
39 SkBitmap dstBitmap;
40 if (!dstBitmap.installPixels(dstPixmap)) {
41 return dstPixmap;
42 }
43 if (!dstBitmap.writePixels(srcPixmap, 0, 0)) {
44 return dstPixmap;
45 }
46 return dstPixmap;
47 }
48 } // namespace
49
Create(void * rawImage)50 RefPtr<CanvasImage> CanvasImage::Create(void* rawImage)
51 {
52 auto* skImagePtr = reinterpret_cast<sk_sp<SkImage>*>(rawImage);
53 return AceType::MakeRefPtr<SkiaImage>(*skImagePtr);
54 }
55
Create()56 RefPtr<CanvasImage> CanvasImage::Create()
57 {
58 return AceType::MakeRefPtr<SkiaImage>();
59 }
60
MakeSkImageFromPixmap(const RefPtr<PixelMap> & pixmap)61 sk_sp<SkImage> SkiaImage::MakeSkImageFromPixmap(const RefPtr<PixelMap>& pixmap)
62 {
63 SkColorType colorType = PixelFormatToSkColorType(pixmap);
64 SkAlphaType alphaType = AlphaTypeToSkAlphaType(pixmap);
65 sk_sp<SkColorSpace> colorSpace = ColorSpaceToSkColorSpace(pixmap);
66 auto info = SkImageInfo::Make(pixmap->GetWidth(), pixmap->GetHeight(), colorType, alphaType, colorSpace);
67
68 SkPixmap skPixmap(info, pixmap->GetPixels(), pixmap->GetRowBytes());
69 return SkImage::MakeFromRaster(skPixmap, &PixelMap::ReleaseProc, PixelMap::GetReleaseContext(pixmap));
70 }
71
ColorSpaceToSkColorSpace(const RefPtr<PixelMap> & pixmap)72 sk_sp<SkColorSpace> SkiaImage::ColorSpaceToSkColorSpace(const RefPtr<PixelMap>& pixmap)
73 {
74 return SkColorSpace::MakeSRGB(); // Media::PixelMap has not support wide gamut yet.
75 }
76
AlphaTypeToSkAlphaType(const RefPtr<PixelMap> & pixmap)77 SkAlphaType SkiaImage::AlphaTypeToSkAlphaType(const RefPtr<PixelMap>& pixmap)
78 {
79 switch (pixmap->GetAlphaType()) {
80 case AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN:
81 return SkAlphaType::kUnknown_SkAlphaType;
82 case AlphaType::IMAGE_ALPHA_TYPE_OPAQUE:
83 return SkAlphaType::kOpaque_SkAlphaType;
84 case AlphaType::IMAGE_ALPHA_TYPE_PREMUL:
85 return SkAlphaType::kPremul_SkAlphaType;
86 case AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL:
87 return SkAlphaType::kUnpremul_SkAlphaType;
88 default:
89 return SkAlphaType::kUnknown_SkAlphaType;
90 }
91 }
92
PixelFormatToSkColorType(const RefPtr<PixelMap> & pixmap)93 SkColorType SkiaImage::PixelFormatToSkColorType(const RefPtr<PixelMap>& pixmap)
94 {
95 switch (pixmap->GetPixelFormat()) {
96 case PixelFormat::RGB_565:
97 return SkColorType::kRGB_565_SkColorType;
98 case PixelFormat::RGBA_8888:
99 return SkColorType::kRGBA_8888_SkColorType;
100 case PixelFormat::BGRA_8888:
101 return SkColorType::kBGRA_8888_SkColorType;
102 case PixelFormat::ALPHA_8:
103 return SkColorType::kAlpha_8_SkColorType;
104 case PixelFormat::RGBA_F16:
105 return SkColorType::kRGBA_F16_SkColorType;
106 case PixelFormat::UNKNOWN:
107 case PixelFormat::ARGB_8888:
108 case PixelFormat::RGB_888:
109 case PixelFormat::NV21:
110 case PixelFormat::NV12:
111 case PixelFormat::CMYK:
112 default:
113 return SkColorType::kUnknown_SkColorType;
114 }
115 }
116
ReplaceSkImage(sk_sp<SkImage> newSkImage)117 void SkiaImage::ReplaceSkImage(sk_sp<SkImage> newSkImage)
118 {
119 image_ = std::move(newSkImage);
120 }
121
GetWidth() const122 int32_t SkiaImage::GetWidth() const
123 {
124 return image_ ? image_->width() : compressWidth_;
125 }
126
GetHeight() const127 int32_t SkiaImage::GetHeight() const
128 {
129 return image_ ? image_->height() : compressHeight_;
130 }
131
Clone()132 RefPtr<CanvasImage> SkiaImage::Clone()
133 {
134 auto clone = MakeRefPtr<SkiaImage>(image_);
135 clone->uniqueId_ = uniqueId_;
136 clone->compressData_ = std::move(compressData_);
137 clone->compressWidth_ = compressWidth_;
138 clone->compressHeight_ = compressHeight_;
139 return clone;
140 }
141
Cache(const std::string & key)142 void SkiaImage::Cache(const std::string& key)
143 {
144 auto pipelineCtx = PipelineContext::GetCurrentContext();
145 CHECK_NULL_VOID(pipelineCtx);
146 auto cache = pipelineCtx->GetImageCache();
147 CHECK_NULL_VOID(cache);
148
149 auto cached = std::make_shared<CachedImage>(GetImage());
150 cached->uniqueId = GetUniqueID();
151 pipelineCtx->GetImageCache()->CacheImage(key, cached);
152 }
153
QueryFromCache(const std::string & key)154 RefPtr<CanvasImage> SkiaImage::QueryFromCache(const std::string& key)
155 {
156 auto pipelineCtx = PipelineContext::GetCurrentContext();
157 CHECK_NULL_RETURN(pipelineCtx, nullptr);
158 auto cache = pipelineCtx->GetImageCache();
159 CHECK_NULL_RETURN(cache, nullptr);
160 auto cacheImage = cache->GetCacheImage(key);
161 CHECK_NULL_RETURN(cacheImage, nullptr);
162
163 auto skiaImage = MakeRefPtr<SkiaImage>(cacheImage->imagePtr);
164 skiaImage->SetUniqueID(cacheImage->uniqueId);
165
166 return skiaImage;
167 }
168
GetPixelMap() const169 RefPtr<PixelMap> SkiaImage::GetPixelMap() const
170 {
171 CHECK_NULL_RETURN(GetImage(), nullptr);
172 auto rasterImage = GetImage()->makeRasterImage();
173 SkPixmap srcPixmap;
174 if (!rasterImage->peekPixels(&srcPixmap)) {
175 return nullptr;
176 }
177 auto dstPixels = std::make_unique<uint8_t[]>(srcPixmap.computeByteSize());
178 SkPixmap newSrcPixmap = CloneSkPixmap(srcPixmap, dstPixels);
179 const auto* addr = newSrcPixmap.addr32();
180 auto width = static_cast<int32_t>(newSrcPixmap.width());
181 auto height = static_cast<int32_t>(newSrcPixmap.height());
182 int32_t length = width * height;
183 return PixelMap::ConvertSkImageToPixmap(addr, length, width, height);
184 }
185
DrawToRSCanvas(RSCanvas & canvas,const RSRect & srcRect,const RSRect & dstRect,const BorderRadiusArray & radiusXY)186 void SkiaImage::DrawToRSCanvas(
187 RSCanvas& canvas, const RSRect& srcRect, const RSRect& dstRect, const BorderRadiusArray& radiusXY)
188 {
189 auto image = GetImage();
190 CHECK_NULL_VOID(image || GetCompressData());
191 if (isDrawAnimate_) {
192 RSImage rsImage(&image);
193 RSSamplingOptions options;
194 ImagePainterUtils::ClipRRect(canvas, dstRect, radiusXY);
195 canvas.DrawImageRect(rsImage, srcRect, dstRect, options);
196 } else {
197 DrawWithRecordingCanvas(canvas, radiusXY);
198 }
199 }
200
DrawWithRecordingCanvas(RSCanvas & canvas,const BorderRadiusArray & radiusXY)201 bool SkiaImage::DrawWithRecordingCanvas(RSCanvas& canvas, const BorderRadiusArray& radiusXY)
202 {
203 #ifdef ENABLE_ROSEN_BACKEND
204 auto rsCanvas = canvas.GetImpl<RSSkCanvas>();
205 CHECK_NULL_RETURN(rsCanvas, false);
206 auto skCanvas = rsCanvas->ExportSkCanvas();
207 CHECK_NULL_RETURN(skCanvas, false);
208 auto recordingCanvas = static_cast<Rosen::RSRecordingCanvas*>(skCanvas);
209 CHECK_NULL_RETURN(recordingCanvas, false);
210
211 SkPaint paint;
212 auto config = GetPaintConfig();
213
214 SkSamplingOptions options;
215 ImagePainterUtils::AddFilter(paint, options, config);
216 auto radii = ImagePainterUtils::ToSkRadius(radiusXY);
217 recordingCanvas->ClipAdaptiveRRect(radii.get());
218 recordingCanvas->scale(config.scaleX_, config.scaleY_);
219
220 Rosen::RsImageInfo rsImageInfo((int)(config.imageFit_), (int)(config.imageRepeat_), radii.get(), 1.0, GetUniqueID(),
221 GetCompressWidth(), GetCompressHeight());
222 auto data = GetCompressData();
223
224 // Haw to set SamplingOptions?
225 recordingCanvas->DrawImageWithParm(GetImage(), std::move(data), rsImageInfo, options, paint);
226 return true;
227 #else // !ENABLE_ROSEN_BACKEND
228 return false;
229 #endif
230 }
231 } // namespace OHOS::Ace::NG
232
233 namespace OHOS::Ace {
Purge()234 void ImageCache::Purge()
235 {
236 SkGraphics::PurgeResourceCache();
237 }
238 } // namespace OHOS::Ace
239