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/rosen/drawing_image.h"
17
18 #include "include/core/SkGraphics.h"
19 #include "core/components_ng/property/measure_utils.h"
20 #include "frameworks/core/components_ng/render/adapter/image_painter_utils.h"
21 #include "frameworks/core/image/sk_image_cache.h"
22 #ifdef ENABLE_ROSEN_BACKEND
23 #include "pipeline/rs_recording_canvas.h"
24 #endif
25
26 namespace OHOS::Ace::NG {
27 namespace {
28 // The [GRAY_COLOR_MATRIX] is of dimension [4 x 5], which transforms a RGB source color (R, G, B, A) to the
29 // destination color (R', G', B', A').
30 //
31 // A classic color image to grayscale conversion formula is [Gray = R * 0.3 + G * 0.59 + B * 0.11].
32 // Hence we get the following conversion:
33 //
34 // | M11 M12 M13 M14 M15 | | R | | R' |
35 // | M21 M22 M23 M24 M25 | | G | | G' |
36 // | M31 M32 M33 M34 M35 | x | B | = | B' |
37 // | M41 M42 M43 M44 M45 | | A | | A' |
38 // | 1 |
39 const float GRAY_COLOR_MATRIX[20] = { 0.30f, 0.59f, 0.11f, 0, 0, // red
40 0.30f, 0.59f, 0.11f, 0, 0, // green
41 0.30f, 0.59f, 0.11f, 0, 0, // blue
42 0, 0, 0, 1.0f, 0 }; // alpha transparency
43
PrintDrawingLatticeConfig(const Rosen::Drawing::Lattice & lattice)44 void PrintDrawingLatticeConfig(const Rosen::Drawing::Lattice& lattice)
45 {
46 std::string drawingConfigStr;
47 drawingConfigStr.append("fXCount = " + std::to_string(lattice.fXCount));
48 drawingConfigStr.append("fXDivs = [");
49 for (int32_t idx = 0; idx < lattice.fXCount; ++idx) {
50 drawingConfigStr.append(std::to_string(lattice.fXDivs[idx]) + " ");
51 }
52 drawingConfigStr.append("] ");
53 drawingConfigStr.append("fYCount = " + std::to_string(lattice.fYCount));
54 drawingConfigStr.append("fYDivs = [");
55 for (int32_t idx = 0; idx < lattice.fYCount; ++idx) {
56 drawingConfigStr.append(std::to_string(lattice.fYDivs[idx]) + " ");
57 }
58 drawingConfigStr.append("] ");
59 TAG_LOGD(AceLogTag::ACE_IMAGE, "Begin to draw iamge with lattice : %{public}s", drawingConfigStr.c_str());
60 }
61
ConvertSlice(const ImagePaintConfig & config,RectF & result,float rawImageWidth,float rawImageHeight)62 bool ConvertSlice(const ImagePaintConfig& config, RectF& result, float rawImageWidth, float rawImageHeight)
63 {
64 const auto& slice = config.resizableSlice_;
65 CHECK_NULL_RETURN(slice.Valid(), false);
66 TAG_LOGD(AceLogTag::ACE_IMAGE, "Draw image with slice = %{public}s.", slice.ToString().c_str());
67 result.SetLeft(ConvertToPx(slice.left, ScaleProperty::CreateScaleProperty(), rawImageWidth).value_or(0.0f));
68 result.SetTop(ConvertToPx(slice.top, ScaleProperty::CreateScaleProperty(), rawImageHeight).value_or(0.0f));
69 auto rightSliceValue = ConvertToPx(slice.right, ScaleProperty::CreateScaleProperty(), rawImageWidth).value_or(0.0f);
70 auto bottomSliceValue =
71 ConvertToPx(slice.bottom, ScaleProperty::CreateScaleProperty(), rawImageHeight).value_or(0.0f);
72 // illegal case if left position if larger than right, then rect has negative width
73 if (GreatNotEqual(rawImageWidth - rightSliceValue - result.GetX(), 0.0f)) {
74 result.SetWidth(rawImageWidth - rightSliceValue - result.GetX());
75 } else {
76 return false;
77 }
78 // same illegal case for height
79 if (GreatNotEqual(rawImageHeight - bottomSliceValue - result.GetY(), 0.0f)) {
80 result.SetHeight(rawImageHeight - bottomSliceValue - result.GetY());
81 } else {
82 return false;
83 }
84 return true;
85 }
86
87 #ifndef USE_ROSEN_DRAWING
UpdateSKFilter(const ImagePaintConfig & config,SKPaint & paint)88 void UpdateSKFilter(const ImagePaintConfig& config, SKPaint& paint)
89 {
90 if (config.colorFilter_.colorFilterMatrix_) {
91 paint.setColorFilter(SkColorFilters::Matrix(config.colorFilter_.colorFilterMatrix_->data()));
92 } else if (ImageRenderMode::TEMPLATE == config.renderMode_) {
93 paint.setColorFilter(SkColorFilters::Matrix(GRAY_COLOR_MATRIX));
94 }
95 }
96 #else
UpdateRSFilter(const ImagePaintConfig & config,RSFilter & filter)97 void UpdateRSFilter(const ImagePaintConfig& config, RSFilter& filter)
98 {
99 if (config.colorFilter_.colorFilterMatrix_) {
100 RSColorMatrix colorMatrix;
101 colorMatrix.SetArray(config.colorFilter_.colorFilterMatrix_->data());
102 filter.SetColorFilter(RSRecordingColorFilter::CreateMatrixColorFilter(colorMatrix));
103 } else if (config.colorFilter_.colorFilterDrawing_) {
104 auto colorFilterSptrAddr = static_cast<std::shared_ptr<RSColorFilter>*>(
105 config.colorFilter_.colorFilterDrawing_->GetDrawingColorFilterSptrAddr());
106 if (colorFilterSptrAddr && (*colorFilterSptrAddr)) {
107 filter.SetColorFilter(*colorFilterSptrAddr);
108 }
109 } else if (ImageRenderMode::TEMPLATE == config.renderMode_) {
110 RSColorMatrix colorMatrix;
111 colorMatrix.SetArray(GRAY_COLOR_MATRIX);
112 filter.SetColorFilter(RSRecordingColorFilter::CreateMatrixColorFilter(colorMatrix));
113 }
114 }
115 #endif
116 } // namespace
117
Create(void * rawImage)118 RefPtr<CanvasImage> CanvasImage::Create(void* rawImage)
119 {
120 auto* rsImagePtr = reinterpret_cast<std::shared_ptr<RSImage>*>(rawImage);
121 return AceType::MakeRefPtr<DrawingImage>(*rsImagePtr);
122 }
123
Create()124 RefPtr<CanvasImage> CanvasImage::Create()
125 {
126 return AceType::MakeRefPtr<DrawingImage>();
127 }
128
MakeRSImageFromPixmap(const RefPtr<PixelMap> & pixmap)129 std::shared_ptr<RSImage> DrawingImage::MakeRSImageFromPixmap(const RefPtr<PixelMap>& pixmap)
130 {
131 RSColorType colorType = PixelFormatToRSColorType(pixmap);
132 RSAlphaType alphaType = AlphaTypeToRSAlphaType(pixmap);
133 RSBitmapFormat bitmapFormat = { colorType, alphaType };
134 auto bitmap = std::make_shared<RSBitmap>();
135 bitmap->Build(pixmap->GetWidth(), pixmap->GetHeight(), bitmapFormat, pixmap->GetRowStride());
136 bitmap->SetPixels(const_cast<void*>(reinterpret_cast<const void*>(pixmap->GetPixels())));
137
138 auto image = std::make_shared<RSImage>();
139 image->BuildFromBitmap(*bitmap);
140 return image;
141 }
142
AlphaTypeToRSAlphaType(const RefPtr<PixelMap> & pixmap)143 RSAlphaType DrawingImage::AlphaTypeToRSAlphaType(const RefPtr<PixelMap>& pixmap)
144 {
145 switch (pixmap->GetAlphaType()) {
146 case AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN:
147 return RSAlphaType::ALPHATYPE_UNKNOWN;
148 case AlphaType::IMAGE_ALPHA_TYPE_OPAQUE:
149 return RSAlphaType::ALPHATYPE_OPAQUE;
150 case AlphaType::IMAGE_ALPHA_TYPE_PREMUL:
151 return RSAlphaType::ALPHATYPE_PREMUL;
152 case AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL:
153 return RSAlphaType::ALPHATYPE_UNPREMUL;
154 default:
155 return RSAlphaType::ALPHATYPE_UNKNOWN;
156 }
157 }
158
PixelFormatToRSColorType(const RefPtr<PixelMap> & pixmap)159 RSColorType DrawingImage::PixelFormatToRSColorType(const RefPtr<PixelMap>& pixmap)
160 {
161 switch (pixmap->GetPixelFormat()) {
162 case PixelFormat::RGB_565:
163 return RSColorType::COLORTYPE_RGB_565;
164 case PixelFormat::RGBA_8888:
165 return RSColorType::COLORTYPE_RGBA_8888;
166 case PixelFormat::BGRA_8888:
167 return RSColorType::COLORTYPE_BGRA_8888;
168 case PixelFormat::ALPHA_8:
169 return RSColorType::COLORTYPE_ALPHA_8;
170 case PixelFormat::RGBA_F16:
171 return RSColorType::COLORTYPE_RGBA_F16;
172 case PixelFormat::UNKNOWN:
173 case PixelFormat::ARGB_8888:
174 case PixelFormat::RGB_888:
175 case PixelFormat::NV21:
176 case PixelFormat::NV12:
177 case PixelFormat::CMYK:
178 default:
179 return RSColorType::COLORTYPE_UNKNOWN;
180 }
181 }
182
ReplaceRSImage(std::shared_ptr<RSImage> image)183 void DrawingImage::ReplaceRSImage(std::shared_ptr<RSImage> image)
184 {
185 image_ = std::move(image);
186 }
187
GetWidth() const188 int32_t DrawingImage::GetWidth() const
189 {
190 return image_ ? image_->GetWidth() : compressWidth_;
191 }
192
GetHeight() const193 int32_t DrawingImage::GetHeight() const
194 {
195 return image_ ? image_->GetHeight() : compressHeight_;
196 }
197
Clone()198 RefPtr<CanvasImage> DrawingImage::Clone()
199 {
200 auto clone = MakeRefPtr<DrawingImage>(image_);
201 clone->uniqueId_ = uniqueId_;
202 clone->compressData_ = std::move(compressData_);
203 clone->compressWidth_ = compressWidth_;
204 clone->compressHeight_ = compressHeight_;
205 return clone;
206 }
207
Cache(const std::string & key)208 void DrawingImage::Cache(const std::string& key)
209 {
210 auto pipelineCtx = PipelineContext::GetCurrentContext();
211 CHECK_NULL_VOID(pipelineCtx);
212 auto cache = pipelineCtx->GetImageCache();
213 CHECK_NULL_VOID(cache);
214
215 auto cached = std::make_shared<CachedImage>(GetImage());
216 cached->uniqueId = GetUniqueID();
217 pipelineCtx->GetImageCache()->CacheImage(key, cached);
218 }
219
QueryFromCache(const std::string & key)220 RefPtr<CanvasImage> DrawingImage::QueryFromCache(const std::string& key)
221 {
222 auto pipelineCtx = PipelineContext::GetCurrentContext();
223 CHECK_NULL_RETURN(pipelineCtx, nullptr);
224 auto cache = pipelineCtx->GetImageCache();
225 CHECK_NULL_RETURN(cache, nullptr);
226 auto cacheImage = cache->GetCacheImage(key);
227 CHECK_NULL_RETURN(cacheImage, nullptr);
228
229 auto rosenImage = MakeRefPtr<DrawingImage>(cacheImage->imagePtr);
230 rosenImage->SetUniqueID(cacheImage->uniqueId);
231
232 return rosenImage;
233 }
234
GetPixelMap() const235 RefPtr<PixelMap> DrawingImage::GetPixelMap() const
236 {
237 CHECK_NULL_RETURN(GetImage(), nullptr);
238 auto rsImage = GetImage();
239 RSBitmapFormat rsBitmapFormat = { RSColorType::COLORTYPE_BGRA_8888, rsImage->GetAlphaType() };
240 RSBitmap rsBitmap;
241 if (!rsBitmap.Build(rsImage->GetWidth(), rsImage->GetHeight(), rsBitmapFormat)) {
242 LOGW("rsBitmap build fail.");
243 return nullptr;
244 }
245 CHECK_NULL_RETURN(rsImage->ReadPixels(rsBitmap, 0, 0), nullptr);
246 const auto* addr = static_cast<uint32_t*>(rsBitmap.GetPixels());
247 auto width = static_cast<int32_t>(rsBitmap.GetWidth());
248 auto height = static_cast<int32_t>(rsBitmap.GetHeight());
249 int32_t length = width * height;
250 return PixelMap::ConvertSkImageToPixmap(addr, length, width, height);
251 }
252
DrawToRSCanvas(RSCanvas & canvas,const RSRect & srcRect,const RSRect & dstRect,const BorderRadiusArray & radiusXY)253 void DrawingImage::DrawToRSCanvas(
254 RSCanvas& canvas, const RSRect& srcRect, const RSRect& dstRect, const BorderRadiusArray& radiusXY)
255 {
256 auto image = GetImage();
257 CHECK_NULL_VOID(image || GetCompressData());
258 if (isDrawAnimate_) {
259 RSSamplingOptions options;
260 ImagePainterUtils::ClipRRect(canvas, dstRect, radiusXY);
261 canvas.DrawImageRect(*image, srcRect, dstRect, options);
262 } else {
263 const auto& config = GetPaintConfig();
264 if (config.resizableLattice_ && DrawImageLattice(canvas, srcRect, dstRect, radiusXY)) {
265 return;
266 }
267 if (config.resizableSlice_.Valid() && DrawImageNine(canvas, srcRect, dstRect, radiusXY)) {
268 return;
269 }
270 DrawWithRecordingCanvas(canvas, radiusXY);
271 }
272 }
273
DrawImageLattice(RSCanvas & canvas,const RSRect & srcRect,const RSRect & dstRect,const BorderRadiusArray & radiusXY)274 bool DrawingImage::DrawImageLattice(
275 RSCanvas& canvas, const RSRect& srcRect, const RSRect& dstRect, const BorderRadiusArray& radiusXY)
276 {
277 const auto& config = GetPaintConfig();
278 const auto& drawingLattice = config.resizableLattice_;
279 CHECK_NULL_RETURN(drawingLattice, false);
280 #ifdef ENABLE_ROSEN_BACKEND
281 auto latticeSptrAddr =
282 static_cast<std::shared_ptr<Rosen::Drawing::Lattice>*>(drawingLattice->GetDrawingLatticeSptrAddr());
283 RSBrush brush;
284 auto filterMode = RSFilterMode::NEAREST;
285 switch (config.imageInterpolation_) {
286 case ImageInterpolation::LOW:
287 case ImageInterpolation::MEDIUM:
288 filterMode = RSFilterMode::LINEAR;
289 break;
290 case ImageInterpolation::HIGH:
291 default:
292 break;
293 }
294
295 auto filter = brush.GetFilter();
296 UpdateRSFilter(config, filter);
297 brush.SetFilter(filter);
298 auto& recordingCanvas = static_cast<Rosen::ExtendRecordingCanvas&>(canvas);
299 auto radii = ImagePainterUtils::ToRSRadius(radiusXY);
300 std::vector<RSPoint> radius;
301 for (size_t ii = 0; ii < 4; ii++) {
302 RSPoint point(radii[ii].GetX(), radii[ii].GetY());
303 radius.emplace_back(point);
304 }
305 recordingCanvas.ClipAdaptiveRoundRect(radius);
306 recordingCanvas.Scale(config.scaleX_, config.scaleY_);
307
308 RSPoint pointRadius[4] = {};
309 for (size_t i = 0; i < 4; i++) {
310 pointRadius[i] = radius[i];
311 }
312 auto lattice = *(*latticeSptrAddr);
313 if (SystemProperties::GetDebugEnabled()) {
314 PrintDrawingLatticeConfig(lattice);
315 }
316 recordingCanvas.AttachBrush(brush);
317 recordingCanvas.DrawImageLattice(image_.get(), *(*latticeSptrAddr), dstRect, filterMode);
318 recordingCanvas.DetachBrush();
319 return true;
320 #endif
321 return false;
322 }
323
DrawImageNine(RSCanvas & canvas,const RSRect & srcRect,const RSRect & dstRect,const BorderRadiusArray & radiusXY)324 bool DrawingImage::DrawImageNine(
325 RSCanvas& canvas, const RSRect& srcRect, const RSRect& dstRect, const BorderRadiusArray& radiusXY)
326 {
327 const auto& config = GetPaintConfig();
328 const auto& slice = GetPaintConfig().resizableSlice_;
329 CHECK_NULL_RETURN(slice.Valid(), false);
330 RectF centerRect;
331 CHECK_NULL_RETURN(ConvertSlice(config, centerRect, GetWidth(), GetHeight()), false);
332 #ifdef ENABLE_ROSEN_BACKEND
333 #ifndef USE_ROSEN_DRAWING
334 return false;
335 #endif
336 RSBrush brush;
337 auto filterMode = RSFilterMode::NEAREST;
338 switch (config.imageInterpolation_) {
339 case ImageInterpolation::LOW:
340 case ImageInterpolation::MEDIUM:
341 filterMode = RSFilterMode::LINEAR;
342 break;
343 case ImageInterpolation::HIGH:
344 default:
345 break;
346 }
347
348 auto filter = brush.GetFilter();
349 UpdateRSFilter(config, filter);
350 brush.SetFilter(filter);
351 auto& recordingCanvas = static_cast<Rosen::ExtendRecordingCanvas&>(canvas);
352 auto radii = ImagePainterUtils::ToRSRadius(radiusXY);
353 std::vector<RSPoint> radius;
354 for (int ii = 0; ii < 4; ii++) {
355 RSPoint point(radii[ii].GetX(), radii[ii].GetY());
356 radius.emplace_back(point);
357 }
358 recordingCanvas.ClipAdaptiveRoundRect(radius);
359 recordingCanvas.Scale(config.scaleX_, config.scaleY_);
360
361 RSPoint pointRadius[4] = {};
362 for (int i = 0; i < 4; i++) {
363 pointRadius[i] = radius[i];
364 }
365 RSRectI rsCenterRect(centerRect.GetX(), centerRect.GetY(), centerRect.GetX() + centerRect.Width(),
366 centerRect.GetY() + centerRect.Height());
367 recordingCanvas.AttachBrush(brush);
368 recordingCanvas.DrawImageNine(image_.get(), rsCenterRect, dstRect, filterMode, &brush);
369 recordingCanvas.DetachBrush();
370 return true;
371 #endif
372 return false;
373 }
374
DrawWithRecordingCanvas(RSCanvas & canvas,const BorderRadiusArray & radiusXY)375 bool DrawingImage::DrawWithRecordingCanvas(RSCanvas& canvas, const BorderRadiusArray& radiusXY)
376 {
377 #ifdef ENABLE_ROSEN_BACKEND
378 RSBrush brush;
379 auto config = GetPaintConfig();
380 RSSamplingOptions options;
381 ImagePainterUtils::AddFilter(brush, options, config);
382 auto radii = ImagePainterUtils::ToRSRadius(radiusXY);
383 auto& recordingCanvas = static_cast<Rosen::ExtendRecordingCanvas&>(canvas);
384 std::vector<RSPoint> radius;
385 for (int ii = 0; ii < 4; ii++) {
386 RSPoint point(radii[ii].GetX(), radii[ii].GetY());
387 radius.emplace_back(point);
388 }
389 recordingCanvas.ClipAdaptiveRoundRect(radius);
390 recordingCanvas.Scale(config.scaleX_, config.scaleY_);
391
392 RSPoint pointRadius[4] = {};
393 for (int i = 0; i < 4; i++) {
394 pointRadius[i] = radius[i];
395 }
396 Rosen::Drawing::AdaptiveImageInfo rsImageInfo = {
397 static_cast<int32_t>(config.imageFit_), static_cast<int32_t>(config.imageRepeat_),
398 {pointRadius[0], pointRadius[1], pointRadius[2], pointRadius[3]}, 1.0, GetUniqueID(),
399 GetCompressWidth(), GetCompressHeight()
400 };
401 auto data = GetCompressData();
402 recordingCanvas.AttachBrush(brush);
403 recordingCanvas.DrawImageWithParm(GetImage(), std::move(data), rsImageInfo, options);
404 recordingCanvas.DetachBrush();
405 return true;
406 #else // !ENABLE_ROSEN_BACKEND
407 return false;
408 #endif
409 }
410
DrawRect(RSCanvas & canvas,const RSRect & srcRect,const RSRect & dstRect)411 void DrawingImage::DrawRect(RSCanvas& canvas, const RSRect& srcRect, const RSRect& dstRect)
412 {
413 #ifdef ENABLE_ROSEN_BACKEND
414 auto& recordingCanvas = static_cast<Rosen::Drawing::RecordingCanvas&>(canvas);
415 RSBrush brush;
416 RSSamplingOptions options;
417 RSRect dst = RSRect(dstRect.GetLeft(), dstRect.GetTop(), dstRect.GetRight(), dstRect.GetBottom());
418 RSRect src = RSRect(srcRect.GetLeft(), srcRect.GetTop(), srcRect.GetRight(), srcRect.GetBottom());
419 recordingCanvas.AttachBrush(brush);
420 auto imagePtr = GetImage();
421 recordingCanvas.DrawImageRect(*imagePtr, src, dst, options);
422 recordingCanvas.DetachBrush();
423 #else // !ENABLE_ROSEN_BACKEND
424 #endif
425 }
426 } // namespace OHOS::Ace::NG
427
428 namespace OHOS::Ace {
Purge()429 void ImageCache::Purge()
430 {
431 SkGraphics::PurgeResourceCache();
432 }
433 } // namespace OHOS::Ace::NG
434