1 /*
2 * Copyright 2015 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 <cstdio>
9 #include <cstdlib>
10 #include <sstream>
11 #include <string>
12
13 #include "fiddle_main.h"
14
15 // Globals externed in fiddle_main.h
16 SkBitmap source;
17 sk_sp<SkImage> image;
18
19 // Global used by the local impl of SkDebugf.
20 std::ostringstream gTextOutput;
21
SkDebugf(const char * fmt,...)22 void SkDebugf(const char * fmt, ...) {
23 va_list args;
24 va_start(args, fmt);
25 char formatbuffer[1024];
26 int n = vsnprintf(formatbuffer, sizeof(formatbuffer), fmt, args);
27 va_end(args);
28 if (n>=0 && n<=int(sizeof(formatbuffer))) {
29 gTextOutput.write(formatbuffer, n);
30 }
31 }
32
encode_to_base64(const void * data,size_t size,FILE * out)33 static void encode_to_base64(const void* data, size_t size, FILE* out) {
34 const uint8_t* input = reinterpret_cast<const uint8_t*>(data);
35 const uint8_t* end = &input[size];
36 static const char codes[] =
37 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
38 "abcdefghijklmnopqrstuvwxyz0123456789+/";
39 while (input != end) {
40 uint8_t b = (*input & 0xFC) >> 2;
41 fputc(codes[b], out);
42 b = (*input & 0x03) << 4;
43 ++input;
44 if (input == end) {
45 fputc(codes[b], out);
46 fputs("==", out);
47 return;
48 }
49 b |= (*input & 0xF0) >> 4;
50 fputc(codes[b], out);
51 b = (*input & 0x0F) << 2;
52 ++input;
53 if (input == end) {
54 fputc(codes[b], out);
55 fputc('=', out);
56 return;
57 }
58 b |= (*input & 0xC0) >> 6;
59 fputc(codes[b], out);
60 b = *input & 0x3F;
61 fputc(codes[b], out);
62 ++input;
63 }
64 }
65
66
dump_output(const void * data,size_t size,const char * name,bool last=true)67 static void dump_output(const void* data, size_t size,
68 const char* name, bool last = true) {
69 printf("\t\"%s\": \"", name);
70 encode_to_base64(data, size, stdout);
71 fputs(last ? "\"\n" : "\",\n", stdout);
72 }
73
dump_output(const sk_sp<SkData> & data,const char * name,bool last=true)74 static void dump_output(const sk_sp<SkData>& data,
75 const char* name, bool last = true) {
76 if (data) {
77 dump_output(data->data(), data->size(), name, last);
78 }
79 }
80
encode_snapshot(const sk_sp<SkSurface> & surface)81 static SkData* encode_snapshot(const sk_sp<SkSurface>& surface) {
82 sk_sp<SkImage> img(surface->makeImageSnapshot());
83 return img ? img->encode() : nullptr;
84 }
85
86 #if defined(__linux) && !defined(__ANDROID__)
87 #include <GL/osmesa.h>
create_grcontext()88 static sk_sp<GrContext> create_grcontext() {
89 // We just leak the OSMesaContext... the process will die soon anyway.
90 if (OSMesaContext osMesaContext = OSMesaCreateContextExt(OSMESA_BGRA, 0, 0, 0, nullptr)) {
91 static uint32_t buffer[16 * 16];
92 OSMesaMakeCurrent(osMesaContext, &buffer, GL_UNSIGNED_BYTE, 16, 16);
93 }
94
95 auto osmesa_get = [](void* ctx, const char name[]) {
96 SkASSERT(nullptr == ctx);
97 SkASSERT(OSMesaGetCurrentContext());
98 return OSMesaGetProcAddress(name);
99 };
100 sk_sp<const GrGLInterface> mesa(GrGLAssembleInterface(nullptr, osmesa_get));
101 if (!mesa) {
102 return nullptr;
103 }
104 return sk_sp<GrContext>(GrContext::Create(
105 kOpenGL_GrBackend,
106 reinterpret_cast<intptr_t>(mesa.get())));
107 }
108 #else
create_grcontext()109 static sk_sp<GrContext> create_grcontext() { return nullptr; }
110 #endif
111
112
113
main()114 int main() {
115 DrawOptions options = GetDrawOptions();
116 // If textOnly then only do one type of image, otherwise the text
117 // output is duplicated for each type.
118 if (options.textOnly) {
119 options.raster = true;
120 options.gpu = false;
121 options.pdf = false;
122 options.skp = false;
123 }
124 if (options.source) {
125 sk_sp<SkData> data(SkData::MakeFromFileName(options.source));
126 if (!data) {
127 perror(options.source);
128 return 1;
129 } else {
130 image = SkImage::MakeFromEncoded(std::move(data));
131 if (!image) {
132 perror("Unable to decode the source image.");
133 return 1;
134 }
135 SkAssertResult(image->asLegacyBitmap(
136 &source, SkImage::kRO_LegacyBitmapMode));
137 }
138 }
139 sk_sp<SkData> rasterData, gpuData, pdfData, skpData;
140 SkColorType colorType = kN32_SkColorType;
141 sk_sp<SkColorSpace> colorSpace = nullptr;
142 if (options.f16) {
143 SkASSERT(options.srgb);
144 colorType = kRGBA_F16_SkColorType;
145 colorSpace = SkColorSpace::MakeSRGBLinear();
146 } else if (options.srgb) {
147 colorSpace = SkColorSpace::MakeSRGB();
148 }
149 SkImageInfo info = SkImageInfo::Make(options.size.width(), options.size.height(), colorType,
150 kPremul_SkAlphaType, colorSpace);
151 if (options.raster) {
152 auto rasterSurface = SkSurface::MakeRaster(info);
153 srand(0);
154 draw(rasterSurface->getCanvas());
155 rasterData.reset(encode_snapshot(rasterSurface));
156 }
157 if (options.gpu) {
158 auto grContext = create_grcontext();
159 if (!grContext) {
160 fputs("Unable to get GrContext.\n", stderr);
161 } else {
162 auto surface = SkSurface::MakeRenderTarget(grContext.get(), SkBudgeted::kNo, info);
163 if (!surface) {
164 fputs("Unable to get render surface.\n", stderr);
165 exit(1);
166 }
167 srand(0);
168 draw(surface->getCanvas());
169 gpuData.reset(encode_snapshot(surface));
170 }
171 }
172 if (options.pdf) {
173 SkDynamicMemoryWStream pdfStream;
174 sk_sp<SkDocument> document(SkDocument::MakePDF(&pdfStream));
175 if (document) {
176 srand(0);
177 draw(document->beginPage(options.size.width(), options.size.height()));
178 document->close();
179 pdfData = pdfStream.detachAsData();
180 }
181 }
182 if (options.skp) {
183 SkSize size;
184 size = options.size;
185 SkPictureRecorder recorder;
186 srand(0);
187 draw(recorder.beginRecording(size.width(), size.height()));
188 auto picture = recorder.finishRecordingAsPicture();
189 SkDynamicMemoryWStream skpStream;
190 picture->serialize(&skpStream);
191 skpData = skpStream.detachAsData();
192 }
193
194 printf("{\n");
195 if (!options.textOnly) {
196 dump_output(rasterData, "Raster", !gpuData && !pdfData && !skpData);
197 dump_output(gpuData, "Gpu", !pdfData && !skpData);
198 dump_output(pdfData, "Pdf", !skpData);
199 dump_output(skpData, "Skp");
200 } else {
201 std::string textoutput = gTextOutput.str();
202 dump_output(textoutput.c_str(), textoutput.length(), "Text");
203 }
204 printf("}\n");
205
206 return 0;
207 }
208