2016-04-20 18:53:35 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2016 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef SkEncodedInfo_DEFINED
|
|
|
|
#define SkEncodedInfo_DEFINED
|
|
|
|
|
2018-08-27 15:55:46 +00:00
|
|
|
#include "SkData.h"
|
2016-04-20 18:53:35 +00:00
|
|
|
#include "SkImageInfo.h"
|
2018-08-27 15:55:46 +00:00
|
|
|
#include "../../third_party/skcms/skcms.h"
|
2016-04-20 18:53:35 +00:00
|
|
|
|
|
|
|
struct SkEncodedInfo {
|
|
|
|
public:
|
2018-08-27 15:55:46 +00:00
|
|
|
class ICCProfile {
|
|
|
|
public:
|
|
|
|
static std::unique_ptr<ICCProfile> Make(sk_sp<SkData>);
|
|
|
|
static std::unique_ptr<ICCProfile> Make(const skcms_ICCProfile&);
|
|
|
|
|
|
|
|
const skcms_ICCProfile* profile() const { return &fProfile; }
|
|
|
|
private:
|
|
|
|
ICCProfile(const skcms_ICCProfile&, sk_sp<SkData> = nullptr);
|
|
|
|
|
|
|
|
skcms_ICCProfile fProfile;
|
|
|
|
sk_sp<SkData> fData;
|
|
|
|
};
|
2016-04-20 18:53:35 +00:00
|
|
|
|
|
|
|
enum Alpha {
|
|
|
|
kOpaque_Alpha,
|
|
|
|
kUnpremul_Alpha,
|
|
|
|
|
|
|
|
// Each pixel is either fully opaque or fully transparent.
|
|
|
|
// There is no difference between requesting kPremul or kUnpremul.
|
|
|
|
kBinary_Alpha,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We strive to make the number of components per pixel obvious through
|
|
|
|
* our naming conventions.
|
|
|
|
* Ex: kRGB has 3 components. kRGBA has 4 components.
|
|
|
|
*
|
|
|
|
* This sometimes results in redundant Alpha and Color information.
|
|
|
|
* Ex: kRGB images must also be kOpaque.
|
|
|
|
*/
|
|
|
|
enum Color {
|
|
|
|
// PNG, WBMP
|
|
|
|
kGray_Color,
|
|
|
|
|
|
|
|
// PNG
|
|
|
|
kGrayAlpha_Color,
|
|
|
|
|
2018-08-27 15:55:46 +00:00
|
|
|
// PNG with Skia-specific sBIT
|
|
|
|
// Like kGrayAlpha, except this expects to be treated as
|
|
|
|
// kAlpha_8_SkColorType, which ignores the gray component. If
|
|
|
|
// decoded to full color (e.g. kN32), the gray component is respected
|
|
|
|
// (so it can share code with kGrayAlpha).
|
|
|
|
kXAlpha_Color,
|
|
|
|
|
|
|
|
// PNG
|
|
|
|
// 565 images may be encoded to PNG by specifying the number of
|
|
|
|
// significant bits for each channel. This is a strange 565
|
|
|
|
// representation because the image is still encoded with 8 bits per
|
|
|
|
// component.
|
|
|
|
k565_Color,
|
|
|
|
|
2016-04-20 18:53:35 +00:00
|
|
|
// PNG, GIF, BMP
|
|
|
|
kPalette_Color,
|
|
|
|
|
|
|
|
// PNG, RAW
|
|
|
|
kRGB_Color,
|
|
|
|
kRGBA_Color,
|
|
|
|
|
|
|
|
// BMP
|
|
|
|
kBGR_Color,
|
|
|
|
kBGRX_Color,
|
|
|
|
kBGRA_Color,
|
|
|
|
|
|
|
|
// JPEG, WEBP
|
|
|
|
kYUV_Color,
|
|
|
|
|
|
|
|
// WEBP
|
|
|
|
kYUVA_Color,
|
|
|
|
|
|
|
|
// JPEG
|
|
|
|
// Photoshop actually writes inverted CMYK data into JPEGs, where zero
|
|
|
|
// represents 100% ink coverage. For this reason, we treat CMYK JPEGs
|
|
|
|
// as having inverted CMYK. libjpeg-turbo warns that this may break
|
|
|
|
// other applications, but the CMYK JPEGs we see on the web expect to
|
|
|
|
// be treated as inverted CMYK.
|
|
|
|
kInvertedCMYK_Color,
|
|
|
|
kYCCK_Color,
|
|
|
|
};
|
|
|
|
|
2018-08-27 15:55:46 +00:00
|
|
|
static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha,
|
|
|
|
int bitsPerComponent) {
|
|
|
|
return Make(width, height, color, alpha, bitsPerComponent, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha,
|
|
|
|
int bitsPerComponent, std::unique_ptr<ICCProfile> profile) {
|
2016-04-20 18:53:35 +00:00
|
|
|
SkASSERT(1 == bitsPerComponent ||
|
|
|
|
2 == bitsPerComponent ||
|
|
|
|
4 == bitsPerComponent ||
|
|
|
|
8 == bitsPerComponent ||
|
|
|
|
16 == bitsPerComponent);
|
|
|
|
|
|
|
|
switch (color) {
|
|
|
|
case kGray_Color:
|
|
|
|
SkASSERT(kOpaque_Alpha == alpha);
|
|
|
|
break;
|
|
|
|
case kGrayAlpha_Color:
|
|
|
|
SkASSERT(kOpaque_Alpha != alpha);
|
|
|
|
break;
|
|
|
|
case kPalette_Color:
|
|
|
|
SkASSERT(16 != bitsPerComponent);
|
|
|
|
break;
|
|
|
|
case kRGB_Color:
|
|
|
|
case kBGR_Color:
|
|
|
|
case kBGRX_Color:
|
|
|
|
SkASSERT(kOpaque_Alpha == alpha);
|
|
|
|
SkASSERT(bitsPerComponent >= 8);
|
|
|
|
break;
|
|
|
|
case kYUV_Color:
|
|
|
|
case kInvertedCMYK_Color:
|
|
|
|
case kYCCK_Color:
|
|
|
|
SkASSERT(kOpaque_Alpha == alpha);
|
|
|
|
SkASSERT(8 == bitsPerComponent);
|
|
|
|
break;
|
|
|
|
case kRGBA_Color:
|
|
|
|
SkASSERT(kOpaque_Alpha != alpha);
|
|
|
|
SkASSERT(bitsPerComponent >= 8);
|
|
|
|
break;
|
|
|
|
case kBGRA_Color:
|
|
|
|
case kYUVA_Color:
|
|
|
|
SkASSERT(kOpaque_Alpha != alpha);
|
|
|
|
SkASSERT(8 == bitsPerComponent);
|
|
|
|
break;
|
2018-08-27 15:55:46 +00:00
|
|
|
case kXAlpha_Color:
|
|
|
|
SkASSERT(kUnpremul_Alpha == alpha);
|
|
|
|
SkASSERT(8 == bitsPerComponent);
|
|
|
|
break;
|
|
|
|
case k565_Color:
|
|
|
|
SkASSERT(kOpaque_Alpha == alpha);
|
|
|
|
SkASSERT(8 == bitsPerComponent);
|
|
|
|
break;
|
2016-04-20 18:53:35 +00:00
|
|
|
default:
|
|
|
|
SkASSERT(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-08-27 15:55:46 +00:00
|
|
|
return SkEncodedInfo(width, height, color, alpha, bitsPerComponent, std::move(profile));
|
2016-04-20 18:53:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2018-08-27 15:55:46 +00:00
|
|
|
* Returns a recommended SkImageInfo.
|
|
|
|
*
|
|
|
|
* TODO: Leave this up to the client.
|
2016-04-20 18:53:35 +00:00
|
|
|
*/
|
2018-08-27 15:55:46 +00:00
|
|
|
SkImageInfo makeImageInfo() const {
|
|
|
|
auto ct = kGray_Color == fColor ? kGray_8_SkColorType :
|
|
|
|
kXAlpha_Color == fColor ? kAlpha_8_SkColorType :
|
|
|
|
k565_Color == fColor ? kRGB_565_SkColorType :
|
|
|
|
kN32_SkColorType ;
|
2017-12-05 18:55:24 +00:00
|
|
|
auto alpha = kOpaque_Alpha == fAlpha ? kOpaque_SkAlphaType
|
|
|
|
: kUnpremul_SkAlphaType;
|
2018-08-27 15:55:46 +00:00
|
|
|
sk_sp<SkColorSpace> cs = fProfile ? SkColorSpace::Make(*fProfile->profile())
|
|
|
|
: nullptr;
|
|
|
|
if (!cs) {
|
|
|
|
cs = SkColorSpace::MakeSRGB();
|
|
|
|
}
|
|
|
|
return SkImageInfo::Make(fWidth, fHeight, ct, alpha, std::move(cs));
|
2016-04-20 18:53:35 +00:00
|
|
|
}
|
|
|
|
|
2018-08-27 15:55:46 +00:00
|
|
|
int width() const { return fWidth; }
|
|
|
|
int height() const { return fHeight; }
|
|
|
|
Color color() const { return fColor; }
|
|
|
|
Alpha alpha() const { return fAlpha; }
|
2017-08-15 16:24:02 +00:00
|
|
|
bool opaque() const { return fAlpha == kOpaque_Alpha; }
|
2018-08-27 15:55:46 +00:00
|
|
|
const skcms_ICCProfile* profile() const {
|
|
|
|
if (!fProfile) return nullptr;
|
|
|
|
return fProfile->profile();
|
|
|
|
}
|
2017-08-15 16:24:02 +00:00
|
|
|
|
2016-04-22 20:18:37 +00:00
|
|
|
uint8_t bitsPerComponent() const { return fBitsPerComponent; }
|
|
|
|
|
|
|
|
uint8_t bitsPerPixel() const {
|
|
|
|
switch (fColor) {
|
|
|
|
case kGray_Color:
|
|
|
|
return fBitsPerComponent;
|
2018-08-27 15:55:46 +00:00
|
|
|
case kXAlpha_Color:
|
2016-04-22 20:18:37 +00:00
|
|
|
case kGrayAlpha_Color:
|
|
|
|
return 2 * fBitsPerComponent;
|
|
|
|
case kPalette_Color:
|
|
|
|
return fBitsPerComponent;
|
|
|
|
case kRGB_Color:
|
|
|
|
case kBGR_Color:
|
|
|
|
case kYUV_Color:
|
2018-08-27 15:55:46 +00:00
|
|
|
case k565_Color:
|
2016-04-22 20:18:37 +00:00
|
|
|
return 3 * fBitsPerComponent;
|
|
|
|
case kRGBA_Color:
|
|
|
|
case kBGRA_Color:
|
|
|
|
case kBGRX_Color:
|
|
|
|
case kYUVA_Color:
|
|
|
|
case kInvertedCMYK_Color:
|
|
|
|
case kYCCK_Color:
|
|
|
|
return 4 * fBitsPerComponent;
|
|
|
|
default:
|
|
|
|
SkASSERT(false);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-27 15:55:46 +00:00
|
|
|
SkEncodedInfo(const SkEncodedInfo& orig) = delete;
|
|
|
|
SkEncodedInfo& operator=(const SkEncodedInfo&) = delete;
|
Revert "Reland "Switch SkCodec to use skcms" plus fixes"
This reverts commit 49894f450fb155f4f236067109abd9017c85096e.
Reason for revert: Breaking a CTS test on the Android roll:
java.lang.AssertionError: expected:<67043583> but was:<50266367>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:834)
at org.junit.Assert.assertEquals(Assert.java:645)
at org.junit.Assert.assertEquals(Assert.java:631)
at android.graphics.cts.BitmapColorSpaceTest.verifyGetPixel(BitmapColorSpaceTest.java:301)
at android.graphics.cts.BitmapColorSpaceTest.inColorSpaceP3ToSRGB(BitmapColorSpaceTest.java:612)
Expected: 3FF00FF Actual: 2FF00FF
Original change's description:
> Reland "Switch SkCodec to use skcms" plus fixes
>
> This reverts commit 33d5394d08f645a9f612ba96115acb0e8408a97c,
> relanding 81886e8f9461c7049751c6a2c194a1df632dd362 as well as
> "Fix CMYK handling in JPEG codec" (commit
> f8ae5ce20cf6df2dab4149fb2838d9d8dc6bd1af)
>
> Add a test based on the CTS test that failed in the original commit.
> purple-displayprofile.png is the image used in the CTS test, with the
> Android license.
>
> This also adds a fix for SkAndroidCodec, ensuring that we continue to
> use a wide gamut SkColorSpace for images that do not have a numerical
> transfer function and have a wide gamut. This includes a test, with
> wide-gamut.png, which was created with Photoshop and the profile
> "sRGB_Calibrated_Homogeneous.icc" from the skcms tree.
>
> Bug: skia:6839
> Bug: skia:8052
> Bug: skia:8278
>
> TBR=djsollen@google.com
> As with the original, no API change
>
> Change-Id: I4e5bba6a3151f9dc6491e8eda73d4de0535bd692
> Reviewed-on: https://skia-review.googlesource.com/149043
> Commit-Queue: Leon Scroggins <scroggo@google.com>
> Reviewed-by: Brian Osman <brianosman@google.com>
> Reviewed-by: Leon Scroggins <scroggo@google.com>
TBR=djsollen@google.com,mtklein@google.com,scroggo@google.com,brianosman@google.com
Change-Id: Ie71e1fecc26de8225d2fe603765c1e1e0d738634
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:6839, skia:8052, skia:8278
Reviewed-on: https://skia-review.googlesource.com/149262
Reviewed-by: Leon Scroggins <scroggo@google.com>
Commit-Queue: Leon Scroggins <scroggo@google.com>
2018-08-24 21:41:24 +00:00
|
|
|
|
2018-08-27 15:55:46 +00:00
|
|
|
SkEncodedInfo(SkEncodedInfo&& orig) = default;
|
|
|
|
SkEncodedInfo& operator=(SkEncodedInfo&&) = default;
|
|
|
|
|
|
|
|
// Explicit copy method, to avoid accidental copying.
|
|
|
|
SkEncodedInfo copy() const {
|
|
|
|
auto copy = SkEncodedInfo::Make(fWidth, fHeight, fColor, fAlpha, fBitsPerComponent);
|
|
|
|
if (fProfile) {
|
|
|
|
copy.fProfile.reset(new ICCProfile(*fProfile.get()));
|
|
|
|
}
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
SkEncodedInfo(int width, int height, Color color, Alpha alpha,
|
|
|
|
uint8_t bitsPerComponent, std::unique_ptr<ICCProfile> profile)
|
|
|
|
: fWidth(width)
|
|
|
|
, fHeight(height)
|
|
|
|
, fColor(color)
|
2016-04-20 18:53:35 +00:00
|
|
|
, fAlpha(alpha)
|
|
|
|
, fBitsPerComponent(bitsPerComponent)
|
2018-08-27 15:55:46 +00:00
|
|
|
, fProfile(std::move(profile))
|
2016-04-20 18:53:35 +00:00
|
|
|
{}
|
|
|
|
|
2018-08-27 15:55:46 +00:00
|
|
|
int fWidth;
|
|
|
|
int fHeight;
|
|
|
|
Color fColor;
|
|
|
|
Alpha fAlpha;
|
|
|
|
uint8_t fBitsPerComponent;
|
|
|
|
std::unique_ptr<ICCProfile> fProfile;
|
2016-04-20 18:53:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|