 Chromium Code Reviews
 Chromium Code Reviews Issue 54913004:
  Implement DPI for perspective bitmaps in PDF - we save the bitmap at the resolution requested.  (Closed) 
  Base URL: https://skia.googlecode.com/svn/trunk
    
  
    Issue 54913004:
  Implement DPI for perspective bitmaps in PDF - we save the bitmap at the resolution requested.  (Closed) 
  Base URL: https://skia.googlecode.com/svn/trunk| 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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 42 int upperBounds; | 42 int upperBounds; | 
| 43 | 43 | 
| 44 bool operator==(const TypefaceFallbackData& b) const { | 44 bool operator==(const TypefaceFallbackData& b) const { | 
| 45 return typeface == b.typeface && | 45 return typeface == b.typeface && | 
| 46 lowerBounds == b.lowerBounds && | 46 lowerBounds == b.lowerBounds && | 
| 47 upperBounds == b.upperBounds; | 47 upperBounds == b.upperBounds; | 
| 48 } | 48 } | 
| 49 }; | 49 }; | 
| 50 #endif | 50 #endif | 
| 51 | 51 | 
| 52 #define DPI_FOR_RASTER_SCALE_ONE 72 | |
| 53 | |
| 52 // Utility functions | 54 // Utility functions | 
| 53 | 55 | 
| 54 static void emit_pdf_color(SkColor color, SkWStream* result) { | 56 static void emit_pdf_color(SkColor color, SkWStream* result) { | 
| 55 SkASSERT(SkColorGetA(color) == 0xFF); // We handle alpha elsewhere. | 57 SkASSERT(SkColorGetA(color) == 0xFF); // We handle alpha elsewhere. | 
| 56 SkScalar colorMax = SkIntToScalar(0xFF); | 58 SkScalar colorMax = SkIntToScalar(0xFF); | 
| 57 SkPDFScalar::Append( | 59 SkPDFScalar::Append( | 
| 58 SkScalarDiv(SkIntToScalar(SkColorGetR(color)), colorMax), result); | 60 SkScalarDiv(SkIntToScalar(SkColorGetR(color)), colorMax), result); | 
| 59 result->writeText(" "); | 61 result->writeText(" "); | 
| 60 SkPDFScalar::Append( | 62 SkPDFScalar::Append( | 
| 61 SkScalarDiv(SkIntToScalar(SkColorGetG(color)), colorMax), result); | 63 SkScalarDiv(SkIntToScalar(SkColorGetG(color)), colorMax), result); | 
| (...skipping 2094 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2156 const SkPaint& paint) { | 2158 const SkPaint& paint) { | 
| 2157 SkMatrix matrix = origMatrix; | 2159 SkMatrix matrix = origMatrix; | 
| 2158 SkRegion perspectiveBounds; | 2160 SkRegion perspectiveBounds; | 
| 2159 const SkRegion* clipRegion = &origClipRegion; | 2161 const SkRegion* clipRegion = &origClipRegion; | 
| 2160 SkBitmap perspectiveBitmap; | 2162 SkBitmap perspectiveBitmap; | 
| 2161 const SkBitmap* bitmap = &origBitmap; | 2163 const SkBitmap* bitmap = &origBitmap; | 
| 2162 SkBitmap tmpSubsetBitmap; | 2164 SkBitmap tmpSubsetBitmap; | 
| 2163 | 2165 | 
| 2164 // Rasterize the bitmap using perspective in a new bitmap. | 2166 // Rasterize the bitmap using perspective in a new bitmap. | 
| 2165 if (origMatrix.hasPerspective()) { | 2167 if (origMatrix.hasPerspective()) { | 
| 2168 if (fRasterDpi == 0) { | |
| 2169 return; | |
| 2170 } | |
| 2166 SkBitmap* subsetBitmap; | 2171 SkBitmap* subsetBitmap; | 
| 2167 if (srcRect) { | 2172 if (srcRect) { | 
| 2168 if (!origBitmap.extractSubset(&tmpSubsetBitmap, *srcRect)) { | 2173 if (!origBitmap.extractSubset(&tmpSubsetBitmap, *srcRect)) { | 
| 2169 return; | 2174 return; | 
| 2170 } | 2175 } | 
| 2171 subsetBitmap = &tmpSubsetBitmap; | 2176 subsetBitmap = &tmpSubsetBitmap; | 
| 2172 } else { | 2177 } else { | 
| 2173 subsetBitmap = &tmpSubsetBitmap; | 2178 subsetBitmap = &tmpSubsetBitmap; | 
| 2174 *subsetBitmap = origBitmap; | 2179 *subsetBitmap = origBitmap; | 
| 2175 } | 2180 } | 
| 2176 srcRect = NULL; | 2181 srcRect = NULL; | 
| 2177 | 2182 | 
| 2178 // Transform the bitmap in the new space. | 2183 // Transform the bitmap in the new space, without taking into | 
| 2184 // account the initial transform. | |
| 2179 SkPath perspectiveOutline; | 2185 SkPath perspectiveOutline; | 
| 2180 perspectiveOutline.addRect( | 2186 perspectiveOutline.addRect( | 
| 2181 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()), | 2187 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()), | 
| 2182 SkIntToScalar(subsetBitmap->height()))); | 2188 SkIntToScalar(subsetBitmap->height()))); | 
| 2183 perspectiveOutline.transform(origMatrix); | 2189 perspectiveOutline.transform(origMatrix); | 
| 2184 | 2190 | 
| 2185 // TODO(edisonn): perf - use current clip too. | 2191 // TODO(edisonn): perf - use current clip too. | 
| 2186 // Retrieve the bounds of the new shape. | 2192 // Retrieve the bounds of the new shape. | 
| 2187 SkRect bounds = perspectiveOutline.getBounds(); | 2193 SkRect bounds = perspectiveOutline.getBounds(); | 
| 2188 | 2194 | 
| 2189 // TODO(edisonn): add DPI settings. Currently 1 pixel/point, which does | 2195 // Transform the bitmap in the new space, taking into | 
| 2190 // not look great, but it is not producing large PDFs. | 2196 // account the initial transform. | 
| 2197 SkMatrix total = origMatrix; | |
| 2198 total.postConcat(fInitialTransform); | |
| 
vandebo (ex-Chrome)
2013/11/07 22:44:00
Should this be preConcat?  fInitialTransform is ap
 
edisonn
2013/11/11 17:26:56
I don't think so, gms fail and they don't output a
 
vandebo (ex-Chrome)
2013/11/11 17:52:19
Oops, I got Pre/Post mixed up in what they do.
 | |
| 2199 SkMatrix scaleDpi; | |
| 2200 scaleDpi.setScale(SkIntToScalar(fRasterDpi) / | |
| 2201 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE), | |
| 2202 SkIntToScalar(fRasterDpi) / | |
| 2203 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE)); | |
| 2204 total.postConcat(scaleDpi); | |
| 
vandebo (ex-Chrome)
2013/11/07 22:44:00
nit: scaleDPI isn't needed, just do postScale here
 
