Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(369)

Unified Diff: src/pdf/SkPDFImage.cpp

Issue 22889020: Refactor SkPDFImage (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Make JPEG mode not crash Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/pdf/SkPDFImage.h ('k') | src/pdf/SkPDFImageStream.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/pdf/SkPDFImage.cpp
diff --git a/src/pdf/SkPDFImage.cpp b/src/pdf/SkPDFImage.cpp
index a5cb4c20d1b9e187948cc6654d590b219df4d686..d92afd1fe7145bf3cb74c0715721c1b7ff505025 100644
--- a/src/pdf/SkPDFImage.cpp
+++ b/src/pdf/SkPDFImage.cpp
@@ -10,6 +10,8 @@
#include "SkBitmap.h"
#include "SkColor.h"
#include "SkColorPriv.h"
+#include "SkData.h"
+#include "SkFlate.h"
#include "SkPDFCatalog.h"
#include "SkRect.h"
#include "SkStream.h"
@@ -18,18 +20,58 @@
namespace {
-void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect,
- SkStream** imageData, SkStream** alphaData) {
- SkMemoryStream* image = NULL;
- SkMemoryStream* alpha = NULL;
- bool hasAlpha = false;
- bool isTransparent = false;
+#define kNoColorTransform 0
+
+static bool skip_compression(SkPDFCatalog* catalog) {
+ return SkToBool(catalog->getDocumentFlags() &
+ SkPDFDocument::kFavorSpeedOverSize_Flags);
+}
+
+static size_t get_row_bytes(const SkBitmap& bitmap,
+ const SkIRect& srcRect) {
+ switch (bitmap.getConfig()) {
+ case SkBitmap::kIndex8_Config:
+ return srcRect.width();
+ case SkBitmap::kARGB_4444_Config:
+ return (srcRect.width() * 3 + 1) / 2;
+ case SkBitmap::kRGB_565_Config:
+ return srcRect.width() * 3;
+ case SkBitmap::kARGB_8888_Config:
+ return srcRect.width() * 3;
+ case SkBitmap::kA1_Config:
+ case SkBitmap::kA8_Config:
+ return 1;
+ default:
+ SkASSERT(false);
+ return 0;
+ }
+}
+static size_t get_uncompressed_size(const SkBitmap& bitmap,
+ const SkIRect& srcRect) {
+ switch (bitmap.getConfig()) {
+ case SkBitmap::kIndex8_Config:
+ case SkBitmap::kARGB_4444_Config:
+ case SkBitmap::kRGB_565_Config:
+ case SkBitmap::kARGB_8888_Config:
+ return get_row_bytes(bitmap, srcRect) * srcRect.height();
+ case SkBitmap::kA1_Config:
+ case SkBitmap::kA8_Config:
+ return 1;
+ default:
+ SkASSERT(false);
+ return 0;
+ }
+}
+
+static SkStream* extract_image_data(const SkBitmap& bitmap,
+ const SkIRect& srcRect) {
+ const int rowBytes = get_row_bytes(bitmap, srcRect);
+ SkMemoryStream* image = new SkMemoryStream(get_uncompressed_size(bitmap,
+ srcRect));
bitmap.lockPixels();
switch (bitmap.getConfig()) {
case SkBitmap::kIndex8_Config: {
- const int rowBytes = srcRect.width();
- image = new SkMemoryStream(rowBytes * srcRect.height());
uint8_t* dst = (uint8_t*)image->getMemoryBase();
for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes);
@@ -38,13 +80,7 @@ void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect,
break;
}
case SkBitmap::kARGB_4444_Config: {
- isTransparent = true;
- const int rowBytes = (srcRect.width() * 3 + 1) / 2;
- const int alphaRowBytes = (srcRect.width() + 1) / 2;
- image = new SkMemoryStream(rowBytes * srcRect.height());
- alpha = new SkMemoryStream(alphaRowBytes * srcRect.height());
uint8_t* dst = (uint8_t*)image->getMemoryBase();
- uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase();
for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
uint16_t* src = bitmap.getAddr16(0, y);
int x;
@@ -56,36 +92,17 @@ void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect,
dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) |
SkGetPackedB4444(src[x + 1]);
dst += 3;
- alphaDst[0] = (SkGetPackedA4444(src[x]) << 4) |
- SkGetPackedA4444(src[x + 1]);
- if (alphaDst[0] != 0xFF) {
- hasAlpha = true;
- }
- if (alphaDst[0]) {
- isTransparent = false;
- }
- alphaDst++;
}
if (srcRect.width() & 1) {
dst[0] = (SkGetPackedR4444(src[x]) << 4) |
SkGetPackedG4444(src[x]);
dst[1] = (SkGetPackedB4444(src[x]) << 4);
dst += 2;
- alphaDst[0] = (SkGetPackedA4444(src[x]) << 4);
- if (alphaDst[0] != 0xF0) {
- hasAlpha = true;
- }
- if (alphaDst[0] & 0xF0) {
- isTransparent = false;
- }
- alphaDst++;
}
}
break;
}
case SkBitmap::kRGB_565_Config: {
- const int rowBytes = srcRect.width() * 3;
- image = new SkMemoryStream(rowBytes * srcRect.height());
uint8_t* dst = (uint8_t*)image->getMemoryBase();
for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
uint16_t* src = bitmap.getAddr16(0, y);
@@ -99,12 +116,7 @@ void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect,
break;
}
case SkBitmap::kARGB_8888_Config: {
- isTransparent = true;
- const int rowBytes = srcRect.width() * 3;
- image = new SkMemoryStream(rowBytes * srcRect.height());
- alpha = new SkMemoryStream(srcRect.width() * srcRect.height());
uint8_t* dst = (uint8_t*)image->getMemoryBase();
- uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase();
for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
uint32_t* src = bitmap.getAddr32(0, y);
for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
@@ -112,12 +124,79 @@ void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect,
dst[1] = SkGetPackedG32(src[x]);
dst[2] = SkGetPackedB32(src[x]);
dst += 3;
+ }
+ }
+ break;
+ }
+ case SkBitmap::kA1_Config:
+ case SkBitmap::kA8_Config: {
+ ((uint8_t*)image->getMemoryBase())[0] = 0;
+ break;
+ }
+ default:
+ SkASSERT(false);
+ }
+ bitmap.unlockPixels();
+
+ return image;
+}
+
+// Extract the alpha data from a SkBitmap and output it in a SkStream.
+// alphaData may be NULL if there was no alpha data to extract (image
+// completely opaque).
+// isTransparent outputs true if the alpha is completely transparent.
+static SkStream* extract_alpha_data(const SkBitmap& bitmap,
+ const SkIRect& srcRect,
+ bool* isTransparent) {
+ SkMemoryStream* alpha = NULL;
+ bool hasAlpha = false;
+ *isTransparent = true;
+
+ bitmap.lockPixels();
+ switch (bitmap.getConfig()) {
+ case SkBitmap::kARGB_4444_Config: {
+ const int alphaRowBytes = (srcRect.width() + 1) / 2;
+ alpha = new SkMemoryStream(alphaRowBytes * srcRect.height());
+ uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase();
+ for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
+ uint16_t* src = bitmap.getAddr16(0, y);
+ int x;
+ for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) {
+ alphaDst[0] = (SkGetPackedA4444(src[x]) << 4) |
+ SkGetPackedA4444(src[x + 1]);
+ if (alphaDst[0] != 0xFF) {
edisonn 2013/08/21 18:40:51 alphaDst[0] != 0xFF if (alphaDst[0]) { alphaDst[0]
ducky 2013/08/21 19:27:53 Done. I think the old code was written before thin
+ hasAlpha = true;
+ }
+ if (alphaDst[0]) {
+ *isTransparent = false;
+ }
+ alphaDst++;
+ }
+ if (srcRect.width() & 1) {
+ alphaDst[0] = (SkGetPackedA4444(src[x]) << 4);
+ if (alphaDst[0] != 0xF0) {
+ hasAlpha = true;
+ }
+ if (alphaDst[0] & 0xF0) {
+ *isTransparent = false;
+ }
+ alphaDst++;
+ }
+ }
+ break;
+ }
+ case SkBitmap::kARGB_8888_Config: {
+ alpha = new SkMemoryStream(srcRect.width() * srcRect.height());
+ uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase();
+ for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
+ uint32_t* src = bitmap.getAddr32(0, y);
+ for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
alphaDst[0] = SkGetPackedA32(src[x]);
if (alphaDst[0] != 0xFF) {
hasAlpha = true;
}
if (alphaDst[0]) {
- isTransparent = false;
+ *isTransparent = false;
}
alphaDst++;
}
@@ -125,10 +204,6 @@ void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect,
break;
}
case SkBitmap::kA1_Config: {
- isTransparent = true;
- image = new SkMemoryStream(1);
- ((uint8_t*)image->getMemoryBase())[0] = 0;
-
const int alphaRowBytes = (srcRect.width() + 7) / 8;
alpha = new SkMemoryStream(alphaRowBytes * srcRect.height());
uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase();
@@ -149,7 +224,7 @@ void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect,
hasAlpha = true;
}
if (x + 7 < srcRect.fRight && alphaDst[0]) {
- isTransparent = false;
+ *isTransparent = false;
}
alphaDst++;
}
@@ -161,16 +236,12 @@ void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect,
hasAlpha = true;
}
if (srcRect.width() % 8 && (alphaDst[-1] & mask)) {
- isTransparent = false;
+ *isTransparent = false;
}
}
break;
}
case SkBitmap::kA8_Config: {
- isTransparent = true;
- image = new SkMemoryStream(1);
- ((uint8_t*)image->getMemoryBase())[0] = 0;
-
const int alphaRowBytes = srcRect.width();
alpha = new SkMemoryStream(alphaRowBytes * srcRect.height());
uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase();
@@ -182,28 +253,28 @@ void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect,
hasAlpha = true;
}
if (alphaDst[0]) {
- isTransparent = false;
+ *isTransparent = false;
}
alphaDst++;
}
}
break;
}
+ case SkBitmap::kRGB_565_Config:
+ case SkBitmap::kIndex8_Config: {
+ *isTransparent = false;
+ break;
+ }
default:
SkASSERT(false);
}
bitmap.unlockPixels();
- if (isTransparent) {
- SkSafeUnref(image);
- } else {
- *imageData = image;
- }
-
- if (isTransparent || !hasAlpha) {
+ if (!hasAlpha || *isTransparent) {
SkSafeUnref(alpha);
+ return NULL;
} else {
- *alphaData = alpha;
+ return alpha;
}
}
@@ -238,26 +309,14 @@ SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap,
if (bitmap.getConfig() == SkBitmap::kNo_Config) {
return NULL;
}
+ SkPDFImage* image = SkNEW_ARGS(SkPDFImage, (bitmap, srcRect, encoder));
- SkStream* imageData = NULL;
- SkStream* alphaData = NULL;
- extractImageData(bitmap, srcRect, &imageData, &alphaData);
- SkAutoUnref unrefImageData(imageData);
- SkAutoUnref unrefAlphaData(alphaData);
- if (!imageData) {
- SkASSERT(!alphaData);
+ if (image->isEmpty()) {
+ image->unref();
return NULL;
+ } else {
+ return image;
}
-
- SkPDFImage* image =
- SkNEW_ARGS(SkPDFImage, (imageData, bitmap, srcRect, false, encoder));
-
- if (alphaData != NULL) {
- // Don't try to use DCT compression with alpha because alpha is small
- // anyway and it could lead to artifacts.
- image->addSMask(SkNEW_ARGS(SkPDFImage, (alphaData, bitmap, srcRect, true, NULL)))->unref();
- }
- return image;
}
SkPDFImage::~SkPDFImage() {
@@ -276,51 +335,89 @@ void SkPDFImage::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects);
}
-SkPDFImage::SkPDFImage(SkStream* imageData,
- const SkBitmap& bitmap,
+SkPDFImage::SkPDFImage(const SkBitmap& bitmap,
const SkIRect& srcRect,
- bool doingAlpha,
EncodeToDCTStream encoder)
- : SkPDFImageStream(imageData, bitmap, srcRect, encoder) {
- SkBitmap::Config config = bitmap.getConfig();
- bool alphaOnly = (config == SkBitmap::kA1_Config ||
- config == SkBitmap::kA8_Config);
+ : fBitmap(bitmap),
+ fSrcRect(srcRect),
+ fEncoder(encoder) {
+ bool isTransparent;
+ SkAutoTUnref<SkStream> alphaData(extract_alpha_data(bitmap, srcRect,
+ &isTransparent));
+ if (isTransparent) {
+ fSrcRect = SkIRect::MakeEmpty();
+ return;
+ }
+ if (alphaData.get() != NULL) {
+ addSMask(SkNEW_ARGS(SkPDFImage,
+ (alphaData.get(), bitmap, srcRect)))->unref();
+ }
+
+ initImageParams(false);
+}
+
+SkPDFImage::SkPDFImage(SkStream* stream, const SkBitmap& bitmap,
+ const SkIRect& srcRect)
+ : fBitmap(bitmap),
+ fSrcRect(srcRect),
+ fEncoder(NULL) {
+ setData(stream);
+ insertInt("Length", getData()->getLength());
+ setState(kNoCompression_State);
+
+ initImageParams(true);
+}
+
+SkPDFImage::SkPDFImage(SkPDFImage& pdfImage)
+ : SkPDFStream(pdfImage),
+ fBitmap(pdfImage.fBitmap),
+ fSrcRect(pdfImage.fSrcRect),
+ fEncoder(pdfImage.fEncoder){
+ // Nothing to do here - the image params are already copied in SkPDFStream's
+ // constructor, and the bitmap will be regenerated and re-encoded in
+ // populate.
+}
+
+void SkPDFImage::initImageParams(bool isAlpha) {
+ SkBitmap::Config config = fBitmap.getConfig();
insertName("Type", "XObject");
insertName("Subtype", "Image");
- if (!doingAlpha && alphaOnly) {
+ bool alphaOnly = (config == SkBitmap::kA1_Config ||
+ config == SkBitmap::kA8_Config);
+
+ if (!isAlpha && alphaOnly) {
// For alpha only images, we stretch a single pixel of black for
// the color/shape part.
SkAutoTUnref<SkPDFInt> one(new SkPDFInt(1));
insert("Width", one.get());
insert("Height", one.get());
} else {
- insertInt("Width", srcRect.width());
- insertInt("Height", srcRect.height());
+ insertInt("Width", fSrcRect.width());
+ insertInt("Height", fSrcRect.height());
}
- // if (!image mask) {
- if (doingAlpha || alphaOnly) {
+ if (isAlpha || alphaOnly) {
insertName("ColorSpace", "DeviceGray");
} else if (config == SkBitmap::kIndex8_Config) {
- SkAutoLockPixels alp(bitmap);
+ SkAutoLockPixels alp(fBitmap);
insert("ColorSpace",
- makeIndexedColorSpace(bitmap.getColorTable()))->unref();
+ makeIndexedColorSpace(fBitmap.getColorTable()))->unref();
} else {
insertName("ColorSpace", "DeviceRGB");
}
- // }
int bitsPerComp = 8;
if (config == SkBitmap::kARGB_4444_Config) {
bitsPerComp = 4;
- } else if (doingAlpha && config == SkBitmap::kA1_Config) {
+ } else if (isAlpha && config == SkBitmap::kA1_Config) {
bitsPerComp = 1;
}
insertInt("BitsPerComponent", bitsPerComp);
if (config == SkBitmap::kRGB_565_Config) {
+ SkASSERT(!isAlpha);
SkAutoTUnref<SkPDFInt> zeroVal(new SkPDFInt(0));
SkAutoTUnref<SkPDFScalar> scale5Val(
new SkPDFScalar(SkFloatToScalar(8.2258f))); // 255/2^5-1
@@ -337,3 +434,54 @@ SkPDFImage::SkPDFImage(SkStream* imageData,
insert("Decode", decodeValue.get());
}
}
+
+SkStream* SkPDFImage::getCompressedStream() {
+ SkDynamicMemoryWStream dctCompressedWStream;
+ if (fEncoder && fEncoder(&dctCompressedWStream, fBitmap, fSrcRect)) {
+ // Ensure compressed version is smaller than the uncompressed version
+ if (dctCompressedWStream.getOffset() <
+ get_uncompressed_size(fBitmap, fSrcRect)) {
+ SkData* data = dctCompressedWStream.copyToData();
+ SkMemoryStream* stream = SkNEW_ARGS(SkMemoryStream, (data));
+ data->unref();
+ return stream;
+ }
+ }
+ return NULL;
+}
+
+bool SkPDFImage::populate(SkPDFCatalog* catalog) {
+ if (getState() == kUnused_State) {
+ // Initializing image data for the first time.
+ if (!skip_compression(catalog)) {
+ SkAutoTUnref<SkStream> stream(getCompressedStream());
+ if (stream.get() != NULL) {
+ setData(stream.get());
+ insertName("Filter", "DCTDecode");
+ insertInt("ColorTransform", kNoColorTransform);
+ insertInt("Length", getData()->getLength());
+ setState(kCompressed_State);
+ }
+ }
+
+ // Fallback if it doesn't work.
+ if (getState() == kUnused_State) {
+ SkAutoTUnref<SkStream> stream(extract_image_data(fBitmap,
+ fSrcRect));
+ setData(stream.get());
+ return INHERITED::populate(catalog);
+ }
+ } else if (getState() == kNoCompression_State &&
+ !skip_compression(catalog) &&
+ (SkFlate::HaveFlate() || fEncoder)) {
+ // Compression has not been requested when the stream was first created.
+ // But a new Catalog would want it compressed.
+ if (!getSubstitute()) {
+ SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this));
+ setSubstitute(substitute);
+ catalog->setSubstitute(this, substitute);
+ }
+ return false;
+ }
+ return true;
+}
« no previous file with comments | « src/pdf/SkPDFImage.h ('k') | src/pdf/SkPDFImageStream.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698