Index: src/pdf/SkPDFImage.cpp |
diff --git a/src/pdf/SkPDFImage.cpp b/src/pdf/SkPDFImage.cpp |
index a5cb4c20d1b9e187948cc6654d590b219df4d686..6ede7aaf515d54b5155ade6f8b9ee6033eb01cec 100644 |
--- a/src/pdf/SkPDFImage.cpp |
+++ b/src/pdf/SkPDFImage.cpp |
@@ -10,204 +10,311 @@ |
#include "SkBitmap.h" |
#include "SkColor.h" |
#include "SkColorPriv.h" |
+#include "SkData.h" |
+#include "SkFlate.h" |
#include "SkPDFCatalog.h" |
#include "SkRect.h" |
#include "SkStream.h" |
#include "SkString.h" |
#include "SkUnPreMultiply.h" |
-namespace { |
+static const int kNoColorTransform = 0; |
-void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect, |
- SkStream** imageData, SkStream** alphaData) { |
- SkMemoryStream* image = NULL; |
- SkMemoryStream* alpha = NULL; |
- bool hasAlpha = false; |
- bool isTransparent = false; |
+static bool skip_compression(SkPDFCatalog* catalog) { |
+ return SkToBool(catalog->getDocumentFlags() & |
+ SkPDFDocument::kFavorSpeedOverSize_Flags); |
+} |
- bitmap.lockPixels(); |
+static size_t get_uncompressed_size(const SkBitmap& bitmap, |
+ const SkIRect& srcRect) { |
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); |
- dst += rowBytes; |
+ case SkBitmap::kIndex8_Config: |
+ return srcRect.width() * srcRect.height(); |
+ case SkBitmap::kARGB_4444_Config: |
+ return ((srcRect.width() * 3 + 1) / 2) * srcRect.height(); |
+ case SkBitmap::kRGB_565_Config: |
+ return srcRect.width() * 3 * srcRect.height(); |
+ case SkBitmap::kARGB_8888_Config: |
+ return srcRect.width() * 3 * srcRect.height(); |
+ case SkBitmap::kA1_Config: |
+ case SkBitmap::kA8_Config: |
+ return 1; |
+ default: |
+ SkASSERT(false); |
+ return 0; |
+ } |
+} |
+ |
+static SkStream* extract_index8_image(const SkBitmap& bitmap, |
+ const SkIRect& srcRect) { |
+ const int rowBytes = srcRect.width(); |
+ SkStream* stream = SkNEW_ARGS(SkMemoryStream, |
+ (get_uncompressed_size(bitmap, srcRect))); |
+ uint8_t* dst = (uint8_t*)stream->getMemoryBase(); |
+ |
+ for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { |
+ memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes); |
+ dst += rowBytes; |
+ } |
+ return stream; |
+} |
+ |
+static SkStream* extract_argb4444_data(const SkBitmap& bitmap, |
+ const SkIRect& srcRect, |
+ bool extractAlpha, |
+ bool* isOpaque, |
+ bool* isTransparent) { |
+ SkStream* stream; |
+ uint8_t* dst = NULL; |
+ if (extractAlpha) { |
+ const int alphaRowBytes = (srcRect.width() + 1) / 2; |
+ stream = SkNEW_ARGS(SkMemoryStream, |
+ (alphaRowBytes * srcRect.height())); |
+ } else { |
+ stream = SkNEW_ARGS(SkMemoryStream, |
+ (get_uncompressed_size(bitmap, srcRect))); |
+ } |
+ dst = (uint8_t*)stream->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) { |
+ if (extractAlpha) { |
+ dst[0] = (SkGetPackedA4444(src[x]) << 4) | |
+ SkGetPackedA4444(src[x + 1]); |
+ *isOpaque &= dst[0] == SK_AlphaOPAQUE; |
+ *isTransparent &= dst[0] == SK_AlphaTRANSPARENT; |
+ dst++; |
+ } else { |
+ dst[0] = (SkGetPackedR4444(src[x]) << 4) | |
+ SkGetPackedG4444(src[x]); |
+ dst[1] = (SkGetPackedB4444(src[x]) << 4) | |
+ SkGetPackedR4444(src[x + 1]); |
+ dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) | |
+ SkGetPackedB4444(src[x + 1]); |
+ dst += 3; |
} |
- 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; |
- for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) { |
- dst[0] = (SkGetPackedR4444(src[x]) << 4) | |
- SkGetPackedG4444(src[x]); |
- dst[1] = (SkGetPackedB4444(src[x]) << 4) | |
- SkGetPackedR4444(src[x + 1]); |
- 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++; |
- } |
+ if (srcRect.width() & 1) { |
+ if (extractAlpha) { |
+ dst[0] = (SkGetPackedA4444(src[x]) << 4); |
+ *isOpaque &= dst[0] == (SK_AlphaOPAQUE & 0xF0); |
+ *isTransparent &= dst[0] == (SK_AlphaTRANSPARENT & 0xF0); |
+ dst++; |
+ |
+ } else { |
+ dst[0] = (SkGetPackedR4444(src[x]) << 4) | |
+ SkGetPackedG4444(src[x]); |
+ dst[1] = (SkGetPackedB4444(src[x]) << 4); |
+ dst += 2; |
} |
- 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); |
- for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { |
- dst[0] = SkGetPackedR16(src[x]); |
- dst[1] = SkGetPackedG16(src[x]); |
- dst[2] = SkGetPackedB16(src[x]); |
- dst += 3; |
- } |
+ } |
+ return stream; |
+} |
+ |
+static SkStream* extract_rgb565_image(const SkBitmap& bitmap, |
+ const SkIRect& srcRect) { |
+ SkStream* stream = SkNEW_ARGS(SkMemoryStream, |
+ (get_uncompressed_size(bitmap, |
+ srcRect))); |
+ uint8_t* dst = (uint8_t*)stream->getMemoryBase(); |
+ for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { |
+ uint16_t* src = bitmap.getAddr16(0, y); |
+ for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { |
+ dst[0] = SkGetPackedR16(src[x]); |
+ dst[1] = SkGetPackedG16(src[x]); |
+ dst[2] = SkGetPackedB16(src[x]); |
+ dst += 3; |
+ } |
+ } |
+ return stream; |
+} |
+ |
+static SkStream* extract_argb8888_data(const SkBitmap& bitmap, |
+ const SkIRect& srcRect, |
+ bool extractAlpha, |
+ bool* isOpaque, |
+ bool* isTransparent) { |
+ SkStream* stream; |
+ if (extractAlpha) { |
+ stream = SkNEW_ARGS(SkMemoryStream, |
+ (srcRect.width() * srcRect.height())); |
+ } else { |
+ stream = SkNEW_ARGS(SkMemoryStream, |
+ (get_uncompressed_size(bitmap, srcRect))); |
+ } |
+ uint8_t* dst = (uint8_t*)stream->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++) { |
+ if (extractAlpha) { |
+ dst[0] = SkGetPackedA32(src[x]); |
+ *isOpaque &= dst[0] == SK_AlphaOPAQUE; |
+ *isTransparent &= dst[0] == SK_AlphaTRANSPARENT; |
+ dst++; |
+ } else { |
+ dst[0] = SkGetPackedR32(src[x]); |
+ dst[1] = SkGetPackedG32(src[x]); |
+ dst[2] = SkGetPackedB32(src[x]); |
+ dst += 3; |
} |
- 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++) { |
- dst[0] = SkGetPackedR32(src[x]); |
- dst[1] = SkGetPackedG32(src[x]); |
- dst[2] = SkGetPackedB32(src[x]); |
- dst += 3; |
- alphaDst[0] = SkGetPackedA32(src[x]); |
- if (alphaDst[0] != 0xFF) { |
- hasAlpha = true; |
- } |
- if (alphaDst[0]) { |
- isTransparent = false; |
- } |
- alphaDst++; |
- } |
+ } |
+ return stream; |
+} |
+ |
+static SkStream* extract_a1_alpha(const SkBitmap& bitmap, |
+ const SkIRect& srcRect, |
+ bool* isOpaque, |
+ bool* isTransparent) { |
+ const int alphaRowBytes = (srcRect.width() + 7) / 8; |
+ SkStream* stream = SkNEW_ARGS(SkMemoryStream, |
+ (alphaRowBytes * srcRect.height())); |
+ uint8_t* alphaDst = (uint8_t*)stream->getMemoryBase(); |
+ |
+ int offset1 = srcRect.fLeft % 8; |
+ int offset2 = 8 - offset1; |
+ |
+ for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { |
+ uint8_t* src = bitmap.getAddr1(0, y); |
+ // This may read up to one byte after src, but the |
+ // potentially invalid bits are never used for computation. |
+ for (int x = srcRect.fLeft; x < srcRect.fRight; x += 8) { |
+ if (offset1) { |
+ alphaDst[0] = src[x / 8] << offset1 | |
+ src[x / 8 + 1] >> offset2; |
+ } else { |
+ alphaDst[0] = src[x / 8]; |
} |
- break; |
+ if (x + 7 < srcRect.fRight) { |
+ *isOpaque &= alphaDst[0] == SK_AlphaOPAQUE; |
+ *isTransparent &= alphaDst[0] == SK_AlphaTRANSPARENT; |
+ } |
+ alphaDst++; |
+ } |
+ // Calculate the mask of bits we're interested in within the |
+ // last byte of alphaDst. |
+ // width mod 8 == 1 -> 0x80 ... width mod 8 == 7 -> 0xFE |
+ uint8_t mask = ~((1 << (8 - (srcRect.width() % 8))) - 1); |
+ if (srcRect.width() % 8) { |
+ *isOpaque &= (alphaDst[-1] & mask) == (SK_AlphaOPAQUE & mask); |
+ *isTransparent &= |
+ (alphaDst[-1] & mask) == (SK_AlphaTRANSPARENT & mask); |
} |
- 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(); |
- int offset1 = srcRect.fLeft % 8; |
- int offset2 = 8 - offset1; |
- for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { |
- uint8_t* src = bitmap.getAddr1(0, y); |
- // This may read up to one byte after src, but the potentially |
- // invalid bits are never used for computation. |
- for (int x = srcRect.fLeft; x < srcRect.fRight; x += 8) { |
- if (offset1) { |
- alphaDst[0] = src[x / 8] << offset1 | |
- src[x / 8 + 1] >> offset2; |
- } else { |
- alphaDst[0] = src[x / 8]; |
- } |
- if (x + 7 < srcRect.fRight && alphaDst[0] != 0xFF) { |
- hasAlpha = true; |
- } |
- if (x + 7 < srcRect.fRight && alphaDst[0]) { |
- isTransparent = false; |
- } |
- alphaDst++; |
- } |
- // Calculate the mask of bits we're interested in within the |
- // last byte of alphaDst. |
- // width mod 8 == 1 -> 0x80 ... width mod 8 == 7 -> 0xFE |
- uint8_t mask = ~((1 << (8 - (srcRect.width() % 8))) - 1); |
- if (srcRect.width() % 8 && (alphaDst[-1] & mask) != mask) { |
- hasAlpha = true; |
- } |
- if (srcRect.width() % 8 && (alphaDst[-1] & mask)) { |
- isTransparent = false; |
- } |
+ } |
+ return stream; |
+} |
+ |
+static SkStream* extract_a8_alpha(const SkBitmap& bitmap, |
+ const SkIRect& srcRect, |
+ bool* isOpaque, |
+ bool* isTransparent) { |
+ const int alphaRowBytes = srcRect.width(); |
+ SkStream* stream = SkNEW_ARGS(SkMemoryStream, |
+ (alphaRowBytes * srcRect.height())); |
+ uint8_t* alphaDst = (uint8_t*)stream->getMemoryBase(); |
+ |
+ for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { |
+ uint8_t* src = bitmap.getAddr8(0, y); |
+ for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { |
+ alphaDst[0] = src[x]; |
+ *isOpaque &= alphaDst[0] == SK_AlphaOPAQUE; |
+ *isTransparent &= alphaDst[0] == SK_AlphaTRANSPARENT; |
+ alphaDst++; |
+ } |
+ } |
+ return stream; |
+} |
+ |
+static SkStream* create_black_image() { |
+ SkStream* stream = SkNEW_ARGS(SkMemoryStream, (1)); |
+ ((uint8_t*)stream->getMemoryBase())[0] = 0; |
+ return stream; |
+} |
+ |
+/** |
+ * Extract either the color or image data from a SkBitmap into a SkStream. |
+ * @param bitmap Bitmap to extract data from. |
+ * @param srcRect Region in the bitmap to extract. |
+ * @param extractAlpha Set to true to extract the alpha data or false to |
+ * extract the color data. |
+ * @param isTransparent Pointer to a bool to output whether the alpha is |
+ * completely transparent. May be NULL. Only valid when |
+ * extractAlpha == true. |
+ * @return Unencoded image data, or NULL if either data was not |
+ * available or alpha data was requested but the image was |
+ * entirely transparent or opaque. |
+ */ |
+static SkStream* extract_image_data(const SkBitmap& bitmap, |
+ const SkIRect& srcRect, |
+ bool extractAlpha, bool* isTransparent) { |
+ SkBitmap::Config config = bitmap.config(); |
+ if (extractAlpha && (config == SkBitmap::kIndex8_Config || |
+ config == SkBitmap::kRGB_565_Config)) { |
+ if (isTransparent != NULL) { |
+ *isTransparent = false; |
+ } |
+ return NULL; |
+ } |
+ bool isOpaque = true; |
+ bool transparent = extractAlpha; |
+ SkStream* stream = NULL; |
+ |
+ bitmap.lockPixels(); |
+ switch (config) { |
+ case SkBitmap::kIndex8_Config: |
+ if (!extractAlpha) { |
+ stream = extract_index8_image(bitmap, srcRect); |
} |
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(); |
- for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { |
- uint8_t* src = bitmap.getAddr8(0, y); |
- for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { |
- alphaDst[0] = src[x]; |
- if (alphaDst[0] != 0xFF) { |
- hasAlpha = true; |
- } |
- if (alphaDst[0]) { |
- isTransparent = false; |
- } |
- alphaDst++; |
- } |
+ case SkBitmap::kARGB_4444_Config: |
+ stream = extract_argb4444_data(bitmap, srcRect, extractAlpha, |
+ &isOpaque, &transparent); |
+ break; |
+ case SkBitmap::kRGB_565_Config: |
+ if (!extractAlpha) { |
+ stream = extract_rgb565_image(bitmap, srcRect); |
+ } |
+ break; |
+ case SkBitmap::kARGB_8888_Config: |
+ stream = extract_argb8888_data(bitmap, srcRect, extractAlpha, |
+ &isOpaque, &transparent); |
+ break; |
+ case SkBitmap::kA1_Config: |
+ if (!extractAlpha) { |
+ stream = create_black_image(); |
+ } else { |
+ stream = extract_a1_alpha(bitmap, srcRect, |
+ &isOpaque, &transparent); |
+ } |
+ break; |
+ case SkBitmap::kA8_Config: |
+ if (!extractAlpha) { |
+ stream = create_black_image(); |
+ } else { |
+ stream = extract_a8_alpha(bitmap, srcRect, |
+ &isOpaque, &transparent); |
} |
break; |
- } |
default: |
SkASSERT(false); |
} |
bitmap.unlockPixels(); |
- if (isTransparent) { |
- SkSafeUnref(image); |
- } else { |
- *imageData = image; |
+ if (isTransparent != NULL) { |
+ *isTransparent = transparent; |
} |
- |
- if (isTransparent || !hasAlpha) { |
- SkSafeUnref(alpha); |
- } else { |
- *alphaData = alpha; |
+ if (extractAlpha && (transparent || isOpaque)) { |
+ SkSafeUnref(stream); |
+ return NULL; |
} |
+ return stream; |
} |
-SkPDFArray* makeIndexedColorSpace(SkColorTable* table) { |
+static SkPDFArray* make_indexed_color_space(SkColorTable* table) { |
SkPDFArray* result = new SkPDFArray(); |
result->reserve(4); |
result->appendName("Indexed"); |
@@ -229,8 +336,6 @@ SkPDFArray* makeIndexedColorSpace(SkColorTable* table) { |
return result; |
} |
-}; // namespace |
- |
// static |
SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap, |
const SkIRect& srcRect, |
@@ -239,24 +344,29 @@ SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap, |
return NULL; |
} |
- SkStream* imageData = NULL; |
- SkStream* alphaData = NULL; |
- extractImageData(bitmap, srcRect, &imageData, &alphaData); |
- SkAutoUnref unrefImageData(imageData); |
- SkAutoUnref unrefAlphaData(alphaData); |
- if (!imageData) { |
- SkASSERT(!alphaData); |
+ bool isTransparent = false; |
+ SkAutoTUnref<SkStream> alphaData; |
+ if (!bitmap.isOpaque()) { |
+ // Note that isOpaque is not guaranteed to return false for bitmaps |
+ // with alpha support but a completely opaque alpha channel, |
+ // so alphaData may still be NULL if we have a completely opaque |
+ // (or transparent) bitmap. |
+ alphaData.reset( |
+ extract_image_data(bitmap, srcRect, true, &isTransparent)); |
+ } |
+ if (isTransparent) { |
return NULL; |
} |
- 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(); |
+ SkPDFImage* image = SkNEW_ARGS(SkPDFImage, (NULL, bitmap, |
+ false, srcRect, encoder)); |
+ if (alphaData.get() != NULL) { |
+ SkAutoTUnref<SkPDFImage> mask( |
+ SkNEW_ARGS(SkPDFImage, (alphaData.get(), bitmap, |
+ true, srcRect, NULL))); |
+ image->addSMask(mask); |
} |
+ |
return image; |
} |
@@ -276,51 +386,62 @@ void SkPDFImage::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, |
GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects); |
} |
-SkPDFImage::SkPDFImage(SkStream* imageData, |
+SkPDFImage::SkPDFImage(SkStream* stream, |
const SkBitmap& bitmap, |
+ bool isAlpha, |
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), |
+ fIsAlpha(isAlpha), |
+ fSrcRect(srcRect), |
+ fEncoder(encoder) { |
+ |
+ if (stream != NULL) { |
+ setData(stream); |
+ fStreamValid = true; |
+ } else { |
+ fStreamValid = false; |
+ } |
+ |
+ 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(); |
+ make_indexed_color_space(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 +458,57 @@ SkPDFImage::SkPDFImage(SkStream* imageData, |
insert("Decode", decodeValue.get()); |
} |
} |
+ |
+SkPDFImage::SkPDFImage(SkPDFImage& pdfImage) |
+ : SkPDFStream(pdfImage), |
+ fBitmap(pdfImage.fBitmap), |
+ fIsAlpha(pdfImage.fIsAlpha), |
+ fSrcRect(pdfImage.fSrcRect), |
+ fEncoder(pdfImage.fEncoder), |
+ fStreamValid(pdfImage.fStreamValid) { |
+ // Nothing to do here - the image params are already copied in SkPDFStream's |
+ // constructor, and the bitmap will be regenerated and encoded in |
+ // populate. |
+} |
+ |
+bool SkPDFImage::populate(SkPDFCatalog* catalog) { |
+ if (getState() == kUnused_State) { |
+ // Initializing image data for the first time. |
+ SkDynamicMemoryWStream dctCompressedWStream; |
+ if (!skip_compression(catalog) && fEncoder && |
+ get_uncompressed_size(fBitmap, fSrcRect) > 1 && |
+ fEncoder(&dctCompressedWStream, fBitmap, fSrcRect) && |
+ dctCompressedWStream.getOffset() < |
+ get_uncompressed_size(fBitmap, fSrcRect)) { |
+ SkAutoTUnref<SkData> data(dctCompressedWStream.copyToData()); |
+ SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream, (data))); |
+ setData(stream.get()); |
+ |
+ insertName("Filter", "DCTDecode"); |
+ insertInt("ColorTransform", kNoColorTransform); |
+ insertInt("Length", getData()->getLength()); |
+ setState(kCompressed_State); |
+ return true; |
+ } |
+ // Fallback method |
+ if (!fStreamValid) { |
+ SkAutoTUnref<SkStream> stream( |
+ extract_image_data(fBitmap, fSrcRect, fIsAlpha, NULL)); |
+ setData(stream); |
+ fStreamValid = true; |
+ } |
+ 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 the new catalog wants it compressed. |
+ if (!getSubstitute()) { |
+ SkPDFStream* substitute = SkNEW_ARGS(SkPDFImage, (*this)); |
+ setSubstitute(substitute); |
+ catalog->setSubstitute(this, substitute); |
+ } |
+ return false; |
+ } |
+ return true; |
+} |