OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 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 "SkPDFDevice.h" | 8 #include "SkPDFDevice.h" |
9 | 9 |
10 #include "SkAnnotation.h" | 10 #include "SkAnnotation.h" |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 int upperBounds; | 43 int upperBounds; |
44 | 44 |
45 bool operator==(const TypefaceFallbackData& b) const { | 45 bool operator==(const TypefaceFallbackData& b) const { |
46 return typeface == b.typeface && | 46 return typeface == b.typeface && |
47 lowerBounds == b.lowerBounds && | 47 lowerBounds == b.lowerBounds && |
48 upperBounds == b.upperBounds; | 48 upperBounds == b.upperBounds; |
49 } | 49 } |
50 }; | 50 }; |
51 #endif | 51 #endif |
52 | 52 |
| 53 #define DPI_FOR_RASTER_SCALE_ONE 72 |
| 54 |
53 // Utility functions | 55 // Utility functions |
54 | 56 |
55 static void emit_pdf_color(SkColor color, SkWStream* result) { | 57 static void emit_pdf_color(SkColor color, SkWStream* result) { |
56 SkASSERT(SkColorGetA(color) == 0xFF); // We handle alpha elsewhere. | 58 SkASSERT(SkColorGetA(color) == 0xFF); // We handle alpha elsewhere. |
57 SkScalar colorMax = SkIntToScalar(0xFF); | 59 SkScalar colorMax = SkIntToScalar(0xFF); |
58 SkPDFScalar::Append( | 60 SkPDFScalar::Append( |
59 SkScalarDiv(SkIntToScalar(SkColorGetR(color)), colorMax), result); | 61 SkScalarDiv(SkIntToScalar(SkColorGetR(color)), colorMax), result); |
60 result->writeText(" "); | 62 result->writeText(" "); |
61 SkPDFScalar::Append( | 63 SkPDFScalar::Append( |
62 SkScalarDiv(SkIntToScalar(SkColorGetG(color)), colorMax), result); | 64 SkScalarDiv(SkIntToScalar(SkColorGetG(color)), colorMax), result); |
(...skipping 2101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2164 const SkPaint& paint) { | 2166 const SkPaint& paint) { |
2165 SkMatrix matrix = origMatrix; | 2167 SkMatrix matrix = origMatrix; |
2166 SkRegion perspectiveBounds; | 2168 SkRegion perspectiveBounds; |
2167 const SkRegion* clipRegion = &origClipRegion; | 2169 const SkRegion* clipRegion = &origClipRegion; |
2168 SkBitmap perspectiveBitmap; | 2170 SkBitmap perspectiveBitmap; |
2169 const SkBitmap* bitmap = &origBitmap; | 2171 const SkBitmap* bitmap = &origBitmap; |
2170 SkBitmap tmpSubsetBitmap; | 2172 SkBitmap tmpSubsetBitmap; |
2171 | 2173 |
2172 // Rasterize the bitmap using perspective in a new bitmap. | 2174 // Rasterize the bitmap using perspective in a new bitmap. |
2173 if (origMatrix.hasPerspective()) { | 2175 if (origMatrix.hasPerspective()) { |
| 2176 if (fRasterDpi == 0) { |
| 2177 return; |
| 2178 } |
2174 SkBitmap* subsetBitmap; | 2179 SkBitmap* subsetBitmap; |
2175 if (srcRect) { | 2180 if (srcRect) { |
2176 if (!origBitmap.extractSubset(&tmpSubsetBitmap, *srcRect)) { | 2181 if (!origBitmap.extractSubset(&tmpSubsetBitmap, *srcRect)) { |
2177 return; | 2182 return; |
2178 } | 2183 } |
2179 subsetBitmap = &tmpSubsetBitmap; | 2184 subsetBitmap = &tmpSubsetBitmap; |
2180 } else { | 2185 } else { |
2181 subsetBitmap = &tmpSubsetBitmap; | 2186 subsetBitmap = &tmpSubsetBitmap; |
2182 *subsetBitmap = origBitmap; | 2187 *subsetBitmap = origBitmap; |
2183 } | 2188 } |
2184 srcRect = NULL; | 2189 srcRect = NULL; |
2185 | 2190 |
2186 // Transform the bitmap in the new space. | 2191 // Transform the bitmap in the new space, without taking into |
| 2192 // account the initial transform. |
2187 SkPath perspectiveOutline; | 2193 SkPath perspectiveOutline; |
2188 perspectiveOutline.addRect( | 2194 perspectiveOutline.addRect( |
2189 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()), | 2195 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()), |
2190 SkIntToScalar(subsetBitmap->height()))); | 2196 SkIntToScalar(subsetBitmap->height()))); |
2191 perspectiveOutline.transform(origMatrix); | 2197 perspectiveOutline.transform(origMatrix); |
2192 | 2198 |
2193 // TODO(edisonn): perf - use current clip too. | 2199 // TODO(edisonn): perf - use current clip too. |
2194 // Retrieve the bounds of the new shape. | 2200 // Retrieve the bounds of the new shape. |
2195 SkRect bounds = perspectiveOutline.getBounds(); | 2201 SkRect bounds = perspectiveOutline.getBounds(); |
2196 | 2202 |
2197 // TODO(edisonn): add DPI settings. Currently 1 pixel/point, which does | 2203 // Transform the bitmap in the new space, taking into |
2198 // not look great, but it is not producing large PDFs. | 2204 // account the initial transform. |
| 2205 SkMatrix total = origMatrix; |
| 2206 total.postConcat(fInitialTransform); |
| 2207 total.postScale(SkIntToScalar(fRasterDpi) / |
| 2208 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE), |
| 2209 SkIntToScalar(fRasterDpi) / |
| 2210 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE)); |
| 2211 SkPath physicalPerspectiveOutline; |
| 2212 physicalPerspectiveOutline.addRect( |
| 2213 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()), |
| 2214 SkIntToScalar(subsetBitmap->height()))); |
| 2215 physicalPerspectiveOutline.transform(total); |
| 2216 |
| 2217 SkScalar scaleX = physicalPerspectiveOutline.getBounds().width() / |
| 2218 bounds.width(); |
| 2219 SkScalar scaleY = physicalPerspectiveOutline.getBounds().height() / |
| 2220 bounds.height(); |
2199 | 2221 |
2200 // TODO(edisonn): A better approach would be to use a bitmap shader | 2222 // TODO(edisonn): A better approach would be to use a bitmap shader |
2201 // (in clamp mode) and draw a rect over the entire bounding box. Then | 2223 // (in clamp mode) and draw a rect over the entire bounding box. Then |
2202 // intersect perspectiveOutline to the clip. That will avoid introducing | 2224 // intersect perspectiveOutline to the clip. That will avoid introducing |
2203 // alpha to the image while still giving good behavior at the edge of | 2225 // alpha to the image while still giving good behavior at the edge of |
2204 // the image. Avoiding alpha will reduce the pdf size and generation | 2226 // the image. Avoiding alpha will reduce the pdf size and generation |
2205 // CPU time some. | 2227 // CPU time some. |
2206 | 2228 |
2207 perspectiveBitmap.setConfig(SkBitmap::kARGB_8888_Config, | 2229 perspectiveBitmap.setConfig( |
2208 SkScalarCeilToInt(bounds.width()), | 2230 SkBitmap::kARGB_8888_Config, |
2209 SkScalarCeilToInt(bounds.height())); | 2231 SkScalarCeilToInt( |
| 2232 physicalPerspectiveOutline.getBounds().width()), |
| 2233 SkScalarCeilToInt( |
| 2234 physicalPerspectiveOutline.getBounds().height())); |
2210 perspectiveBitmap.allocPixels(); | 2235 perspectiveBitmap.allocPixels(); |
2211 perspectiveBitmap.eraseColor(SK_ColorTRANSPARENT); | 2236 perspectiveBitmap.eraseColor(SK_ColorTRANSPARENT); |
2212 | 2237 |
2213 SkBitmapDevice device(perspectiveBitmap); | 2238 SkBitmapDevice device(perspectiveBitmap); |
2214 SkCanvas canvas(&device); | 2239 SkCanvas canvas(&device); |
2215 | 2240 |
2216 SkScalar deltaX = bounds.left(); | 2241 SkScalar deltaX = bounds.left(); |
2217 SkScalar deltaY = bounds.top(); | 2242 SkScalar deltaY = bounds.top(); |
2218 | 2243 |
2219 SkMatrix offsetMatrix = origMatrix; | 2244 SkMatrix offsetMatrix = origMatrix; |
2220 offsetMatrix.postTranslate(-deltaX, -deltaY); | 2245 offsetMatrix.postTranslate(-deltaX, -deltaY); |
| 2246 offsetMatrix.postScale(scaleX, scaleY); |
2221 | 2247 |
2222 // Translate the draw in the new canvas, so we perfectly fit the | 2248 // Translate the draw in the new canvas, so we perfectly fit the |
2223 // shape in the bitmap. | 2249 // shape in the bitmap. |
2224 canvas.setMatrix(offsetMatrix); | 2250 canvas.setMatrix(offsetMatrix); |
2225 | 2251 |
2226 canvas.drawBitmap(*subsetBitmap, SkIntToScalar(0), SkIntToScalar(0)); | 2252 canvas.drawBitmap(*subsetBitmap, SkIntToScalar(0), SkIntToScalar(0)); |
2227 | 2253 |
2228 // Make sure the final bits are in the bitmap. | 2254 // Make sure the final bits are in the bitmap. |
2229 canvas.flush(); | 2255 canvas.flush(); |
2230 | 2256 |
2231 // In the new space, we use the identity matrix translated. | 2257 // In the new space, we use the identity matrix translated |
2232 matrix.setTranslate(deltaX, deltaY); | 2258 // and scaled to reflect DPI. |
| 2259 matrix.setScale(1 / scaleX, 1 / scaleY); |
| 2260 matrix.postTranslate(deltaX, deltaY); |
| 2261 |
2233 perspectiveBounds.setRect( | 2262 perspectiveBounds.setRect( |
2234 SkIRect::MakeXYWH(SkScalarFloorToInt(bounds.x()), | 2263 SkIRect::MakeXYWH(SkScalarFloorToInt(bounds.x()), |
2235 SkScalarFloorToInt(bounds.y()), | 2264 SkScalarFloorToInt(bounds.y()), |
2236 SkScalarCeilToInt(bounds.width()), | 2265 SkScalarCeilToInt(bounds.width()), |
2237 SkScalarCeilToInt(bounds.height()))); | 2266 SkScalarCeilToInt(bounds.height()))); |
2238 clipRegion = &perspectiveBounds; | 2267 clipRegion = &perspectiveBounds; |
2239 srcRect = NULL; | 2268 srcRect = NULL; |
2240 bitmap = &perspectiveBitmap; | 2269 bitmap = &perspectiveBitmap; |
2241 } | 2270 } |
2242 | 2271 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2275 } | 2304 } |
2276 | 2305 |
2277 bool SkPDFDevice::onReadPixels(const SkBitmap& bitmap, int x, int y, | 2306 bool SkPDFDevice::onReadPixels(const SkBitmap& bitmap, int x, int y, |
2278 SkCanvas::Config8888) { | 2307 SkCanvas::Config8888) { |
2279 return false; | 2308 return false; |
2280 } | 2309 } |
2281 | 2310 |
2282 bool SkPDFDevice::allowImageFilter(SkImageFilter*) { | 2311 bool SkPDFDevice::allowImageFilter(SkImageFilter*) { |
2283 return false; | 2312 return false; |
2284 } | 2313 } |
OLD | NEW |