Fix color xform width bug when scaling/subsetting

This was not caught by the bots because we don't test
color correct modes with our many image decoding tests
(takes too long).

Adding a unit test.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2247743002

Review-Url: https://codereview.chromium.org/2247743002
This commit is contained in:
msarett 2016-08-22 07:41:28 -07:00 committed by Commit bot
parent a629166d6e
commit 35bb74b444
5 changed files with 54 additions and 13 deletions

View File

@ -495,11 +495,13 @@ int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes
uint32_t* swizzleDst = (uint32_t*) dst;
size_t decodeDstRowBytes = rowBytes;
size_t swizzleDstRowBytes = rowBytes;
int dstWidth = dstInfo.width();
if (fSwizzleSrcRow && fColorXformSrcRow) {
decodeDst = (JSAMPLE*) fSwizzleSrcRow;
swizzleDst = fColorXformSrcRow;
decodeDstRowBytes = 0;
swizzleDstRowBytes = 0;
dstWidth = fSwizzler->swizzleWidth();
} else if (fColorXformSrcRow) {
decodeDst = (JSAMPLE*) fColorXformSrcRow;
swizzleDst = fColorXformSrcRow;
@ -508,6 +510,7 @@ int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes
} else if (fSwizzleSrcRow) {
decodeDst = (JSAMPLE*) fSwizzleSrcRow;
decodeDstRowBytes = 0;
dstWidth = fSwizzler->swizzleWidth();
}
for (int y = 0; y < count; y++) {
@ -523,8 +526,7 @@ int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes
}
if (fColorXform) {
fColorXform->apply(dst, swizzleDst, dstInfo.width(), dstInfo.colorType(),
kOpaque_SkAlphaType);
fColorXform->apply(dst, swizzleDst, dstWidth, dstInfo.colorType(), kOpaque_SkAlphaType);
dst = SkTAddOffset<void>(dst, rowBytes);
}
@ -590,16 +592,19 @@ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
}
void SkJpegCodec::allocateStorage(const SkImageInfo& dstInfo) {
int dstWidth = dstInfo.width();
size_t swizzleBytes = 0;
if (fSwizzler) {
swizzleBytes = get_row_bytes(fDecoderMgr->dinfo());
dstWidth = fSwizzler->swizzleWidth();
SkASSERT(!fColorXform || SkIsAlign4(swizzleBytes));
}
size_t xformBytes = 0;
if (kRGBA_F16_SkColorType == dstInfo.colorType()) {
SkASSERT(fColorXform);
xformBytes = dstInfo.width() * sizeof(uint32_t);
xformBytes = dstWidth * sizeof(uint32_t);
}
size_t totalBytes = swizzleBytes + xformBytes;

View File

@ -358,9 +358,8 @@ static bool png_conversion_possible(const SkImageInfo& dst, const SkImageInfo& s
}
}
void SkPngCodec::allocateStorage(const SkImageInfo& dstInfo) {
const int width = this->getInfo().width();
size_t colorXformBytes = fColorXform ? width * sizeof(uint32_t) : 0;
void SkPngCodec::allocateStorage() {
size_t colorXformBytes = fColorXform ? fSwizzler->swizzleWidth() * sizeof(uint32_t) : 0;
fStorage.reset(SkAlign4(fSrcRowBytes) + colorXformBytes);
fSwizzlerSrcRow = fStorage.get();
@ -384,7 +383,7 @@ public:
return kInvalidConversion;
}
this->allocateStorage(dstInfo);
this->allocateStorage();
return kSuccess;
}
@ -413,7 +412,7 @@ public:
fSwizzler->swizzle(swizzlerDstRow, fSwizzlerSrcRow);
if (fColorXform) {
fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow, dstInfo.width(),
fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow, fSwizzler->swizzleWidth(),
dstInfo.colorType(), xformAlphaType);
dst = SkTAddOffset<void>(dst, rowBytes);
}
@ -464,7 +463,7 @@ public:
return kInvalidConversion;
}
this->allocateStorage(dstInfo);
this->allocateStorage();
fCanSkipRewind = true;
return SkCodec::kSuccess;
}
@ -515,8 +514,9 @@ public:
if (fColorXform) {
if (fColorXform) {
fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow, dstInfo.width(),
dstInfo.colorType(), xformAlphaType);
fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow,
fSwizzler->swizzleWidth(), dstInfo.colorType(),
xformAlphaType);
dst = SkTAddOffset<void>(dst, rowBytes);
}
}
@ -865,7 +865,7 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
return kUnimplemented;
}
this->allocateStorage(dstInfo);
this->allocateStorage();
int count = this->readRows(dstInfo, dst, rowBytes, dstInfo.height(), 0);
if (count > dstInfo.height()) {
*rowsDecoded = count;

View File

@ -41,7 +41,7 @@ protected:
SkASSERT(fSwizzler);
return fSwizzler;
}
void allocateStorage(const SkImageInfo& dstInfo);
void allocateStorage();
virtual int readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count,
int startRow) = 0;

View File

@ -72,6 +72,12 @@ public:
*/
int sampleX() const { return fSampleX; }
/**
* Returns the actual number of pixels written to destination memory, taking
* scaling, subsetting, and partial frames into account.
*/
int swizzleWidth() const { return fSwizzleWidth; }
private:
/**

View File

@ -1044,6 +1044,36 @@ DEF_TEST(Codec_jpeg_rewind, r) {
REPORTER_ASSERT(r, SkCodec::kSuccess == result);
}
static void check_color_xform(skiatest::Reporter* r, const char* path) {
SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(resource(path)));
SkAndroidCodec::AndroidOptions opts;
opts.fSampleSize = 3;
const int subsetWidth = codec->getInfo().width() / 2;
const int subsetHeight = codec->getInfo().height() / 2;
SkIRect subset = SkIRect::MakeWH(subsetWidth, subsetHeight);
opts.fSubset = &subset;
const int dstWidth = subsetWidth / opts.fSampleSize;
const int dstHeight = subsetHeight / opts.fSampleSize;
sk_sp<SkData> data = SkData::MakeFromFileName(
GetResourcePath("icc_profiles/HP_ZR30w.icc").c_str());
sk_sp<SkColorSpace> colorSpace = SkColorSpace::NewICC(data->data(), data->size());
SkImageInfo dstInfo = codec->getInfo().makeWH(dstWidth, dstHeight)
.makeColorType(kN32_SkColorType)
.makeColorSpace(colorSpace);
size_t rowBytes = dstInfo.minRowBytes();
SkAutoMalloc pixelStorage(dstInfo.getSafeSize(rowBytes));
SkCodec::Result result = codec->getAndroidPixels(dstInfo, pixelStorage.get(), rowBytes, &opts);
REPORTER_ASSERT(r, SkCodec::kSuccess == result);
}
DEF_TEST(Codec_ColorXform, r) {
check_color_xform(r, "mandrill_512_q075.jpg");
check_color_xform(r, "mandrill_512.png");
}
DEF_TEST(Codec_Png565, r) {
// Create an arbitrary 565 bitmap.
const char* path = "mandrill_512_q075.jpg";