1 /* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SkPixmap_DEFINED 9 #define SkPixmap_DEFINED 10 11 #include "SkColor.h" 12 #include "SkFilterQuality.h" 13 #include "SkImageInfo.h" 14 15 class SkColorTable; 16 class SkData; 17 struct SkMask; 18 19 /** 20 * Pairs SkImageInfo with actual pixels and rowbytes. This class does not try to manage the 21 * lifetime of the pixel memory (nor the colortable if provided). 22 */ 23 class SK_API SkPixmap { 24 public: SkPixmap()25 SkPixmap() 26 : fPixels(NULL), fCTable(NULL), fRowBytes(0), fInfo(SkImageInfo::MakeUnknown(0, 0)) 27 {} 28 29 SkPixmap(const SkImageInfo& info, const void* addr, size_t rowBytes, 30 SkColorTable* ctable = NULL) fPixels(addr)31 : fPixels(addr), fCTable(ctable), fRowBytes(rowBytes), fInfo(info) 32 { 33 if (kIndex_8_SkColorType == info.colorType()) { 34 SkASSERT(ctable); 35 } else { 36 SkASSERT(NULL == ctable); 37 } 38 } 39 40 void reset(); 41 void reset(const SkImageInfo& info, const void* addr, size_t rowBytes, 42 SkColorTable* ctable = NULL); reset(const SkImageInfo & info)43 void reset(const SkImageInfo& info) { 44 this->reset(info, NULL, 0, NULL); 45 } 46 47 // overrides the colorspace in the SkImageInfo of the pixmap 48 void setColorSpace(sk_sp<SkColorSpace>); 49 50 /** 51 * If supported, set this pixmap to point to the pixels in the specified mask and return true. 52 * On failure, return false and set this pixmap to empty. 53 */ 54 bool SK_WARN_UNUSED_RESULT reset(const SkMask&); 55 56 /** 57 * Computes the intersection of area and this pixmap. If that intersection is non-empty, 58 * set subset to that intersection and return true. 59 * 60 * On failure, return false and ignore the subset parameter. 61 */ 62 bool SK_WARN_UNUSED_RESULT extractSubset(SkPixmap* subset, const SkIRect& area) const; 63 info()64 const SkImageInfo& info() const { return fInfo; } rowBytes()65 size_t rowBytes() const { return fRowBytes; } addr()66 const void* addr() const { return fPixels; } ctable()67 SkColorTable* ctable() const { return fCTable; } 68 width()69 int width() const { return fInfo.width(); } height()70 int height() const { return fInfo.height(); } colorType()71 SkColorType colorType() const { return fInfo.colorType(); } alphaType()72 SkAlphaType alphaType() const { return fInfo.alphaType(); } colorSpace()73 SkColorSpace* colorSpace() const { return fInfo.colorSpace(); } isOpaque()74 bool isOpaque() const { return fInfo.isOpaque(); } 75 bounds()76 SkIRect bounds() const { return SkIRect::MakeWH(this->width(), this->height()); } 77 78 /** 79 * Return the rowbytes expressed as a number of pixels (like width and height). 80 */ rowBytesAsPixels()81 int rowBytesAsPixels() const { return int(fRowBytes >> this->shiftPerPixel()); } 82 83 /** 84 * Return the shift amount per pixel (i.e. 0 for 1-byte per pixel, 1 for 2-bytes per pixel 85 * colortypes, 2 for 4-bytes per pixel colortypes). Return 0 for kUnknown_SkColorType. 86 */ shiftPerPixel()87 int shiftPerPixel() const { return fInfo.shiftPerPixel(); } 88 getSize64()89 uint64_t getSize64() const { return sk_64_mul(fInfo.height(), fRowBytes); } getSafeSize64()90 uint64_t getSafeSize64() const { return fInfo.getSafeSize64(fRowBytes); } getSafeSize()91 size_t getSafeSize() const { return fInfo.getSafeSize(fRowBytes); } 92 93 /** 94 * This will brute-force return true if all of the pixels in the pixmap 95 * are opaque. If there are no pixels, or encounters an error, returns false. 96 */ 97 bool computeIsOpaque() const; 98 99 /** 100 * Converts the pixel at the specified coordinate to an unpremultiplied 101 * SkColor. Note: this ignores any SkColorSpace information, and may return 102 * lower precision data than is actually in the pixel. Alpha only 103 * colortypes (e.g. kAlpha_8_SkColorType) return black with the appropriate 104 * alpha set. The value is undefined for kUnknown_SkColorType or if x or y 105 * are out of bounds, or if the pixtap does not have any pixels. 106 */ 107 SkColor getColor(int x, int y) const; 108 addr(int x,int y)109 const void* addr(int x, int y) const { 110 return (const char*)fPixels + fInfo.computeOffset(x, y, fRowBytes); 111 } addr8()112 const uint8_t* addr8() const { 113 SkASSERT(1 == SkColorTypeBytesPerPixel(fInfo.colorType())); 114 return reinterpret_cast<const uint8_t*>(fPixels); 115 } addr16()116 const uint16_t* addr16() const { 117 SkASSERT(2 == SkColorTypeBytesPerPixel(fInfo.colorType())); 118 return reinterpret_cast<const uint16_t*>(fPixels); 119 } addr32()120 const uint32_t* addr32() const { 121 SkASSERT(4 == SkColorTypeBytesPerPixel(fInfo.colorType())); 122 return reinterpret_cast<const uint32_t*>(fPixels); 123 } addr64()124 const uint64_t* addr64() const { 125 SkASSERT(8 == SkColorTypeBytesPerPixel(fInfo.colorType())); 126 return reinterpret_cast<const uint64_t*>(fPixels); 127 } addrF16()128 const uint16_t* addrF16() const { 129 SkASSERT(8 == SkColorTypeBytesPerPixel(fInfo.colorType())); 130 SkASSERT(kRGBA_F16_SkColorType == fInfo.colorType()); 131 return reinterpret_cast<const uint16_t*>(fPixels); 132 } 133 134 // Offset by the specified x,y coordinates 135 addr8(int x,int y)136 const uint8_t* addr8(int x, int y) const { 137 SkASSERT((unsigned)x < (unsigned)fInfo.width()); 138 SkASSERT((unsigned)y < (unsigned)fInfo.height()); 139 return (const uint8_t*)((const char*)this->addr8() + y * fRowBytes + (x << 0)); 140 } addr16(int x,int y)141 const uint16_t* addr16(int x, int y) const { 142 SkASSERT((unsigned)x < (unsigned)fInfo.width()); 143 SkASSERT((unsigned)y < (unsigned)fInfo.height()); 144 return (const uint16_t*)((const char*)this->addr16() + y * fRowBytes + (x << 1)); 145 } addr32(int x,int y)146 const uint32_t* addr32(int x, int y) const { 147 SkASSERT((unsigned)x < (unsigned)fInfo.width()); 148 SkASSERT((unsigned)y < (unsigned)fInfo.height()); 149 return (const uint32_t*)((const char*)this->addr32() + y * fRowBytes + (x << 2)); 150 } addr64(int x,int y)151 const uint64_t* addr64(int x, int y) const { 152 SkASSERT((unsigned)x < (unsigned)fInfo.width()); 153 SkASSERT((unsigned)y < (unsigned)fInfo.height()); 154 return (const uint64_t*)((const char*)this->addr64() + y * fRowBytes + (x << 3)); 155 } addrF16(int x,int y)156 const uint16_t* addrF16(int x, int y) const { 157 SkASSERT(kRGBA_F16_SkColorType == fInfo.colorType()); 158 return reinterpret_cast<const uint16_t*>(this->addr64(x, y)); 159 } 160 161 // Writable versions 162 writable_addr()163 void* writable_addr() const { return const_cast<void*>(fPixels); } writable_addr(int x,int y)164 void* writable_addr(int x, int y) const { 165 return const_cast<void*>(this->addr(x, y)); 166 } writable_addr8(int x,int y)167 uint8_t* writable_addr8(int x, int y) const { 168 return const_cast<uint8_t*>(this->addr8(x, y)); 169 } writable_addr16(int x,int y)170 uint16_t* writable_addr16(int x, int y) const { 171 return const_cast<uint16_t*>(this->addr16(x, y)); 172 } writable_addr32(int x,int y)173 uint32_t* writable_addr32(int x, int y) const { 174 return const_cast<uint32_t*>(this->addr32(x, y)); 175 } writable_addr64(int x,int y)176 uint64_t* writable_addr64(int x, int y) const { 177 return const_cast<uint64_t*>(this->addr64(x, y)); 178 } writable_addrF16(int x,int y)179 uint16_t* writable_addrF16(int x, int y) const { 180 return reinterpret_cast<uint16_t*>(writable_addr64(x, y)); 181 } 182 183 // copy methods 184 185 bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, 186 int srcX, int srcY) const; readPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes)187 bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes) const { 188 return this->readPixels(dstInfo, dstPixels, dstRowBytes, 0, 0); 189 } readPixels(const SkPixmap & dst,int srcX,int srcY)190 bool readPixels(const SkPixmap& dst, int srcX, int srcY) const { 191 return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY); 192 } readPixels(const SkPixmap & dst)193 bool readPixels(const SkPixmap& dst) const { 194 return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), 0, 0); 195 } 196 197 /** 198 * Copy the pixels from this pixmap into the dst pixmap, converting as needed into dst's 199 * colortype/alphatype. If the conversion cannot be performed, false is returned. 200 * 201 * If dst's dimensions differ from the src dimension, the image will be scaled, applying the 202 * specified filter-quality. 203 */ 204 bool scalePixels(const SkPixmap& dst, SkFilterQuality) const; 205 206 /** 207 * Returns true if pixels were written to (e.g. if colorType is kUnknown_SkColorType, this 208 * will return false). If subset does not intersect the bounds of this pixmap, returns false. 209 */ 210 bool erase(SkColor, const SkIRect& subset) const; 211 erase(SkColor color)212 bool erase(SkColor color) const { return this->erase(color, this->bounds()); } 213 bool erase(const SkColor4f&, const SkIRect* subset = nullptr) const; 214 215 private: 216 const void* fPixels; 217 SkColorTable* fCTable; 218 size_t fRowBytes; 219 SkImageInfo fInfo; 220 }; 221 222 ///////////////////////////////////////////////////////////////////////////////////////////// 223 224 ///////////////////////////////////////////////////////////////////////////////////////////// 225 226 class SK_API SkAutoPixmapUnlock : ::SkNoncopyable { 227 public: SkAutoPixmapUnlock()228 SkAutoPixmapUnlock() : fUnlockProc(NULL), fIsLocked(false) {} SkAutoPixmapUnlock(const SkPixmap & pm,void (* unlock)(void *),void * ctx)229 SkAutoPixmapUnlock(const SkPixmap& pm, void (*unlock)(void*), void* ctx) 230 : fUnlockProc(unlock), fUnlockContext(ctx), fPixmap(pm), fIsLocked(true) 231 {} ~SkAutoPixmapUnlock()232 ~SkAutoPixmapUnlock() { this->unlock(); } 233 234 /** 235 * Return the currently locked pixmap. Undefined if it has been unlocked. 236 */ pixmap()237 const SkPixmap& pixmap() const { 238 SkASSERT(this->isLocked()); 239 return fPixmap; 240 } 241 isLocked()242 bool isLocked() const { return fIsLocked; } 243 244 /** 245 * Unlocks the pixmap. Can safely be called more than once as it will only call the underlying 246 * unlock-proc once. 247 */ unlock()248 void unlock() { 249 if (fUnlockProc) { 250 SkASSERT(fIsLocked); 251 fUnlockProc(fUnlockContext); 252 fUnlockProc = NULL; 253 fIsLocked = false; 254 } 255 } 256 257 /** 258 * If there is a currently locked pixmap, unlock it, then copy the specified pixmap 259 * and (optional) unlock proc/context. 260 */ 261 void reset(const SkPixmap& pm, void (*unlock)(void*), void* ctx); 262 263 private: 264 void (*fUnlockProc)(void*); 265 void* fUnlockContext; 266 SkPixmap fPixmap; 267 bool fIsLocked; 268 269 friend class SkBitmap; 270 }; 271 272 #endif 273