2015-05-22 15:06:21 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2015 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef SkPixmap_DEFINED
|
|
|
|
#define SkPixmap_DEFINED
|
|
|
|
|
2015-06-08 17:22:22 +00:00
|
|
|
#include "SkColor.h"
|
2015-11-23 20:32:16 +00:00
|
|
|
#include "SkFilterQuality.h"
|
2015-05-22 15:06:21 +00:00
|
|
|
#include "SkImageInfo.h"
|
|
|
|
|
|
|
|
class SkColorTable;
|
2016-02-04 21:09:59 +00:00
|
|
|
class SkData;
|
2015-06-05 21:33:17 +00:00
|
|
|
struct SkMask;
|
2015-05-22 15:06:21 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Pairs SkImageInfo with actual pixels and rowbytes. This class does not try to manage the
|
|
|
|
* lifetime of the pixel memory (nor the colortable if provided).
|
|
|
|
*/
|
2015-07-27 17:27:28 +00:00
|
|
|
class SK_API SkPixmap {
|
2015-05-22 15:06:21 +00:00
|
|
|
public:
|
|
|
|
SkPixmap()
|
|
|
|
: fPixels(NULL), fCTable(NULL), fRowBytes(0), fInfo(SkImageInfo::MakeUnknown(0, 0))
|
|
|
|
{}
|
|
|
|
|
|
|
|
SkPixmap(const SkImageInfo& info, const void* addr, size_t rowBytes,
|
|
|
|
SkColorTable* ctable = NULL)
|
|
|
|
: fPixels(addr), fCTable(ctable), fRowBytes(rowBytes), fInfo(info)
|
|
|
|
{
|
|
|
|
if (kIndex_8_SkColorType == info.colorType()) {
|
|
|
|
SkASSERT(ctable);
|
|
|
|
} else {
|
|
|
|
SkASSERT(NULL == ctable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-26 18:31:54 +00:00
|
|
|
void reset();
|
|
|
|
void reset(const SkImageInfo& info, const void* addr, size_t rowBytes,
|
|
|
|
SkColorTable* ctable = NULL);
|
2015-06-05 21:33:17 +00:00
|
|
|
void reset(const SkImageInfo& info) {
|
|
|
|
this->reset(info, NULL, 0, NULL);
|
|
|
|
}
|
|
|
|
|
2016-06-09 18:03:45 +00:00
|
|
|
// overrides the colorspace in the SkImageInfo of the pixmap
|
|
|
|
void setColorSpace(sk_sp<SkColorSpace>);
|
|
|
|
|
2015-06-05 21:33:17 +00:00
|
|
|
/**
|
|
|
|
* If supported, set this pixmap to point to the pixels in the specified mask and return true.
|
|
|
|
* On failure, return false and set this pixmap to empty.
|
|
|
|
*/
|
|
|
|
bool SK_WARN_UNUSED_RESULT reset(const SkMask&);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Computes the intersection of area and this pixmap. If that intersection is non-empty,
|
|
|
|
* set subset to that intersection and return true.
|
|
|
|
*
|
|
|
|
* On failure, return false and ignore the subset parameter.
|
|
|
|
*/
|
|
|
|
bool SK_WARN_UNUSED_RESULT extractSubset(SkPixmap* subset, const SkIRect& area) const;
|
2015-05-26 18:31:54 +00:00
|
|
|
|
2015-05-22 15:06:21 +00:00
|
|
|
const SkImageInfo& info() const { return fInfo; }
|
|
|
|
size_t rowBytes() const { return fRowBytes; }
|
|
|
|
const void* addr() const { return fPixels; }
|
|
|
|
SkColorTable* ctable() const { return fCTable; }
|
|
|
|
|
|
|
|
int width() const { return fInfo.width(); }
|
|
|
|
int height() const { return fInfo.height(); }
|
|
|
|
SkColorType colorType() const { return fInfo.colorType(); }
|
|
|
|
SkAlphaType alphaType() const { return fInfo.alphaType(); }
|
2016-11-11 17:51:36 +00:00
|
|
|
SkColorSpace* colorSpace() const { return fInfo.colorSpace(); }
|
2015-05-22 15:06:21 +00:00
|
|
|
bool isOpaque() const { return fInfo.isOpaque(); }
|
|
|
|
|
2015-06-04 21:12:25 +00:00
|
|
|
SkIRect bounds() const { return SkIRect::MakeWH(this->width(), this->height()); }
|
|
|
|
|
2016-03-24 18:21:25 +00:00
|
|
|
/**
|
|
|
|
* Return the rowbytes expressed as a number of pixels (like width and height).
|
|
|
|
*/
|
|
|
|
int rowBytesAsPixels() const { return int(fRowBytes >> this->shiftPerPixel()); }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the shift amount per pixel (i.e. 0 for 1-byte per pixel, 1 for 2-bytes per pixel
|
|
|
|
* colortypes, 2 for 4-bytes per pixel colortypes). Return 0 for kUnknown_SkColorType.
|
|
|
|
*/
|
2016-04-15 13:59:38 +00:00
|
|
|
int shiftPerPixel() const { return fInfo.shiftPerPixel(); }
|
2016-03-24 18:21:25 +00:00
|
|
|
|
2015-05-23 20:21:06 +00:00
|
|
|
uint64_t getSize64() const { return sk_64_mul(fInfo.height(), fRowBytes); }
|
|
|
|
uint64_t getSafeSize64() const { return fInfo.getSafeSize64(fRowBytes); }
|
2015-05-22 15:06:21 +00:00
|
|
|
size_t getSafeSize() const { return fInfo.getSafeSize(fRowBytes); }
|
|
|
|
|
2016-12-07 20:24:59 +00:00
|
|
|
/**
|
|
|
|
* This will brute-force return true if all of the pixels in the pixmap
|
|
|
|
* are opaque. If there are no pixels, or encounters an error, returns false.
|
|
|
|
*/
|
|
|
|
bool computeIsOpaque() const;
|
|
|
|
|
2016-10-31 13:38:12 +00:00
|
|
|
/**
|
|
|
|
* Converts the pixel at the specified coordinate to an unpremultiplied
|
|
|
|
* SkColor. Note: this ignores any SkColorSpace information, and may return
|
|
|
|
* lower precision data than is actually in the pixel. Alpha only
|
|
|
|
* colortypes (e.g. kAlpha_8_SkColorType) return black with the appropriate
|
|
|
|
* alpha set. The value is undefined for kUnknown_SkColorType or if x or y
|
|
|
|
* are out of bounds, or if the pixtap does not have any pixels.
|
|
|
|
*/
|
|
|
|
SkColor getColor(int x, int y) const;
|
|
|
|
|
2016-02-05 19:18:39 +00:00
|
|
|
const void* addr(int x, int y) const {
|
|
|
|
return (const char*)fPixels + fInfo.computeOffset(x, y, fRowBytes);
|
|
|
|
}
|
|
|
|
const uint8_t* addr8() const {
|
|
|
|
SkASSERT(1 == SkColorTypeBytesPerPixel(fInfo.colorType()));
|
|
|
|
return reinterpret_cast<const uint8_t*>(fPixels);
|
|
|
|
}
|
|
|
|
const uint16_t* addr16() const {
|
|
|
|
SkASSERT(2 == SkColorTypeBytesPerPixel(fInfo.colorType()));
|
|
|
|
return reinterpret_cast<const uint16_t*>(fPixels);
|
|
|
|
}
|
2015-05-22 15:06:21 +00:00
|
|
|
const uint32_t* addr32() const {
|
|
|
|
SkASSERT(4 == SkColorTypeBytesPerPixel(fInfo.colorType()));
|
|
|
|
return reinterpret_cast<const uint32_t*>(fPixels);
|
|
|
|
}
|
2016-02-05 19:18:39 +00:00
|
|
|
const uint64_t* addr64() const {
|
|
|
|
SkASSERT(8 == SkColorTypeBytesPerPixel(fInfo.colorType()));
|
|
|
|
return reinterpret_cast<const uint64_t*>(fPixels);
|
|
|
|
}
|
|
|
|
const uint16_t* addrF16() const {
|
|
|
|
SkASSERT(8 == SkColorTypeBytesPerPixel(fInfo.colorType()));
|
|
|
|
SkASSERT(kRGBA_F16_SkColorType == fInfo.colorType());
|
2015-05-22 15:06:21 +00:00
|
|
|
return reinterpret_cast<const uint16_t*>(fPixels);
|
|
|
|
}
|
|
|
|
|
2016-02-05 19:18:39 +00:00
|
|
|
// Offset by the specified x,y coordinates
|
2015-05-22 15:06:21 +00:00
|
|
|
|
2016-02-05 19:18:39 +00:00
|
|
|
const uint8_t* addr8(int x, int y) const {
|
2015-05-22 15:06:21 +00:00
|
|
|
SkASSERT((unsigned)x < (unsigned)fInfo.width());
|
|
|
|
SkASSERT((unsigned)y < (unsigned)fInfo.height());
|
2016-02-05 19:18:39 +00:00
|
|
|
return (const uint8_t*)((const char*)this->addr8() + y * fRowBytes + (x << 0));
|
2015-05-22 15:06:21 +00:00
|
|
|
}
|
|
|
|
const uint16_t* addr16(int x, int y) const {
|
|
|
|
SkASSERT((unsigned)x < (unsigned)fInfo.width());
|
|
|
|
SkASSERT((unsigned)y < (unsigned)fInfo.height());
|
|
|
|
return (const uint16_t*)((const char*)this->addr16() + y * fRowBytes + (x << 1));
|
|
|
|
}
|
2016-02-05 19:18:39 +00:00
|
|
|
const uint32_t* addr32(int x, int y) const {
|
2015-05-22 15:06:21 +00:00
|
|
|
SkASSERT((unsigned)x < (unsigned)fInfo.width());
|
|
|
|
SkASSERT((unsigned)y < (unsigned)fInfo.height());
|
2016-02-05 19:18:39 +00:00
|
|
|
return (const uint32_t*)((const char*)this->addr32() + y * fRowBytes + (x << 2));
|
2015-05-22 15:06:21 +00:00
|
|
|
}
|
2016-02-05 19:18:39 +00:00
|
|
|
const uint64_t* addr64(int x, int y) const {
|
|
|
|
SkASSERT((unsigned)x < (unsigned)fInfo.width());
|
|
|
|
SkASSERT((unsigned)y < (unsigned)fInfo.height());
|
|
|
|
return (const uint64_t*)((const char*)this->addr64() + y * fRowBytes + (x << 3));
|
|
|
|
}
|
|
|
|
const uint16_t* addrF16(int x, int y) const {
|
|
|
|
SkASSERT(kRGBA_F16_SkColorType == fInfo.colorType());
|
|
|
|
return reinterpret_cast<const uint16_t*>(this->addr64(x, y));
|
2015-05-22 15:06:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Writable versions
|
|
|
|
|
|
|
|
void* writable_addr() const { return const_cast<void*>(fPixels); }
|
2016-04-15 13:59:38 +00:00
|
|
|
void* writable_addr(int x, int y) const {
|
|
|
|
return const_cast<void*>(this->addr(x, y));
|
|
|
|
}
|
2016-02-05 19:18:39 +00:00
|
|
|
uint8_t* writable_addr8(int x, int y) const {
|
|
|
|
return const_cast<uint8_t*>(this->addr8(x, y));
|
2015-05-22 15:06:21 +00:00
|
|
|
}
|
|
|
|
uint16_t* writable_addr16(int x, int y) const {
|
|
|
|
return const_cast<uint16_t*>(this->addr16(x, y));
|
|
|
|
}
|
2016-02-05 19:18:39 +00:00
|
|
|
uint32_t* writable_addr32(int x, int y) const {
|
|
|
|
return const_cast<uint32_t*>(this->addr32(x, y));
|
|
|
|
}
|
|
|
|
uint64_t* writable_addr64(int x, int y) const {
|
|
|
|
return const_cast<uint64_t*>(this->addr64(x, y));
|
|
|
|
}
|
|
|
|
uint16_t* writable_addrF16(int x, int y) const {
|
|
|
|
return reinterpret_cast<uint16_t*>(writable_addr64(x, y));
|
2015-05-22 15:06:21 +00:00
|
|
|
}
|
|
|
|
|
2015-05-23 20:21:06 +00:00
|
|
|
// copy methods
|
|
|
|
|
|
|
|
bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
|
|
|
|
int srcX, int srcY) const;
|
|
|
|
bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes) const {
|
|
|
|
return this->readPixels(dstInfo, dstPixels, dstRowBytes, 0, 0);
|
|
|
|
}
|
|
|
|
bool readPixels(const SkPixmap& dst, int srcX, int srcY) const {
|
|
|
|
return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
|
|
|
|
}
|
|
|
|
bool readPixels(const SkPixmap& dst) const {
|
|
|
|
return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), 0, 0);
|
|
|
|
}
|
|
|
|
|
2015-11-23 20:32:16 +00:00
|
|
|
/**
|
|
|
|
* Copy the pixels from this pixmap into the dst pixmap, converting as needed into dst's
|
|
|
|
* colortype/alphatype. If the conversion cannot be performed, false is returned.
|
|
|
|
*
|
|
|
|
* If dst's dimensions differ from the src dimension, the image will be scaled, applying the
|
|
|
|
* specified filter-quality.
|
|
|
|
*/
|
|
|
|
bool scalePixels(const SkPixmap& dst, SkFilterQuality) const;
|
|
|
|
|
2015-06-08 17:22:22 +00:00
|
|
|
/**
|
|
|
|
* Returns true if pixels were written to (e.g. if colorType is kUnknown_SkColorType, this
|
|
|
|
* will return false). If subset does not intersect the bounds of this pixmap, returns false.
|
|
|
|
*/
|
|
|
|
bool erase(SkColor, const SkIRect& subset) const;
|
|
|
|
|
|
|
|
bool erase(SkColor color) const { return this->erase(color, this->bounds()); }
|
2016-02-05 19:18:39 +00:00
|
|
|
bool erase(const SkColor4f&, const SkIRect* subset = nullptr) const;
|
2015-06-08 17:22:22 +00:00
|
|
|
|
2015-05-22 15:06:21 +00:00
|
|
|
private:
|
|
|
|
const void* fPixels;
|
|
|
|
SkColorTable* fCTable;
|
|
|
|
size_t fRowBytes;
|
|
|
|
SkImageInfo fInfo;
|
|
|
|
};
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2015-06-05 21:33:17 +00:00
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2015-07-27 17:27:28 +00:00
|
|
|
class SK_API SkAutoPixmapUnlock : ::SkNoncopyable {
|
2015-05-22 15:06:21 +00:00
|
|
|
public:
|
|
|
|
SkAutoPixmapUnlock() : fUnlockProc(NULL), fIsLocked(false) {}
|
|
|
|
SkAutoPixmapUnlock(const SkPixmap& pm, void (*unlock)(void*), void* ctx)
|
|
|
|
: fUnlockProc(unlock), fUnlockContext(ctx), fPixmap(pm), fIsLocked(true)
|
|
|
|
{}
|
|
|
|
~SkAutoPixmapUnlock() { this->unlock(); }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the currently locked pixmap. Undefined if it has been unlocked.
|
|
|
|
*/
|
|
|
|
const SkPixmap& pixmap() const {
|
|
|
|
SkASSERT(this->isLocked());
|
|
|
|
return fPixmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isLocked() const { return fIsLocked; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unlocks the pixmap. Can safely be called more than once as it will only call the underlying
|
|
|
|
* unlock-proc once.
|
|
|
|
*/
|
|
|
|
void unlock() {
|
|
|
|
if (fUnlockProc) {
|
|
|
|
SkASSERT(fIsLocked);
|
|
|
|
fUnlockProc(fUnlockContext);
|
|
|
|
fUnlockProc = NULL;
|
|
|
|
fIsLocked = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If there is a currently locked pixmap, unlock it, then copy the specified pixmap
|
|
|
|
* and (optional) unlock proc/context.
|
|
|
|
*/
|
|
|
|
void reset(const SkPixmap& pm, void (*unlock)(void*), void* ctx);
|
|
|
|
|
|
|
|
private:
|
|
|
|
void (*fUnlockProc)(void*);
|
|
|
|
void* fUnlockContext;
|
|
|
|
SkPixmap fPixmap;
|
|
|
|
bool fIsLocked;
|
|
|
|
|
|
|
|
friend class SkBitmap;
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|