OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 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 "SkCanvas.h" | 8 #include "SkCanvas.h" |
9 #include "SkDevice.h" | 9 #include "SkDevice.h" |
10 #include "SkForceLinking.h" | 10 #include "SkForceLinking.h" |
(...skipping 27 matching lines...) Expand all Loading... |
38 /* | 38 /* |
39 #ifdef PDF_TRACE | 39 #ifdef PDF_TRACE |
40 std::string str; | 40 std::string str; |
41 pdfContext->fGraphicsState.fResources->native()->ToString(str); | 41 pdfContext->fGraphicsState.fResources->native()->ToString(str); |
42 printf("Print Tf Resources: %s\n", str.c_str()); | 42 printf("Print Tf Resources: %s\n", str.c_str()); |
43 #endif | 43 #endif |
44 */ | 44 */ |
45 | 45 |
46 #include "SkPdfHeaders_autogen.h" | 46 #include "SkPdfHeaders_autogen.h" |
47 #include "SkPdfMapper_autogen.h" | 47 #include "SkPdfMapper_autogen.h" |
48 #include "SkPdfParser.h" | 48 #include "SkPdfRenderer.h" |
49 | 49 |
50 #include "SkPdfBasics.h" | 50 #include "SkPdfBasics.h" |
51 #include "SkPdfUtils.h" | 51 #include "SkPdfUtils.h" |
52 | 52 |
53 #include "SkPdfFont.h" | 53 #include "SkPdfFont.h" |
54 | 54 |
55 /* | 55 /* |
56 * TODO(edisonn): | 56 * TODO(edisonn): |
57 * - all font types and all ppdf font features | 57 * - all font types and all ppdf font features |
58 * - word spacing | 58 * - word spacing |
59 * - load font for baidu.pdf | 59 * - load font for baidu.pdf |
60 * - load font for youtube.pdf | 60 * - load font for youtube.pdf |
61 * - parser for pdf from the definition already available in pdfspec_autoge
n.py | 61 * - parser for pdf from the definition already available in pdfspec_autoge
n.py |
62 * - all docs from ~/work | 62 * - all docs from ~/work |
63 * - encapsulate native in the pdf api so the skpdf does not know anything about
native ... in progress | 63 * - encapsulate native in the pdf api so the skpdf does not know anything about
native ... in progress |
64 * - load gs/ especially smask and already known prop (skp) ... in progress | 64 * - load gs/ especially smask and already known prop (skp) ... in progress |
65 * - wrapper on classes for customizations? e.g. | 65 * - wrapper on classes for customizations? e.g. |
66 * SkPdfPageObjectVanila - has only the basic loaders/getters | 66 * SkPdfPageObjectVanila - has only the basic loaders/getters |
67 * SkPdfPageObject : public SkPdfPageObjectVanila, extends, and I can add custom
izations here | 67 * SkPdfPageObject : public SkPdfPageObjectVanila, extends, and I can add custom
izations here |
68 * need to find a nice object model for all this with constructors and factories | 68 * need to find a nice object model for all this with constructors and factories |
69 * - deal with inheritable automatically ? | 69 * - deal with inheritable automatically ? |
70 * - deal with specific type in spec directly, add all dictionary types to known
types | 70 * - deal with specific type in spec directly, add all dictionary types to known
types |
71 */ | 71 */ |
72 | 72 |
73 using namespace std; | 73 using namespace std; |
74 | 74 |
| 75 |
| 76 |
| 77 // TODO(edisonn): Document PdfTokenLooper and subclasses. |
| 78 class PdfTokenLooper { |
| 79 protected: |
| 80 PdfTokenLooper* fParent; |
| 81 SkPdfNativeTokenizer* fTokenizer; |
| 82 PdfContext* fPdfContext; |
| 83 SkCanvas* fCanvas; |
| 84 |
| 85 public: |
| 86 PdfTokenLooper(PdfTokenLooper* parent, |
| 87 SkPdfNativeTokenizer* tokenizer, |
| 88 PdfContext* pdfContext, |
| 89 SkCanvas* canvas) |
| 90 : fParent(parent), fTokenizer(tokenizer), fPdfContext(pdfContext), fCanv
as(canvas) {} |
| 91 |
| 92 virtual ~PdfTokenLooper() {} |
| 93 |
| 94 virtual PdfResult consumeToken(PdfToken& token) = 0; |
| 95 virtual void loop() = 0; |
| 96 |
| 97 void setUp(PdfTokenLooper* parent) { |
| 98 fParent = parent; |
| 99 fTokenizer = parent->fTokenizer; |
| 100 fPdfContext = parent->fPdfContext; |
| 101 fCanvas = parent->fCanvas; |
| 102 } |
| 103 }; |
| 104 |
| 105 class PdfMainLooper : public PdfTokenLooper { |
| 106 public: |
| 107 PdfMainLooper(PdfTokenLooper* parent, |
| 108 SkPdfNativeTokenizer* tokenizer, |
| 109 PdfContext* pdfContext, |
| 110 SkCanvas* canvas) |
| 111 : PdfTokenLooper(parent, tokenizer, pdfContext, canvas) {} |
| 112 |
| 113 virtual PdfResult consumeToken(PdfToken& token); |
| 114 virtual void loop(); |
| 115 }; |
| 116 |
| 117 class PdfInlineImageLooper : public PdfTokenLooper { |
| 118 public: |
| 119 PdfInlineImageLooper() |
| 120 : PdfTokenLooper(NULL, NULL, NULL, NULL) {} |
| 121 |
| 122 virtual PdfResult consumeToken(PdfToken& token); |
| 123 virtual void loop(); |
| 124 PdfResult done(); |
| 125 }; |
| 126 |
| 127 class PdfCompatibilitySectionLooper : public PdfTokenLooper { |
| 128 public: |
| 129 PdfCompatibilitySectionLooper() |
| 130 : PdfTokenLooper(NULL, NULL, NULL, NULL) {} |
| 131 |
| 132 virtual PdfResult consumeToken(PdfToken& token); |
| 133 virtual void loop(); |
| 134 }; |
| 135 |
75 // Utilities | 136 // Utilities |
76 static void setup_bitmap(SkBitmap* bitmap, int width, int height, SkColor color
= SK_ColorWHITE) { | 137 static void setup_bitmap(SkBitmap* bitmap, int width, int height, SkColor color
= SK_ColorWHITE) { |
77 bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); | 138 bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); |
78 | 139 |
79 bitmap->allocPixels(); | 140 bitmap->allocPixels(); |
80 bitmap->eraseColor(color); | 141 bitmap->eraseColor(color); |
81 } | 142 } |
82 | 143 |
83 // TODO(edisonn): synonyms? DeviceRGB and RGB ... | 144 // TODO(edisonn): synonyms? DeviceRGB and RGB ... |
84 static int GetColorSpaceComponents(const std::string& colorSpace) { | 145 static int GetColorSpaceComponents(const std::string& colorSpace) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
120 const SkPdfObject* elem = pdfArray->operator [](i); | 181 const SkPdfObject* elem = pdfArray->operator [](i); |
121 if (elem == NULL || !elem->isNumber()) { | 182 if (elem == NULL || !elem->isNumber()) { |
122 return SkMatrix::I(); // TODO(edisonn): report issue | 183 return SkMatrix::I(); // TODO(edisonn): report issue |
123 } | 184 } |
124 array[i] = elem->numberValue(); | 185 array[i] = elem->numberValue(); |
125 } | 186 } |
126 | 187 |
127 return SkMatrixFromPdfMatrix(array); | 188 return SkMatrixFromPdfMatrix(array); |
128 } | 189 } |
129 | 190 |
| 191 |
| 192 extern "C" SkNativeParsedPDF* gDoc; |
130 SkBitmap* gDumpBitmap = NULL; | 193 SkBitmap* gDumpBitmap = NULL; |
131 SkCanvas* gDumpCanvas = NULL; | 194 SkCanvas* gDumpCanvas = NULL; |
132 char gLastKeyword[100] = ""; | 195 char gLastKeyword[100] = ""; |
133 int gLastOpKeyword = -1; | 196 int gLastOpKeyword = -1; |
134 char allOpWithVisualEffects[100] = ",S,s,f,F,f*,B,B*,b,b*,n,Tj,TJ,\',\",d0,d1,sh
,EI,Do,EX,"; | 197 char allOpWithVisualEffects[100] = ",S,s,f,F,f*,B,B*,b,b*,n,Tj,TJ,\',\",d0,d1,sh
,EI,Do,EX,"; |
135 int gReadOp = 0; | 198 int gReadOp = 0; |
136 | 199 |
137 | 200 |
138 #ifdef PDF_TRACE_DIFF_IN_PNG | 201 #ifdef PDF_TRACE_DIFF_IN_PNG |
139 static bool hasVisualEffect(const char* pdfOp) { | 202 static bool hasVisualEffect(const char* pdfOp) { |
140 return true; | 203 return true; |
141 if (*pdfOp == '\0') return false; | 204 if (*pdfOp == '\0') return false; |
142 | 205 |
143 char markedPdfOp[100] = ","; | 206 char markedPdfOp[100] = ","; |
144 strcat(markedPdfOp, pdfOp); | 207 strcat(markedPdfOp, pdfOp); |
145 strcat(markedPdfOp, ","); | 208 strcat(markedPdfOp, ","); |
146 | 209 |
147 return (strstr(allOpWithVisualEffects, markedPdfOp) != NULL); | 210 return (strstr(allOpWithVisualEffects, markedPdfOp) != NULL); |
148 } | 211 } |
149 #endif // PDF_TRACE_DIFF_IN_PNG | 212 #endif // PDF_TRACE_DIFF_IN_PNG |
150 | 213 |
| 214 |
| 215 |
151 // TODO(edisonn): Pass PdfContext and SkCanvasd only with the define for instrum
entation. | 216 // TODO(edisonn): Pass PdfContext and SkCanvasd only with the define for instrum
entation. |
152 static bool readToken(SkPdfNativeTokenizer* fTokenizer, PdfToken* token) { | 217 static bool readToken(SkPdfNativeTokenizer* fTokenizer, PdfToken* token) { |
153 bool ret = fTokenizer->readToken(token); | 218 bool ret = fTokenizer->readToken(token); |
154 | 219 |
155 gReadOp++; | 220 gReadOp++; |
156 | 221 |
157 #ifdef PDF_TRACE_DIFF_IN_PNG | 222 #ifdef PDF_TRACE_DIFF_IN_PNG |
158 // TODO(edisonn): compare with old bitmap, and save only new bits are availa
ble, and save | 223 // TODO(edisonn): compare with old bitmap, and save only new bits are availa
ble, and save |
159 // the numbar and name of last operation, so the file name will reflect op t
hat changed. | 224 // the numbar and name of last operation, so the file name will reflect op t
hat changed. |
160 if (hasVisualEffect(gLastKeyword)) { // TODO(edisonn): and has dirty bits. | 225 if (hasVisualEffect(gLastKeyword)) { // TODO(edisonn): and has dirty bits. |
(...skipping 1688 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1849 // TODO(edisonn): Add API for Forms viewing and editing | 1914 // TODO(edisonn): Add API for Forms viewing and editing |
1850 // e.g. SkBitmap getPage(int page); | 1915 // e.g. SkBitmap getPage(int page); |
1851 // int formsCount(); | 1916 // int formsCount(); |
1852 // SkForm getForm(int formID); // SkForm(SkRect, .. other data) | 1917 // SkForm getForm(int formID); // SkForm(SkRect, .. other data) |
1853 // TODO (edisonn): Add intend when loading pdf, for example: for viewing, parsin
g all content, ... | 1918 // TODO (edisonn): Add intend when loading pdf, for example: for viewing, parsin
g all content, ... |
1854 // if we load the first page, and we zoom to fit to screen horizontally, then lo
ad only those | 1919 // if we load the first page, and we zoom to fit to screen horizontally, then lo
ad only those |
1855 // resources needed, so the preview is fast. | 1920 // resources needed, so the preview is fast. |
1856 // TODO (edisonn): hide parser/tokenizer behind and interface and a query langua
ge, and resolve | 1921 // TODO (edisonn): hide parser/tokenizer behind and interface and a query langua
ge, and resolve |
1857 // references automatically. | 1922 // references automatically. |
1858 | 1923 |
1859 bool SkPdfViewer::load(const SkString inputFileName, SkPicture* out) { | 1924 PdfContext* gPdfContext = NULL; |
1860 std::cout << "PDF Loaded: " << inputFileName.c_str() << std::endl; | |
1861 | 1925 |
1862 SkNativeParsedPDF* doc = new SkNativeParsedPDF(inputFileName.c_str()); | 1926 bool SkPdfRenderer::renderPage(int page, SkCanvas* canvas) const { |
1863 if (!doc->pages()) | 1927 if (!fPdfDoc) { |
1864 { | |
1865 std::cout << "ERROR: Empty PDF Document" << inputFileName.c_str() << std
::endl; | |
1866 return false; | 1928 return false; |
1867 } else { | 1929 } |
1868 | 1930 |
1869 for (int pn = 0; pn < doc->pages(); ++pn) { | 1931 if (page < 0 || page >= pages()) { |
1870 // TODO(edisonn): implement inheritance properties as per PDF spec | 1932 return false; |
1871 //SkRect rect = page->MediaBox(); | 1933 } |
1872 SkRect rect = doc->MediaBox(pn); | |
1873 | 1934 |
1874 #ifdef PDF_TRACE | 1935 SkPdfNativeTokenizer* tokenizer = fPdfDoc->tokenizerOfPage(page); |
1875 printf("Page Width: %f, Page Height: %f\n", SkScalarToDouble(rect.wi
dth()), SkScalarToDouble(rect.height())); | 1936 |
| 1937 PdfContext pdfContext(fPdfDoc); |
| 1938 pdfContext.fOriginalMatrix = SkMatrix::I(); |
| 1939 pdfContext.fGraphicsState.fResources = fPdfDoc->pageResources(page); |
| 1940 |
| 1941 gPdfContext = &pdfContext; |
| 1942 |
| 1943 // TODO(edisonn): get matrix stuff right. |
| 1944 // TODO(edisonn): add DPI/scale/zoom. |
| 1945 SkScalar z = SkIntToScalar(0); |
| 1946 SkRect rect = fPdfDoc->MediaBox(page); |
| 1947 SkScalar w = rect.width(); |
| 1948 SkScalar h = rect.height(); |
| 1949 |
| 1950 SkPoint pdfSpace[4] = {SkPoint::Make(z, z), SkPoint::Make(w, z), SkPoint::Ma
ke(w, h), SkPoint::Make(z, h)}; |
| 1951 // SkPoint skiaSpace[4] = {SkPoint::Make(z, h), SkPoint::Make(w,
h), SkPoint::Make(w, z), SkPoint::Make(z, z)}; |
| 1952 |
| 1953 // TODO(edisonn): add flag for this app to create sourunding buffer zone |
| 1954 // TODO(edisonn): add flagg for no clipping. |
| 1955 // Use larger image to make sure we do not draw anything outside of page |
| 1956 // could be used in tests. |
| 1957 |
| 1958 #ifdef PDF_DEBUG_3X |
| 1959 SkPoint skiaSpace[4] = {SkPoint::Make(w+z, h+h), SkPoint::Make(w+w, h+h), Sk
Point::Make(w+w, h+z), SkPoint::Make(w+z, h+z)}; |
| 1960 #else |
| 1961 SkPoint skiaSpace[4] = {SkPoint::Make(z, h), SkPoint::Make(w, h), SkPoint::M
ake(w, z), SkPoint::Make(z, z)}; |
| 1962 #endif |
| 1963 //SkPoint pdfSpace[2] = {SkPoint::Make(z, z), SkPoint::Make(w, h)}; |
| 1964 //SkPoint skiaSpace[2] = {SkPoint::Make(w, z), SkPoint::Make(z, h)}; |
| 1965 |
| 1966 //SkPoint pdfSpace[2] = {SkPoint::Make(z, z), SkPoint::Make(z, h)}; |
| 1967 //SkPoint skiaSpace[2] = {SkPoint::Make(z, h), SkPoint::Make(z, z)}; |
| 1968 |
| 1969 //SkPoint pdfSpace[3] = {SkPoint::Make(z, z), SkPoint::Make(z, h), SkPoint::
Make(w, h)}; |
| 1970 //SkPoint skiaSpace[3] = {SkPoint::Make(z, h), SkPoint::Make(z, z), SkPoint:
:Make(w, 0)}; |
| 1971 |
| 1972 SkAssertResult(pdfContext.fOriginalMatrix.setPolyToPoly(pdfSpace, skiaSpace,
4)); |
| 1973 SkTraceMatrix(pdfContext.fOriginalMatrix, "Original matrix"); |
| 1974 |
| 1975 |
| 1976 pdfContext.fGraphicsState.fMatrix = pdfContext.fOriginalMatrix; |
| 1977 pdfContext.fGraphicsState.fMatrixTm = pdfContext.fGraphicsState.fMatrix; |
| 1978 pdfContext.fGraphicsState.fMatrixTlm = pdfContext.fGraphicsState.fMatrix; |
| 1979 |
| 1980 canvas->setMatrix(pdfContext.fOriginalMatrix); |
| 1981 |
| 1982 #ifndef PDF_DEBUG_NO_PAGE_CLIPING |
| 1983 canvas->clipRect(SkRect::MakeXYWH(z, z, w, h), SkRegion::kIntersect_Op, true
); |
1876 #endif | 1984 #endif |
1877 | 1985 |
1878 // TODO(edisonn): page->GetCropBox(), page->GetTrimBox() ... how to
use? | 1986 // erase with red before? |
| 1987 // SkPaint paint; |
| 1988 // paint.setColor(SK_ColorRED); |
| 1989 // canvas->drawRect(rect, paint); |
1879 | 1990 |
1880 SkBitmap bitmap; | 1991 PdfMainLooper looper(NULL, tokenizer, &pdfContext, canvas); |
1881 #ifdef PDF_DEBUG_3X | 1992 looper.loop(); |
1882 setup_bitmap(&bitmap, 3 * (int)SkScalarToDouble(rect.width()), 3 * (
int)SkScalarToDouble(rect.height())); | |
1883 #else | |
1884 setup_bitmap(&bitmap, (int)SkScalarToDouble(rect.width()), (int)SkSc
alarToDouble(rect.height())); | |
1885 #endif | |
1886 SkAutoTUnref<SkDevice> device(SkNEW_ARGS(SkDevice, (bitmap))); | |
1887 SkCanvas canvas(device); | |
1888 | 1993 |
1889 gDumpBitmap = &bitmap; | 1994 delete tokenizer; |
1890 | 1995 |
1891 gDumpCanvas = &canvas; | 1996 canvas->flush(); |
1892 doc->drawPage(pn, &canvas); | |
1893 | |
1894 SkString out; | |
1895 if (doc->pages() > 1) { | |
1896 out.appendf("%s-%i.png", inputFileName.c_str(), pn); | |
1897 } else { | |
1898 out = inputFileName; | |
1899 // .pdf -> .png | |
1900 out[out.size() - 2] = 'n'; | |
1901 out[out.size() - 1] = 'g'; | |
1902 } | |
1903 SkImageEncoder::EncodeFile(out.c_str(), bitmap, SkImageEncoder::kPNG
_Type, 100); | |
1904 } | |
1905 return true; | |
1906 } | |
1907 | |
1908 return true; | 1997 return true; |
1909 } | 1998 } |
| 1999 |
| 2000 bool SkPdfRenderer::load(const SkString inputFileName) { |
| 2001 unload(); |
| 2002 |
| 2003 // TODO(edisonn): create static function that could return NULL if there are
errors |
| 2004 fPdfDoc = new SkNativeParsedPDF(inputFileName.c_str()); |
| 2005 |
| 2006 return fPdfDoc != NULL; |
| 2007 } |
| 2008 |
| 2009 int SkPdfRenderer::pages() const { |
| 2010 return fPdfDoc != NULL ? fPdfDoc->pages() : 0; |
| 2011 } |
| 2012 |
| 2013 void SkPdfRenderer::unload() { |
| 2014 delete fPdfDoc; |
| 2015 fPdfDoc = NULL; |
| 2016 } |
| 2017 |
| 2018 SkRect SkPdfRenderer::MediaBox(int page) const { |
| 2019 SkASSERT(fPdfDoc); |
| 2020 return fPdfDoc->MediaBox(page); |
| 2021 } |
OLD | NEW |