• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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