OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include <stdio.h> | 8 // c++ --std=c++11 coreGraphicsPdf2png.cpp -o coreGraphicsPdf2png -framework A
pplicationServices |
9 | 9 |
10 #include "SkBitmap.h" | 10 #include <cstdio> |
11 #include "SkCGUtils.h" | 11 #include <memory> |
12 #include "SkForceLinking.h" | |
13 #include "SkImageEncoder.h" | |
14 #include "SkStream.h" | |
15 | 12 |
16 __SK_FORCE_IMAGE_DECODER_LINKING; | 13 #include <ApplicationServices/ApplicationServices.h> |
17 | 14 |
18 class StdOutWStream : public SkWStream { | 15 #define ASSERT(x) \ |
19 public: | 16 do { \ |
20 StdOutWStream() : fBytesWritten(0) {} | 17 if (!(x)) { \ |
21 bool write(const void* buffer, size_t size) final { | 18 fprintf(stderr, "ERROR: " __FILE__ \ |
22 fBytesWritten += size; | 19 ":%d (%s)\n", __LINE__, #x); \ |
23 return size == fwrite(buffer, 1, size, stdout); | 20 return 1; \ |
| 21 } \ |
| 22 } while (false) \ |
| 23 |
| 24 const int PAGE = 1; |
| 25 |
| 26 int main(int argc, char** argv) { |
| 27 if (argc <= 1 || !*(argv[1]) || 0 == strcmp(argv[1], "-")) { |
| 28 fprintf(stderr, "usage:\n\t%s INPUT_PDF_FILE_PATH [OUTPUT_PNG_PATH]\n",
argv[0]); |
| 29 return 1; |
24 } | 30 } |
25 size_t bytesWritten() const final { return fBytesWritten; } | 31 const char* output = argc > 2 ? argv[2] : nullptr; |
26 | 32 CGDataProviderRef data = CGDataProviderCreateWithFilename(argv[1]); |
27 private: | 33 ASSERT(data); |
28 size_t fBytesWritten; | 34 CGPDFDocumentRef pdf = CGPDFDocumentCreateWithProvider(data); |
29 }; | 35 CGDataProviderRelease(data); |
30 | 36 ASSERT(pdf); |
31 static SkStreamAsset* open_for_reading(const char* path) { | 37 CGPDFPageRef page = CGPDFDocumentGetPage(pdf, PAGE); |
32 if (!path || !path[0] || 0 == strcmp(path, "-")) { | 38 ASSERT(page); |
33 return new SkFILEStream(stdin, SkFILEStream::kCallerRetains_Ownership); | 39 CGRect bounds = CGPDFPageGetBoxRect(page, kCGPDFMediaBox); |
34 } | 40 int w = (int)CGRectGetWidth(bounds); |
35 return SkStream::NewFromFile(path); | 41 int h = (int)CGRectGetHeight(bounds); |
| 42 CGBitmapInfo info = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast
; |
| 43 CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB(); |
| 44 ASSERT(cs); |
| 45 std::unique_ptr<uint32_t[]> bitmap(new uint32_t[w * h]); |
| 46 memset(bitmap.get(), 0xFF, 4 * w * h); |
| 47 CGContextRef ctx = CGBitmapContextCreate(bitmap.get(), w, h, 8, w * 4, cs, i
nfo); |
| 48 ASSERT(ctx); |
| 49 CGContextDrawPDFPage(ctx, page); |
| 50 CGPDFDocumentRelease(pdf); |
| 51 CGImageRef image = CGBitmapContextCreateImage(ctx); |
| 52 ASSERT(image); |
| 53 CGDataConsumerCallbacks procs; |
| 54 procs.putBytes = [](void* f, const void* buf, size_t s) { |
| 55 return fwrite(buf, 1, s, (FILE*)f); |
| 56 }; |
| 57 procs.releaseConsumer = [](void* info) { fclose((FILE*)info); }; |
| 58 FILE* ofile = (!output || !output[0] || 0 == strcmp(output, "-")) |
| 59 ? stdout : fopen(output, "wb"); |
| 60 ASSERT(ofile); |
| 61 CGDataConsumerRef consumer = CGDataConsumerCreate(ofile, &procs); |
| 62 ASSERT(consumer); |
| 63 CGImageDestinationRef dst = |
| 64 CGImageDestinationCreateWithDataConsumer(consumer, kUTTypePNG, 1, nullpt
r); |
| 65 CFRelease(consumer); |
| 66 ASSERT(dst); |
| 67 CGImageDestinationAddImage(dst, image, nullptr); |
| 68 ASSERT(CGImageDestinationFinalize(dst)); |
| 69 CFRelease(dst); |
| 70 CGImageRelease(image); |
| 71 CGColorSpaceRelease(cs); |
| 72 CGContextRelease(ctx); |
| 73 return 0; |
36 } | 74 } |
37 | 75 |
38 static SkWStream* open_for_writing(const char* path) { | |
39 if (!path || !path[0] || 0 == strcmp(path, "-")) { | |
40 return new StdOutWStream; | |
41 } | |
42 return new SkFILEWStream(path); | |
43 } | |
44 | 76 |
45 static bool to_png(SkWStream* o, const SkBitmap& bm) { | |
46 return SkImageEncoder::EncodeStream(o, bm, SkImageEncoder::kPNG_Type, 100); | |
47 } | |
48 | |
49 // Note: I could implement this using only MacOS|CG API calls, but | |
50 // since most of this is already done in Skia, here it is. | |
51 int main(int argc, char** argv) { | |
52 SkBitmap bm; | |
53 SkAutoTDelete<SkStream> in(open_for_reading(argc > 1 ? argv[1] : NULL)); | |
54 SkAutoTDelete<SkWStream> out(open_for_writing(argc > 2 ? argv[2] : NULL)); | |
55 if (SkPDFDocumentToBitmap(in.release(), &bm) && to_png(out, bm)) { | |
56 return 0; | |
57 } else { | |
58 return 1; | |
59 } | |
60 } | |
OLD | NEW |