blob: f427755d470dc4be61f436895e780c5b2fc542e9 [file] [log] [blame]
reed@google.com6997ebb2012-07-30 19:50:31 +00001/*
2 * Copyright 2012 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
reed@google.comf6627b72012-07-27 18:02:50 +00008#include "SkBitmap.h"
mike@reedtribe.org70e35902012-07-29 20:38:16 +00009#include "SkCanvas.h"
reed5965c8a2015-01-07 18:04:45 -080010#include "SkImageGenerator.h"
scroggo@google.com7def5e12013-05-31 14:00:10 +000011#include "SkImagePriv.h"
12#include "SkImage_Base.h"
reed96472de2014-12-10 09:53:42 -080013#include "SkReadPixelsRec.h"
reedf8d18742015-01-02 20:45:37 -080014#include "SkString.h"
reed4af267b2014-11-21 08:46:37 -080015#include "SkSurface.h"
scroggo@google.com7def5e12013-05-31 14:00:10 +000016
reed@google.comf6627b72012-07-27 18:02:50 +000017uint32_t SkImage::NextUniqueID() {
18 static int32_t gUniqueID;
19
20 // never return 0;
21 uint32_t id;
22 do {
23 id = sk_atomic_inc(&gUniqueID) + 1;
24 } while (0 == id);
25 return id;
26}
27
reed973d1f12015-05-04 09:00:45 -070028void SkImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const {
29 as_IB(this)->onDraw(canvas, x, y, paint);
30}
31
32void SkImage::drawRect(SkCanvas* canvas, const SkRect* src, const SkRect& dst,
33 const SkPaint* paint) const {
34 as_IB(this)->onDrawRect(canvas, src, dst, paint);
35}
36
reed@google.com4f7c6152014-02-06 14:11:56 +000037const void* SkImage::peekPixels(SkImageInfo* info, size_t* rowBytes) const {
38 SkImageInfo infoStorage;
39 size_t rowBytesStorage;
40 if (NULL == info) {
41 info = &infoStorage;
42 }
43 if (NULL == rowBytes) {
44 rowBytes = &rowBytesStorage;
45 }
46 return as_IB(this)->onPeekPixels(info, rowBytes);
47}
48
reed96472de2014-12-10 09:53:42 -080049bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
50 int srcX, int srcY) const {
51 SkReadPixelsRec rec(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
52 if (!rec.trim(this->width(), this->height())) {
reed@google.com4f7c6152014-02-06 14:11:56 +000053 return false;
54 }
reed96472de2014-12-10 09:53:42 -080055 return as_IB(this)->onReadPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com4f7c6152014-02-06 14:11:56 +000056}
57
kkinnunencd6ca9e2015-02-18 10:50:52 -080058GrTexture* SkImage::getTexture() const {
scroggo@google.com7def5e12013-05-31 14:00:10 +000059 return as_IB(this)->onGetTexture();
60}
61
piotaixr76d5b472014-07-22 15:02:05 -070062SkShader* SkImage::newShader(SkShader::TileMode tileX,
63 SkShader::TileMode tileY,
64 const SkMatrix* localMatrix) const {
65 return as_IB(this)->onNewShader(tileX, tileY, localMatrix);
piotaixrcef04f82014-07-14 07:48:04 -070066}
67
scroggo@google.com7def5e12013-05-31 14:00:10 +000068SkData* SkImage::encode(SkImageEncoder::Type type, int quality) const {
69 SkBitmap bm;
70 if (as_IB(this)->getROPixels(&bm)) {
71 return SkImageEncoder::EncodeData(bm, type, quality);
72 }
73 return NULL;
junov@chromium.orgda904742013-05-01 22:38:16 +000074}
reed@google.com4f7c6152014-02-06 14:11:56 +000075
reed5965c8a2015-01-07 18:04:45 -080076SkImage* SkImage::NewFromData(SkData* data) {
77 if (NULL == data) {
78 return NULL;
79 }
80 SkImageGenerator* generator = SkImageGenerator::NewFromData(data);
81 return generator ? SkImage::NewFromGenerator(generator) : NULL;
82}
83
reed4af267b2014-11-21 08:46:37 -080084SkSurface* SkImage::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) const {
85 if (NULL == props) {
86 props = &as_IB(this)->props();
87 }
88 return as_IB(this)->onNewSurface(info, *props);
89}
90
reedf8d18742015-01-02 20:45:37 -080091const char* SkImage::toString(SkString* str) const {
92 str->appendf("image: (id:%d (%d, %d) %s)", this->uniqueID(), this->width(), this->height(),
93 this->isOpaque() ? "opaque" : "");
94 return str->c_str();
95}
96
reedf803da12015-01-23 05:58:07 -080097SkImage* SkImage::newImage(int newWidth, int newHeight, const SkIRect* subset,
98 SkFilterQuality quality) const {
99 if (newWidth <= 0 || newHeight <= 0) {
100 return NULL;
101 }
102
103 const SkIRect bounds = SkIRect::MakeWH(this->width(), this->height());
104
105 if (subset) {
106 if (!bounds.contains(*subset)) {
107 return NULL;
108 }
109 if (bounds == *subset) {
110 subset = NULL; // and fall through to check below
111 }
112 }
113
114 if (NULL == subset && this->width() == newWidth && this->height() == newHeight) {
115 return SkRef(const_cast<SkImage*>(this));
116 }
117
118 return as_IB(this)->onNewImage(newWidth, newHeight, subset, quality);
119}
120
reed@google.com4f7c6152014-02-06 14:11:56 +0000121///////////////////////////////////////////////////////////////////////////////
122
123static bool raster_canvas_supports(const SkImageInfo& info) {
reede5ea5002014-09-03 11:54:58 -0700124 switch (info.colorType()) {
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +0000125 case kN32_SkColorType:
reede5ea5002014-09-03 11:54:58 -0700126 return kUnpremul_SkAlphaType != info.alphaType();
reed@google.com4f7c6152014-02-06 14:11:56 +0000127 case kRGB_565_SkColorType:
128 return true;
129 case kAlpha_8_SkColorType:
130 return true;
131 default:
132 break;
133 }
134 return false;
135}
136
reed96472de2014-12-10 09:53:42 -0800137bool SkImage_Base::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
138 int srcX, int srcY) const {
139 if (!raster_canvas_supports(dstInfo)) {
140 return false;
reed@google.com4f7c6152014-02-06 14:11:56 +0000141 }
142
reed96472de2014-12-10 09:53:42 -0800143 SkBitmap bm;
144 bm.installPixels(dstInfo, dstPixels, dstRowBytes);
145 SkCanvas canvas(bm);
reed@google.com4f7c6152014-02-06 14:11:56 +0000146
147 SkPaint paint;
reed96472de2014-12-10 09:53:42 -0800148 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
149 canvas.drawImage(this, -SkIntToScalar(srcX), -SkIntToScalar(srcY), &paint);
reed@google.com4f7c6152014-02-06 14:11:56 +0000150
reed@google.com4f7c6152014-02-06 14:11:56 +0000151 return true;
152}
reedf803da12015-01-23 05:58:07 -0800153
154SkImage* SkImage_Base::onNewImage(int newWidth, int newHeight, const SkIRect* subset,
155 SkFilterQuality quality) const {
156 const bool opaque = this->isOpaque();
157 const SkImageInfo info = SkImageInfo::Make(newWidth, newHeight, kN32_SkColorType,
158 opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
159 SkAutoTUnref<SkSurface> surface(this->newSurface(info, NULL));
160 if (!surface.get()) {
161 return NULL;
162 }
163
164 SkRect src;
165 if (subset) {
166 src.set(*subset);
167 } else {
168 src = SkRect::MakeIWH(this->width(), this->height());
169 }
170
171 surface->getCanvas()->scale(newWidth / src.width(), newHeight / src.height());
172 surface->getCanvas()->translate(-src.x(), -src.y());
173
174 SkPaint paint;
175 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
176 paint.setFilterQuality(quality);
177 surface->getCanvas()->drawImage(this, 0, 0, &paint);
178 return surface->newImageSnapshot();
179}
180
181