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 <cstdint>
17 #include <cstdlib>
18 #include <cstring>
19 #include <iostream>
20 #include <sstream>
21 #include "display_type.h"
22 #include "draw/canvas.h"
23 #include "draw/color.h"
24 #include "graphic_common.h"
25 #include "image/bitmap.h"
26 #include "include/core/SkColor.h"
27 #include "pixel_map.h"
28 #include "png.h"
29 #include "render_context/render_context.h"
30 #include "surface_type.h"
31 #include "transaction/rs_interfaces.h"
32 #include "transaction/rs_transaction.h"
33 #include "ui/rs_display_node.h"
34 #include "ui/rs_ui_director.h"
35 #include "ui/rs_root_node.h"
36 #include "ui/rs_surface_node.h"
37 #include "ui/rs_surface_extractor.h"
38 #include "window.h"
39
40 using namespace OHOS;
41 using namespace OHOS::Rosen;
42 using namespace OHOS::Rosen::Drawing;
43 using namespace std;
44
45 using WriteToPngParam = struct {
46 uint32_t width;
47 uint32_t height;
48 uint32_t stride;
49 uint32_t bitDepth;
50 const uint8_t *data;
51 };
52
53 constexpr int BITMAP_DEPTH = 8;
54
55 shared_ptr<RSNode> rootNode;
56 shared_ptr<RSCanvasNode> canvasNode;
57 shared_ptr<RSCanvasNode> canvasNode2;
58 shared_ptr<RSSurfaceNode> surfaceNode1;
59 shared_ptr<RSSurfaceNode> surfaceNode2;
60
61 #ifdef RS_ENABLE_GPU
62 RenderContext* rc_ = nullptr;
63 #endif
64
WriteToPng(const string & fileName,const WriteToPngParam & param)65 bool WriteToPng(const string &fileName, const WriteToPngParam ¶m)
66 {
67 png_structp pngStruct = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
68 if (pngStruct == nullptr) {
69 cout << "png_create_write_struct error, nullptr!" << endl;
70 return false;
71 }
72 png_infop pngInfo = png_create_info_struct(pngStruct);
73 if (pngInfo == nullptr) {
74 cout << "png_create_info_struct error, nullptr!" <<endl;
75 png_destroy_write_struct(&pngStruct, nullptr);
76 return false;
77 }
78 FILE *fp = fopen(fileName.c_str(), "wb");
79 if (fp == nullptr) {
80 cout << "open file error, nullptr!" << endl;
81 png_destroy_write_struct(&pngStruct, &pngInfo);
82 return false;
83 }
84 png_init_io(pngStruct, fp);
85
86 // set png header
87 png_set_IHDR(pngStruct, pngInfo,
88 param.width, param.height,
89 param.bitDepth,
90 PNG_COLOR_TYPE_RGBA,
91 PNG_INTERLACE_NONE,
92 PNG_COMPRESSION_TYPE_BASE,
93 PNG_FILTER_TYPE_BASE);
94 png_set_packing(pngStruct); // set packing info
95 png_write_info(pngStruct, pngInfo); // write to header
96
97 for (uint32_t i = 0; i < param.height; i++) {
98 png_write_row(pngStruct, param.data + (i * param.stride));
99 }
100
101 png_write_end(pngStruct, pngInfo);
102
103 // free
104 png_destroy_write_struct(&pngStruct, &pngInfo);
105 int ret = fclose(fp);
106 if (ret != 0) {
107 cout << "close fp failed" << endl;
108 }
109 return true;
110 }
111
RenderContextInit()112 void RenderContextInit()
113 {
114 #ifdef RS_ENABLE_GPU
115 cout << "RS_ENABLE_GPU is true" << endl;
116 cout << "Init RenderContext start" << endl;
117 rc_ = RenderContextFactory::GetInstance().CreateEngine();
118 if (rc_) {
119 cout << "Init RenderContext success" << endl;
120 rc_->InitializeEglContext();
121 } else {
122 cout << "Init RenderContext failed, RenderContext is nullptr" << endl;
123 }
124 #endif
125 }
126
DrawSurfaceNode(shared_ptr<RSSurfaceNode> surfaceNode)127 void DrawSurfaceNode(shared_ptr<RSSurfaceNode> surfaceNode)
128 {
129 SkRect surfaceGeometry = SkRect::MakeXYWH(100, 50, 300, 600);
130 auto x = surfaceGeometry.x();
131 auto y = surfaceGeometry.y();
132 auto width = surfaceGeometry.width();
133 auto height = surfaceGeometry.height();
134 surfaceNode->SetBounds(x, y, width, height);
135 shared_ptr<RSSurface> rsSurface = RSSurfaceExtractor::ExtractRSSurface(surfaceNode);
136 if (rsSurface == nullptr) {
137 cout << "surface is nullptr" << endl;
138 return;
139 }
140 #ifdef RS_ENABLE_GPU
141 if (rc_) {
142 rsSurface->SetRenderContext(rc_);
143 } else {
144 cout << "DrawSurface: RenderContext is nullptr" << endl;
145 }
146 #endif
147 auto framePtr = rsSurface->RequestFrame(width, height);
148 if (!framePtr) {
149 cout << "framePtr is nullptr" << endl;
150 return;
151 }
152 auto canvas = framePtr->GetCanvas();
153 if (!canvas) {
154 cout << "canvas is nullptr" << endl;
155 return;
156 }
157 canvas->Сlear(SK_ColorWHITE);
158
159 Brush brush;
160 brush.SetColor(SK_ColorGREEN);
161 brush.SetAntiAlias(true);
162
163 string scaleInfo = "Hello World";
164 Font font = Font();
165 font.SetSize(16); // text size 16
166 std::shared_ptr<TextBlob> scaleInfoTextBlob = TextBlob::MakeFromString(scaleInfo.c_str(),
167 font, TextEncoding::UTF8);
168 canvas->AttachBrush(brush);
169 canvas->DrawTextBlob(scaleInfoTextBlob.get(), 20, 50); // start point is (20, 50)
170 canvas->DetachBrush();
171 framePtr->SetDamageRegion(0, 0, width, height);
172 rsSurface->FlushFrame(framePtr);
173 return;
174 }
175
WriteToPngWithPixelMap(const string & fileName,Media::PixelMap & pixelMap)176 bool WriteToPngWithPixelMap(const string &fileName, Media::PixelMap &pixelMap)
177 {
178 WriteToPngParam param;
179 param.width = static_cast<uint32_t>(pixelMap.GetWidth());
180 param.height = static_cast<uint32_t>(pixelMap.GetHeight());
181 param.data = pixelMap.GetPixels();
182 param.stride = static_cast<uint32_t>(pixelMap.GetRowBytes());
183 param.bitDepth = BITMAP_DEPTH;
184 return WriteToPng(fileName, param);
185 }
186
Init(shared_ptr<RSUIDirector> rsUiDirector,int width,int height)187 void Init(shared_ptr<RSUIDirector> rsUiDirector, int width, int height)
188 {
189 cout << "rs local surface capture demo Init Rosen Backend!" << endl;
190
191 rootNode = RSRootNode::Create();
192 rootNode->SetBounds(0, 0, width, height);
193 rootNode->SetFrame(0, 0, width, height);
194 rootNode->SetBackgroundColor(SK_ColorRED);
195
196 rsUiDirector->SetRoot(rootNode->GetId());
197 canvasNode = RSCanvasNode::Create();
198 canvasNode->SetBounds(10, 10, 600, 1000);
199 canvasNode->SetFrame(10, 10, 600, 1000);
200 canvasNode->SetBackgroundColor(SK_ColorYELLOW);
201 rootNode->AddChild(canvasNode, -1);
202
203 canvasNode2 = RSCanvasNode::Create();
204 canvasNode2->SetBounds(5, 5, 400, 800);
205 canvasNode2->SetFrame(5, 5, 400, 800);
206 canvasNode2->SetBackgroundColor(SK_ColorBLUE);
207 canvasNode->AddChild(canvasNode2, -1);
208
209 RSSurfaceNodeConfig config;
210 surfaceNode1 = RSSurfaceNode::Create(config, false);
211 RenderContextInit();
212 DrawSurfaceNode(surfaceNode1);
213 canvasNode2->AddChild(surfaceNode1, -1);
214 }
215
216 class MyOffscreenRenderCallback : public SurfaceCaptureCallback {
217 public:
OnSurfaceCapture(std::shared_ptr<Media::PixelMap> pixelmap)218 void OnSurfaceCapture(std::shared_ptr<Media::PixelMap> pixelmap) override
219 {
220 if (pixelmap == nullptr) {
221 cout << "RSUIDirector::LocalCapture failed to get pixelmap, return nullptr!" << endl;
222 return;
223 }
224 cout << "rs local surface demo drawPNG" << endl;
225 int ret = WriteToPngWithPixelMap("/data/local/test.jpg", *pixelmap);
226 if (!ret) {
227 cout << "pixelmap write to png failed" << endl;
228 }
229 cout << "pixelmap write to png sucess" << endl;
230 }
231 };
232
main()233 int main()
234 {
235 cout << "rs local surface capture demo" << endl;
236 sptr<WindowOption> option = new WindowOption();
237 option->SetWindowType(WindowType::WINDOW_TYPE_FLOAT);
238 option->SetWindowMode(WindowMode::WINDOW_MODE_FLOATING);
239 option->SetWindowRect({0, 0, 680, 1100});
240 string demoName = "offscreen_render_demo";
241 auto window = Window::Create(demoName, option);
242
243 window->Show();
244 auto rect = window->GetRect();
245 while (rect.width_ == 0 && rect.height_ == 0) {
246 cout << "rs local surface demo create window failed: " << rect.width_ << " " << rect.height_ << endl;
247 window->Hide();
248 window->Destroy();
249 window = Window::Create(demoName, option);
250 window->Show();
251 rect = window->GetRect();
252 }
253 cout << "rs local surface demo create window success: " << rect.width_ << " " << rect.height_ << endl;
254 auto surfaceNode = window->GetSurfaceNode();
255
256 auto rsUiDirector = RSUIDirector::Create();
257 rsUiDirector->Init();
258 RSTransaction::FlushImplicitTransaction();
259
260 cout << "rs local surface demo init" << endl;
261 rsUiDirector->SetRSSurfaceNode(surfaceNode);
262 Init(rsUiDirector, rect.width_, rect.height_);
263 rsUiDirector->SendMessages();
264 sleep(4);
265
266 cout << "rs local surface demo cratePixelMap" << endl;
267 std::shared_ptr<MyOffscreenRenderCallback> myOffscreenRenderCallback =
268 std::make_shared<MyOffscreenRenderCallback>();
269 cout << "rootNode id is" << rootNode->GetId() << endl;
270 RSInterfaces::GetInstance().TakeSurfaceCaptureForUI(rootNode, myOffscreenRenderCallback, 1, 1);
271 sleep(2);
272 rootNode->RemoveFromTree();
273 RSInterfaces::GetInstance().TakeSurfaceCaptureForUI(rootNode, myOffscreenRenderCallback, 1, 1);
274 sleep(2);
275 return 0;
276 }
277