1 /*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "Request.h"
9
10 #include "png.h"
11
12 const int Request::kImageWidth = 1920;
13 const int Request::kImageHeight = 1080;
14
write_png_callback(png_structp png_ptr,png_bytep data,png_size_t length)15 static void write_png_callback(png_structp png_ptr, png_bytep data, png_size_t length) {
16 SkWStream* out = (SkWStream*) png_get_io_ptr(png_ptr);
17 out->write(data, length);
18 }
19
write_png(const png_bytep rgba,png_uint_32 width,png_uint_32 height,SkWStream & out)20 static void write_png(const png_bytep rgba, png_uint_32 width, png_uint_32 height, SkWStream& out) {
21 png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
22 SkASSERT(png != nullptr);
23 png_infop info_ptr = png_create_info_struct(png);
24 SkASSERT(info_ptr != nullptr);
25 if (setjmp(png_jmpbuf(png))) {
26 SkFAIL("png encode error");
27 }
28 png_set_IHDR(png, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
29 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
30 png_set_compression_level(png, 1);
31 png_bytepp rows = (png_bytepp) sk_malloc_throw(height * sizeof(png_byte*));
32 png_bytep pixels = (png_bytep) sk_malloc_throw(width * height * 3);
33 for (png_size_t y = 0; y < height; ++y) {
34 const png_bytep src = rgba + y * width * 4;
35 rows[y] = pixels + y * width * 3;
36 // convert from RGBA to RGB
37 for (png_size_t x = 0; x < width; ++x) {
38 rows[y][x * 3] = src[x * 4];
39 rows[y][x * 3 + 1] = src[x * 4 + 1];
40 rows[y][x * 3 + 2] = src[x * 4 + 2];
41 }
42 }
43 png_set_filter(png, 0, PNG_NO_FILTERS);
44 png_set_rows(png, info_ptr, &rows[0]);
45 png_set_write_fn(png, &out, write_png_callback, NULL);
46 png_write_png(png, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
47 png_destroy_write_struct(&png, NULL);
48 sk_free(rows);
49 }
50
getBitmapFromCanvas(SkCanvas * canvas)51 SkBitmap* Request::getBitmapFromCanvas(SkCanvas* canvas) {
52 SkBitmap* bmp = new SkBitmap();
53 SkImageInfo info = SkImageInfo::Make(kImageWidth, kImageHeight, kRGBA_8888_SkColorType,
54 kOpaque_SkAlphaType);
55 bmp->setInfo(info);
56 if (!canvas->readPixels(bmp, 0, 0)) {
57 fprintf(stderr, "Can't read pixels\n");
58 return nullptr;
59 }
60 return bmp;
61 }
62
writeCanvasToPng(SkCanvas * canvas)63 SkData* Request::writeCanvasToPng(SkCanvas* canvas) {
64 // capture pixels
65 SkAutoTDelete<SkBitmap> bmp(getBitmapFromCanvas(canvas));
66 SkASSERT(bmp);
67
68 // write to png
69 SkDynamicMemoryWStream buffer;
70 write_png((const png_bytep) bmp->getPixels(), bmp->width(), bmp->height(), buffer);
71 return buffer.copyToData();
72 }
73
getCanvas()74 SkCanvas* Request::getCanvas() {
75 GrContextFactory* factory = fContextFactory;
76 SkGLContext* gl = factory->getContextInfo(GrContextFactory::kNative_GLContextType,
77 GrContextFactory::kNone_GLContextOptions).fGLContext;
78 gl->makeCurrent();
79 SkASSERT(fDebugCanvas);
80 SkCanvas* target = fSurface->getCanvas();
81 return target;
82 }
83
drawToCanvas(int n)84 void Request::drawToCanvas(int n) {
85 SkCanvas* target = this->getCanvas();
86 fDebugCanvas->drawTo(target, n);
87 }
88
drawToPng(int n)89 SkData* Request::drawToPng(int n) {
90 this->drawToCanvas(n);
91 return writeCanvasToPng(this->getCanvas());
92 }
93
createCPUSurface()94 SkSurface* Request::createCPUSurface() {
95 SkImageInfo info = SkImageInfo::Make(kImageWidth, kImageHeight, kN32_SkColorType,
96 kPremul_SkAlphaType);
97 return SkSurface::NewRaster(info);
98 }
99
createGPUSurface()100 SkSurface* Request::createGPUSurface() {
101 GrContext* context = fContextFactory->get(GrContextFactory::kNative_GLContextType,
102 GrContextFactory::kNone_GLContextOptions);
103 int maxRTSize = context->caps()->maxRenderTargetSize();
104 SkImageInfo info = SkImageInfo::Make(SkTMin(kImageWidth, maxRTSize),
105 SkTMin(kImageHeight, maxRTSize),
106 kN32_SkColorType, kPremul_SkAlphaType);
107 uint32_t flags = 0;
108 SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
109 SkSurface* surface = SkSurface::NewRenderTarget(context, SkBudgeted::kNo, info, 0,
110 &props);
111 return surface;
112 }
113
114