edisonn
2013/11/11 17:26:56
Done.
 | |
| 2205 SkPath physicalPerspectiveOutline; | |
| 2206 physicalPerspectiveOutline.addRect( | |
| 2207 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()), | |
| 2208 SkIntToScalar(subsetBitmap->height()))); | |
| 2209 physicalPerspectiveOutline.transform(total); | |
| 2210 | |
| 2211 SkScalar scaleX = physicalPerspectiveOutline.getBounds().width() / | |
| 2212 bounds.width(); | |
| 2213 SkScalar scaleY = physicalPerspectiveOutline.getBounds().height() / | |
| 2214 bounds.height(); | |
| 2191 | 2215 | 
| 2192 // TODO(edisonn): A better approach would be to use a bitmap shader | 2216 // TODO(edisonn): A better approach would be to use a bitmap shader | 
| 2193 // (in clamp mode) and draw a rect over the entire bounding box. Then | 2217 // (in clamp mode) and draw a rect over the entire bounding box. Then | 
| 2194 // intersect perspectiveOutline to the clip. That will avoid introducing | 2218 // intersect perspectiveOutline to the clip. That will avoid introducing | 
| 2195 // alpha to the image while still giving good behavior at the edge of | 2219 // alpha to the image while still giving good behavior at the edge of | 
| 2196 // the image. Avoiding alpha will reduce the pdf size and generation | 2220 // the image. Avoiding alpha will reduce the pdf size and generation | 
| 2197 // CPU time some. | 2221 // CPU time some. | 
| 2198 | 2222 | 
| 2199 perspectiveBitmap.setConfig(SkBitmap::kARGB_8888_Config, | 2223 perspectiveBitmap.setConfig( | 
| 2200 SkScalarCeilToInt(bounds.width()), | 2224 SkBitmap::kARGB_8888_Config, | 
| 2201 SkScalarCeilToInt(bounds.height())); | 2225 SkScalarCeilToInt(scaleX * bounds.width()), | 
| 
vandebo (ex-Chrome)
2013/11/07 22:44:00
Just use  physicalPerspectiveOutline.getBounds().w
 
edisonn
2013/11/11 17:26:56
Done.
 | |
| 2226 SkScalarCeilToInt(scaleY * bounds.height())); | |
| 2202 perspectiveBitmap.allocPixels(); | 2227 perspectiveBitmap.allocPixels(); | 
| 2203 perspectiveBitmap.eraseColor(SK_ColorTRANSPARENT); | 2228 perspectiveBitmap.eraseColor(SK_ColorTRANSPARENT); | 
| 2204 | 2229 | 
| 2205 SkBitmapDevice device(perspectiveBitmap); | 2230 SkBitmapDevice device(perspectiveBitmap); | 
| 2206 SkCanvas canvas(&device); | 2231 SkCanvas canvas(&device); | 
| 2207 | 2232 | 
| 2208 SkScalar deltaX = bounds.left(); | 2233 SkScalar deltaX = bounds.left(); | 
| 2209 SkScalar deltaY = bounds.top(); | 2234 SkScalar deltaY = bounds.top(); | 
| 2210 | 2235 | 
| 2211 SkMatrix offsetMatrix = origMatrix; | 2236 SkMatrix offsetMatrix = origMatrix; | 
| 2212 offsetMatrix.postTranslate(-deltaX, -deltaY); | 2237 offsetMatrix.postTranslate(-deltaX, -deltaY); | 
| 2238 offsetMatrix.postScale(scaleX, scaleY); | |
| 2213 | 2239 | 
| 2214 // Translate the draw in the new canvas, so we perfectly fit the | 2240 // Translate the draw in the new canvas, so we perfectly fit the | 
| 2215 // shape in the bitmap. | 2241 // shape in the bitmap. | 
| 2216 canvas.setMatrix(offsetMatrix); | 2242 canvas.setMatrix(offsetMatrix); | 
| 2217 | 2243 | 
| 2218 canvas.drawBitmap(*subsetBitmap, SkIntToScalar(0), SkIntToScalar(0)); | 2244 canvas.drawBitmap(*subsetBitmap, SkIntToScalar(0), SkIntToScalar(0)); | 
| 2219 | 2245 | 
| 2220 // Make sure the final bits are in the bitmap. | 2246 // Make sure the final bits are in the bitmap. | 
| 2221 canvas.flush(); | 2247 canvas.flush(); | 
| 2222 | 2248 | 
| 2223 // In the new space, we use the identity matrix translated. | 2249 // In the new space, we use the identity matrix translated | 
| 2224 matrix.setTranslate(deltaX, deltaY); | 2250 // and scaled to reflect DPI. | 
| 2251 matrix.setScale(1 / scaleX, 1 / scaleY); | |
| 2252 matrix.postTranslate(deltaX, deltaY); | |
| 
vandebo (ex-Chrome)
2013/11/07 22:44:00
Not sure, should this be preTranslate ?
 
