1 /*
2 * Copyright (c) 2022 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/pattern/canvas/offscreen_canvas_paint_method.h"
17
18 #ifndef ACE_UNITTEST
19 #include "include/utils/SkBase64.h"
20 #include "core/components/common/painter/rosen_decoration_painter.h"
21 #include "core/components/font/constants_converter.h"
22 #include "core/components/font/rosen_font_collection.h"
23 #endif
24
25 #include "base/geometry/ng/offset_t.h"
26 #include "base/i18n/localization.h"
27 #include "base/image/pixel_map.h"
28 #include "base/utils/utils.h"
29 #include "core/common/container.h"
30 #include "core/components/common/properties/paint_state.h"
31 #include "core/components_ng/pattern/canvas/custom_paint_util.h"
32
33 namespace OHOS::Ace::NG {
34 constexpr Dimension DEFAULT_FONT_SIZE = 14.0_px;
OffscreenCanvasPaintMethod(int32_t width,int32_t height)35 OffscreenCanvasPaintMethod::OffscreenCanvasPaintMethod(int32_t width, int32_t height)
36 {
37 antiAlias_ = false;
38 matrix_.Reset();
39 width_ = width;
40 height_ = height;
41 lastLayoutSize_.SetWidth(static_cast<float>(width));
42 lastLayoutSize_.SetHeight(static_cast<float>(height));
43 InitBitmap();
44 // The initial value of the font size in canvas is 14px.
45 SetFontSize(DEFAULT_FONT_SIZE);
46 }
47
InitBitmap()48 void OffscreenCanvasPaintMethod::InitBitmap()
49 {
50 RSBitmapFormat bitmapFormat = { RSColorType::COLORTYPE_RGBA_8888, RSAlphaType::ALPHATYPE_UNPREMUL };
51 bool ret = bitmap_.Build(width_, height_, bitmapFormat);
52 if (!ret) {
53 TAG_LOGE(AceLogTag::ACE_CANVAS, "The width and height exceed the limit size.");
54 return ;
55 }
56 bitmap_.ClearWithColor(RSColor::COLOR_TRANSPARENT);
57 bitmapSize_ = bitmap_.ComputeByteSize();
58 rsCanvas_ = std::make_unique<RSCanvas>();
59 rsCanvas_->Bind(bitmap_);
60 }
61
TransferToImageBitmap()62 RefPtr<PixelMap> OffscreenCanvasPaintMethod::TransferToImageBitmap()
63 {
64 #ifdef PIXEL_MAP_SUPPORTED
65 OHOS::Media::InitializationOptions options;
66 options.alphaType = OHOS::Media::AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
67 options.pixelFormat = OHOS::Media::PixelFormat::RGBA_8888;
68 options.scaleMode = OHOS::Media::ScaleMode::CENTER_CROP;
69 options.size.width = width_;
70 options.size.height = height_;
71 options.editable = true;
72 auto pixelMap = Ace::PixelMap::Create(OHOS::Media::PixelMap::Create(options));
73 CHECK_NULL_RETURN(pixelMap, nullptr);
74 std::shared_ptr<Ace::ImageData> imageData = std::make_shared<Ace::ImageData>();
75 imageData->pixelMap = pixelMap;
76 imageData->dirtyX = 0.0f;
77 imageData->dirtyY = 0.0f;
78 imageData->dirtyWidth = width_;
79 imageData->dirtyHeight = height_;
80 GetImageData(imageData);
81 return pixelMap;
82 #else
83 return nullptr;
84 #endif
85 }
86
Reset()87 void OffscreenCanvasPaintMethod::Reset()
88 {
89 matrix_.Reset();
90 ResetStates();
91 InitBitmap();
92 }
93
UpdateSize(int32_t width,int32_t height)94 void OffscreenCanvasPaintMethod::UpdateSize(int32_t width, int32_t height)
95 {
96 width_ = width;
97 height_ = height;
98 lastLayoutSize_.SetWidth(static_cast<float>(width));
99 lastLayoutSize_.SetHeight(static_cast<float>(height));
100 Reset();
101 }
102
DrawPixelMap(RefPtr<PixelMap> pixelMap,const Ace::CanvasImage & canvasImage)103 void OffscreenCanvasPaintMethod::DrawPixelMap(RefPtr<PixelMap> pixelMap, const Ace::CanvasImage& canvasImage)
104 {
105 #ifndef ACE_UNITTEST
106 // get Image form pixelMap
107 CHECK_NULL_VOID(pixelMap);
108 auto rsBitmapFormat = Ace::ImageProvider::MakeRSBitmapFormatFromPixelMap(pixelMap);
109 auto rsBitmap = std::make_shared<RSBitmap>();
110 rsBitmap->Build(pixelMap->GetWidth(), pixelMap->GetHeight(), rsBitmapFormat, pixelMap->GetRowStride());
111 rsBitmap->SetPixels(const_cast<void*>(reinterpret_cast<const void*>(pixelMap->GetPixels())));
112
113 // Step2: Create Image and draw it, using gpu or cpu
114 auto image = std::make_shared<RSImage>();
115 CHECK_NULL_VOID(image->BuildFromBitmap(*rsBitmap));
116 DrawImageInternal(canvasImage, image);
117 #endif
118 }
119
GetImageData(double left,double top,double width,double height)120 std::unique_ptr<Ace::ImageData> OffscreenCanvasPaintMethod::GetImageData(
121 double left, double top, double width, double height)
122 {
123 double dirtyWidth = std::abs(width);
124 double dirtyHeight = std::abs(height);
125 double scaledLeft = left + std::min(width, 0.0);
126 double scaledTop = top + std::min(height, 0.0);
127 // copy the bitmap to tempCanvas
128 RSBitmapFormat format { RSColorType::COLORTYPE_BGRA_8888, RSAlphaType::ALPHATYPE_OPAQUE };
129 int32_t size = dirtyWidth * dirtyHeight;
130 auto srcRect =
131 RSRect(scaledLeft, scaledTop, dirtyWidth + scaledLeft, dirtyHeight + scaledTop);
132 auto dstRect = RSRect(0.0, 0.0, dirtyWidth, dirtyHeight);
133 RSBitmap tempCache;
134 tempCache.Build(dirtyWidth, dirtyHeight, format);
135 RSCanvas tempCanvas;
136 tempCanvas.Bind(tempCache);
137 RSImage rsImage;
138 rsImage.BuildFromBitmap(bitmap_);
139 tempCanvas.DrawImageRect(
140 rsImage, srcRect, dstRect, RSSamplingOptions(), RSSrcRectConstraint::FAST_SRC_RECT_CONSTRAINT);
141 // write color
142 uint8_t* pixels = static_cast<uint8_t*>(tempCache.GetPixels());
143 std::unique_ptr<Ace::ImageData> imageData = std::make_unique<Ace::ImageData>();
144 imageData->dirtyWidth = dirtyWidth;
145 imageData->dirtyHeight = dirtyHeight;
146 // a pixel include 4 data blue, green, red, alpha
147 for (int i = 0; i < size * 4; i += 4) {
148 auto blue = pixels[i];
149 auto green = pixels[i + 1];
150 auto red = pixels[i + 2];
151 auto alpha = pixels[i + 3];
152 imageData->data.emplace_back(Color::FromARGB(alpha, red, green, blue).GetValue());
153 }
154 return imageData;
155 }
156
GetImageData(const std::shared_ptr<Ace::ImageData> & imageData)157 void OffscreenCanvasPaintMethod::GetImageData(const std::shared_ptr<Ace::ImageData>& imageData)
158 {
159 int32_t dirtyWidth = std::abs(imageData->dirtyWidth);
160 int32_t dirtyHeight = std::abs(imageData->dirtyHeight);
161 double scaledLeft = imageData->dirtyX + std::min(imageData->dirtyWidth, 0);
162 double scaledTop = imageData->dirtyY + std::min(imageData->dirtyHeight, 0);
163 double dx = std::min(scaledLeft, 0.0);
164 double dy = std::min(scaledTop, 0.0);
165 // copy the bitmap to tempCanvas
166 RSBitmap subBitmap;
167 auto rect = RSRect(scaledLeft, scaledTop, dirtyWidth + scaledLeft, dirtyHeight + scaledTop);
168 bool ret = bitmap_.ExtractSubset(subBitmap, rect);
169 if (!ret) {
170 return;
171 }
172 auto pixelMap = imageData->pixelMap;
173 CHECK_NULL_VOID(pixelMap);
174 auto* rawData = pixelMap->GetWritablePixels();
175 CHECK_NULL_VOID(rawData);
176 RSImageInfo imageInfo =
177 RSImageInfo(dirtyWidth, dirtyHeight, RSColorType::COLORTYPE_RGBA_8888, RSAlphaType::ALPHATYPE_PREMUL);
178 subBitmap.ReadPixels(imageInfo, rawData, dirtyWidth * imageInfo.GetBytesPerPixel(), dx, dy);
179 }
180
ToDataURL(const std::string & type,const double quality)181 std::string OffscreenCanvasPaintMethod::ToDataURL(const std::string& type, const double quality)
182 {
183 #ifndef ACE_UNITTEST
184 std::string mimeType = GetMimeType(type);
185 // Quality needs to be between 0.0 and 1.0 for MimeType jpeg and webp
186 double qua = GetQuality(mimeType, quality);
187 auto imageInfo = SkImageInfo::Make(width_, height_, SkColorType::kBGRA_8888_SkColorType,
188 (mimeType == IMAGE_JPEG) ? SkAlphaType::kOpaque_SkAlphaType : SkAlphaType::kUnpremul_SkAlphaType);
189 RSBitmap tempCache;
190 tempCache.Build(width_, height_,
191 { RSColorType::COLORTYPE_BGRA_8888,
192 (mimeType == IMAGE_JPEG) ? RSAlphaType::ALPHATYPE_OPAQUE : RSAlphaType::ALPHATYPE_UNPREMUL });
193 RSCanvas tempCanvas;
194 tempCanvas.Bind(tempCache);
195 tempCanvas.Clear(RSColor::COLOR_TRANSPARENT);
196 tempCanvas.Scale(1.0, 1.0);
197 tempCanvas.DrawBitmap(bitmap_, 0.0f, 0.0f);
198 RSPixmap rsSrc;
199 bool success = tempCache.PeekPixels(rsSrc);
200 CHECK_NULL_RETURN(success, UNSUPPORTED);
201 SkPixmap src { imageInfo, rsSrc.GetAddr(), rsSrc.GetRowBytes() };
202 SkDynamicMemoryWStream dst;
203 success = EncodeImage(mimeType, qua, src, dst);
204 CHECK_NULL_RETURN(success, UNSUPPORTED);
205 auto result = dst.detachAsData();
206 CHECK_NULL_RETURN(result, UNSUPPORTED);
207 size_t len = SkBase64::Encode(result->data(), result->size(), nullptr);
208 if (len > MAX_LENGTH) {
209 return UNSUPPORTED;
210 }
211 SkString info(len);
212 SkBase64::Encode(result->data(), result->size(), info.writable_str());
213 return std::string(URL_PREFIX).append(mimeType).append(URL_SYMBOL).append(info.c_str());
214 #else
215 return UNSUPPORTED;
216 #endif
217 }
218
GetTransform() const219 TransformParam OffscreenCanvasPaintMethod::GetTransform() const
220 {
221 TransformParam param;
222 CHECK_NULL_RETURN(rsCanvas_, param);
223 RSMatrix matrix = rsCanvas_->GetTotalMatrix();
224 param.scaleX = matrix.Get(RSMatrix::SCALE_X);
225 param.scaleY = matrix.Get(RSMatrix::SCALE_Y);
226 param.skewX = matrix.Get(RSMatrix::SKEW_X);
227 param.skewY = matrix.Get(RSMatrix::SKEW_Y);
228 param.translateX = matrix.Get(RSMatrix::TRANS_X);
229 param.translateY = matrix.Get(RSMatrix::TRANS_Y);
230 return param;
231 }
232
GetLineDash() const233 LineDashParam OffscreenCanvasPaintMethod::GetLineDash() const
234 {
235 return state_.strokeState.GetLineDash();
236 }
237
238 #ifndef ACE_UNITTEST
ConvertTxtStyle(const TextStyle & textStyle,Rosen::TextStyle & txtStyle)239 void OffscreenCanvasPaintMethod::ConvertTxtStyle(const TextStyle& textStyle, Rosen::TextStyle& txtStyle)
240 {
241 Constants::ConvertTxtStyle(textStyle, txtStyle);
242 }
243 #endif
244 } // namespace OHOS::Ace::NG
245