1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "SkPDFImage.h" 18 19 #include "SkBitmap.h" 20 #include "SkColor.h" 21 #include "SkColorPriv.h" 22 #include "SkPaint.h" 23 #include "SkPackBits.h" 24 #include "SkPDFCatalog.h" 25 #include "SkRect.h" 26 #include "SkStream.h" 27 #include "SkString.h" 28 #include "SkUnPreMultiply.h" 29 30 namespace { 31 32 void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect, 33 SkStream** imageData, SkStream** alphaData) { 34 SkMemoryStream* image = NULL; 35 SkMemoryStream* alpha = NULL; 36 bool hasAlpha = false; 37 bool isTransparent = false; 38 39 bitmap.lockPixels(); 40 switch (bitmap.getConfig()) { 41 case SkBitmap::kIndex8_Config: { 42 const int rowBytes = srcRect.width(); 43 image = new SkMemoryStream(rowBytes * srcRect.height()); 44 uint8_t* dst = (uint8_t*)image->getMemoryBase(); 45 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 46 memcpy(dst, bitmap.getAddr8(srcRect.fLeft, y), rowBytes); 47 dst += rowBytes; 48 } 49 break; 50 } 51 case SkBitmap::kRLE_Index8_Config: { 52 const int rowBytes = srcRect.width(); 53 image = new SkMemoryStream(rowBytes * srcRect.height()); 54 uint8_t* dst = (uint8_t*)image->getMemoryBase(); 55 const SkBitmap::RLEPixels* rle = 56 (const SkBitmap::RLEPixels*)bitmap.getPixels(); 57 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 58 SkPackBits::Unpack8(dst, srcRect.fLeft, rowBytes, 59 rle->packedAtY(y)); 60 dst += rowBytes; 61 } 62 break; 63 } 64 case SkBitmap::kARGB_4444_Config: { 65 isTransparent = true; 66 const int rowBytes = (srcRect.width() * 3 + 1) / 2; 67 const int alphaRowBytes = (srcRect.width() + 1) / 2; 68 image = new SkMemoryStream(rowBytes * srcRect.height()); 69 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height()); 70 uint8_t* dst = (uint8_t*)image->getMemoryBase(); 71 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase(); 72 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 73 uint16_t* src = bitmap.getAddr16(0, y); 74 int x; 75 for (x = srcRect.fLeft; x + 1 < srcRect.fRight; x += 2) { 76 dst[0] = (SkGetPackedR4444(src[x]) << 4) | 77 SkGetPackedG4444(src[x]); 78 dst[1] = (SkGetPackedB4444(src[x]) << 4) | 79 SkGetPackedR4444(src[x + 1]); 80 dst[2] = (SkGetPackedG4444(src[x + 1]) << 4) | 81 SkGetPackedB4444(src[x + 1]); 82 dst += 3; 83 alphaDst[0] = (SkGetPackedA4444(src[x]) << 4) | 84 SkGetPackedA4444(src[x + 1]); 85 if (alphaDst[0] != 0xFF) 86 hasAlpha = true; 87 if (alphaDst[0]) 88 isTransparent = false; 89 alphaDst++; 90 } 91 if (srcRect.width() & 1) { 92 dst[0] = (SkGetPackedR4444(src[x]) << 4) | 93 SkGetPackedG4444(src[x]); 94 dst[1] = (SkGetPackedB4444(src[x]) << 4); 95 dst += 2; 96 alphaDst[0] = (SkGetPackedA4444(src[x]) << 4); 97 if (alphaDst[0] != 0xF0) 98 hasAlpha = true; 99 if (alphaDst[0] & 0xF0) 100 isTransparent = false; 101 alphaDst++; 102 } 103 } 104 break; 105 } 106 case SkBitmap::kRGB_565_Config: { 107 const int rowBytes = srcRect.width() * 3; 108 image = new SkMemoryStream(rowBytes * srcRect.height()); 109 uint8_t* dst = (uint8_t*)image->getMemoryBase(); 110 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 111 uint16_t* src = bitmap.getAddr16(0, y); 112 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { 113 dst[0] = SkGetPackedR16(src[x]); 114 dst[1] = SkGetPackedG16(src[x]); 115 dst[2] = SkGetPackedB16(src[x]); 116 dst += 3; 117 } 118 } 119 break; 120 } 121 case SkBitmap::kARGB_8888_Config: { 122 isTransparent = true; 123 const int rowBytes = srcRect.width() * 3; 124 image = new SkMemoryStream(rowBytes * srcRect.height()); 125 alpha = new SkMemoryStream(srcRect.width() * srcRect.height()); 126 uint8_t* dst = (uint8_t*)image->getMemoryBase(); 127 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase(); 128 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 129 uint32_t* src = bitmap.getAddr32(0, y); 130 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { 131 dst[0] = SkGetPackedR32(src[x]); 132 dst[1] = SkGetPackedG32(src[x]); 133 dst[2] = SkGetPackedB32(src[x]); 134 dst += 3; 135 alphaDst[0] = SkGetPackedA32(src[x]); 136 if (alphaDst[0] != 0xFF) 137 hasAlpha = true; 138 if (alphaDst[0]) 139 isTransparent = false; 140 alphaDst++; 141 } 142 } 143 break; 144 } 145 case SkBitmap::kA1_Config: { 146 isTransparent = true; 147 image = new SkMemoryStream(1); 148 ((uint8_t*)image->getMemoryBase())[0] = 0; 149 150 const int alphaRowBytes = (srcRect.width() + 7) / 8; 151 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height()); 152 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase(); 153 int offset1 = srcRect.fLeft % 8; 154 int offset2 = 8 - offset1; 155 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 156 uint8_t* src = bitmap.getAddr1(0, y); 157 // This may read up to one byte after src, but the potentially 158 // invalid bits are never used for computation. 159 for (int x = srcRect.fLeft; x < srcRect.fRight; x += 8) { 160 if (offset1) { 161 alphaDst[0] = src[x / 8] << offset1 | 162 src[x / 8 + 1] >> offset2; 163 } else { 164 alphaDst[0] = src[x / 8]; 165 } 166 if (x + 7 < srcRect.fRight && alphaDst[0] != 0xFF) 167 hasAlpha = true; 168 if (x + 7 < srcRect.fRight && alphaDst[0]) 169 isTransparent = false; 170 alphaDst++; 171 } 172 // Calculate the mask of bits we're interested in within the 173 // last byte of alphaDst. 174 // width mod 8 == 1 -> 0x80 ... width mod 8 == 7 -> 0xFE 175 uint8_t mask = ~((1 << (8 - (srcRect.width() % 8))) - 1); 176 if (srcRect.width() % 8 && (alphaDst[-1] & mask) != mask) 177 hasAlpha = true; 178 if (srcRect.width() % 8 && (alphaDst[-1] & mask)) 179 isTransparent = false; 180 } 181 break; 182 } 183 case SkBitmap::kA8_Config: { 184 isTransparent = true; 185 image = new SkMemoryStream(1); 186 ((uint8_t*)image->getMemoryBase())[0] = 0; 187 188 const int alphaRowBytes = srcRect.width(); 189 alpha = new SkMemoryStream(alphaRowBytes * srcRect.height()); 190 uint8_t* alphaDst = (uint8_t*)alpha->getMemoryBase(); 191 for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { 192 uint8_t* src = bitmap.getAddr8(0, y); 193 for (int x = srcRect.fLeft; x < srcRect.fRight; x++) { 194 alphaDst[0] = src[x]; 195 if (alphaDst[0] != 0xFF) 196 hasAlpha = true; 197 if (alphaDst[0]) 198 isTransparent = false; 199 alphaDst++; 200 } 201 } 202 break; 203 } 204 default: 205 SkASSERT(false); 206 } 207 bitmap.unlockPixels(); 208 209 if (isTransparent) { 210 SkSafeUnref(image); 211 } else { 212 *imageData = image; 213 } 214 215 if (isTransparent || !hasAlpha) { 216 SkSafeUnref(alpha); 217 } else { 218 *alphaData = alpha; 219 } 220 } 221 222 SkPDFArray* makeIndexedColorSpace(SkColorTable* table) { 223 SkPDFArray* result = new SkPDFArray(); 224 result->reserve(4); 225 result->append(new SkPDFName("Indexed"))->unref(); 226 result->append(new SkPDFName("DeviceRGB"))->unref();; 227 result->append(new SkPDFInt(table->count() - 1))->unref(); 228 229 // Potentially, this could be represented in fewer bytes with a stream. 230 // Max size as a string is 1.5k. 231 SkString index; 232 for (int i = 0; i < table->count(); i++) { 233 char buf[3]; 234 SkColor color = SkUnPreMultiply::PMColorToColor((*table)[i]); 235 buf[0] = SkGetPackedR32(color); 236 buf[1] = SkGetPackedG32(color); 237 buf[2] = SkGetPackedB32(color); 238 index.append(buf, 3); 239 } 240 result->append(new SkPDFString(index))->unref(); 241 return result; 242 } 243 244 }; // namespace 245 246 // static 247 SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap, 248 const SkIRect& srcRect, 249 const SkPaint& paint) { 250 if (bitmap.getConfig() == SkBitmap::kNo_Config) 251 return NULL; 252 253 SkStream* imageData = NULL; 254 SkStream* alphaData = NULL; 255 extractImageData(bitmap, srcRect, &imageData, &alphaData); 256 SkAutoUnref unrefImageData(imageData); 257 SkAutoUnref unrefAlphaData(alphaData); 258 if (!imageData) { 259 SkASSERT(!alphaData); 260 return NULL; 261 } 262 263 SkPDFImage* image = 264 new SkPDFImage(imageData, bitmap, srcRect, false, paint); 265 266 if (alphaData != NULL) { 267 image->addSMask(new SkPDFImage(alphaData, bitmap, srcRect, true, 268 paint))->unref(); 269 } 270 return image; 271 } 272 273 SkPDFImage::~SkPDFImage() { 274 fResources.unrefAll(); 275 } 276 277 SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) { 278 fResources.push(mask); 279 mask->ref(); 280 insert("SMask", new SkPDFObjRef(mask))->unref(); 281 return mask; 282 } 283 284 void SkPDFImage::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 285 bool indirect) { 286 if (indirect) 287 return emitIndirectObject(stream, catalog); 288 289 fStream->emitObject(stream, catalog, indirect); 290 } 291 292 size_t SkPDFImage::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 293 if (indirect) 294 return getIndirectOutputSize(catalog); 295 296 return fStream->getOutputSize(catalog, indirect); 297 } 298 299 void SkPDFImage::getResources(SkTDArray<SkPDFObject*>* resourceList) { 300 if (fResources.count()) { 301 resourceList->setReserve(resourceList->count() + fResources.count()); 302 for (int i = 0; i < fResources.count(); i++) { 303 resourceList->push(fResources[i]); 304 fResources[i]->ref(); 305 fResources[i]->getResources(resourceList); 306 } 307 } 308 } 309 310 SkPDFImage::SkPDFImage(SkStream* imageData, const SkBitmap& bitmap, 311 const SkIRect& srcRect, bool doingAlpha, 312 const SkPaint& paint) { 313 fStream = new SkPDFStream(imageData); 314 fStream->unref(); // SkRefPtr and new both took a reference. 315 316 SkBitmap::Config config = bitmap.getConfig(); 317 bool alphaOnly = (config == SkBitmap::kA1_Config || 318 config == SkBitmap::kA8_Config); 319 320 insert("Type", new SkPDFName("XObject"))->unref(); 321 insert("Subtype", new SkPDFName("Image"))->unref(); 322 323 if (!doingAlpha && alphaOnly) { 324 // For alpha only images, we stretch a single pixel of black for 325 // the color/shape part. 326 SkRefPtr<SkPDFInt> one = new SkPDFInt(1); 327 one->unref(); // SkRefPtr and new both took a reference. 328 insert("Width", one.get()); 329 insert("Height", one.get()); 330 } else { 331 insert("Width", new SkPDFInt(srcRect.width()))->unref(); 332 insert("Height", new SkPDFInt(srcRect.height()))->unref(); 333 } 334 335 // if (!image mask) { 336 if (doingAlpha || alphaOnly) { 337 insert("ColorSpace", new SkPDFName("DeviceGray"))->unref(); 338 } else if (config == SkBitmap::kIndex8_Config || 339 config == SkBitmap::kRLE_Index8_Config) { 340 insert("ColorSpace", 341 makeIndexedColorSpace(bitmap.getColorTable()))->unref(); 342 } else { 343 insert("ColorSpace", new SkPDFName("DeviceRGB"))->unref(); 344 } 345 // } 346 347 int bitsPerComp = 8; 348 if (config == SkBitmap::kARGB_4444_Config) 349 bitsPerComp = 4; 350 else if (doingAlpha && config == SkBitmap::kA1_Config) 351 bitsPerComp = 1; 352 insert("BitsPerComponent", new SkPDFInt(bitsPerComp))->unref(); 353 354 if (config == SkBitmap::kRGB_565_Config) { 355 SkRefPtr<SkPDFInt> zeroVal = new SkPDFInt(0); 356 zeroVal->unref(); // SkRefPtr and new both took a reference. 357 SkRefPtr<SkPDFScalar> scale5Val = 358 new SkPDFScalar(8.2258f); // 255/2^5-1 359 scale5Val->unref(); // SkRefPtr and new both took a reference. 360 SkRefPtr<SkPDFScalar> scale6Val = 361 new SkPDFScalar(4.0476f); // 255/2^6-1 362 scale6Val->unref(); // SkRefPtr and new both took a reference. 363 SkRefPtr<SkPDFArray> decodeValue = new SkPDFArray(); 364 decodeValue->unref(); // SkRefPtr and new both took a reference. 365 decodeValue->reserve(6); 366 decodeValue->append(zeroVal.get()); 367 decodeValue->append(scale5Val.get()); 368 decodeValue->append(zeroVal.get()); 369 decodeValue->append(scale6Val.get()); 370 decodeValue->append(zeroVal.get()); 371 decodeValue->append(scale5Val.get()); 372 insert("Decode", decodeValue.get()); 373 } 374 } 375 376 SkPDFObject* SkPDFImage::insert(SkPDFName* key, SkPDFObject* value) { 377 return fStream->insert(key, value); 378 } 379 380 SkPDFObject* SkPDFImage::insert(const char key[], SkPDFObject* value) { 381 return fStream->insert(key, value); 382 } 383