edisonn
2013/11/11 17:26:56
gms fail badly if I use preTranslate
 | |
| 2253 | |
| 2225 perspectiveBounds.setRect( | 2254 perspectiveBounds.setRect( | 
| 2226 SkIRect::MakeXYWH(SkScalarFloorToInt(bounds.x()), | 2255 SkIRect::MakeXYWH(SkScalarFloorToInt(bounds.x()), | 
| 2227 SkScalarFloorToInt(bounds.y()), | 2256 SkScalarFloorToInt(bounds.y()), | 
| 2228 SkScalarCeilToInt(bounds.width()), | 2257 SkScalarCeilToInt(bounds.width()), | 
| 2229 SkScalarCeilToInt(bounds.height()))); | 2258 SkScalarCeilToInt(bounds.height()))); | 
| 2230 clipRegion = &perspectiveBounds; | 2259 clipRegion = &perspectiveBounds; | 
| 2231 srcRect = NULL; | 2260 srcRect = NULL; | 
| 2232 bitmap = &perspectiveBitmap; | 2261 bitmap = &perspectiveBitmap; | 
| 2233 } | 2262 } | 
| 2234 | 2263 | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2267 } | 2296 } | 
| 2268 | 2297 | 
| 2269 bool SkPDFDevice::onReadPixels(const SkBitmap& bitmap, int x, int y, | 2298 bool SkPDFDevice::onReadPixels(const SkBitmap& bitmap, int x, int y, | 
| 2270 SkCanvas::Config8888) { | 2299 SkCanvas::Config8888) { | 
| 2271 return false; | 2300 return false; | 
| 2272 } | 2301 } | 
| 2273 | 2302 | 
| 2274 bool SkPDFDevice::allowImageFilter(SkImageFilter*) { | 2303 bool SkPDFDevice::allowImageFilter(SkImageFilter*) { | 
| 2275 return false; | 2304 return false; | 
| 2276 } | 2305 } | 
| OLD | NEW |