SkPDF: more accurate (float) colors from paint
Does not yet affect colors from gradient shaders. Serialize colors with 4 digits of accuracy, not 3. Resulting PDFs are usually slightly larger, but render the same when rendered into an 8-bit buffer. Change-Id: I64336f3a1f34021f9ddb723bd8a16d51ddfea0f4 Reviewed-on: https://skia-review.googlesource.com/c/161141 Commit-Queue: Hal Canary <halcanary@google.com> Auto-Submit: Hal Canary <halcanary@google.com> Reviewed-by: Mike Klein <mtklein@google.com>
This commit is contained in:
parent
6187f09dcf
commit
04ac46135f
@ -148,13 +148,13 @@ static void transform_shader(SkPaint* paint, const SkMatrix& ctm) {
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_pdf_color(SkColor color, SkWStream* result) {
|
||||
SkASSERT(SkColorGetA(color) == 0xFF); // We handle alpha elsewhere.
|
||||
SkPDFUtils::AppendColorComponent(SkColorGetR(color), result);
|
||||
static void emit_pdf_color(SkColor4f color, SkWStream* result) {
|
||||
SkASSERT(color.fA == 1); // We handle alpha elsewhere.
|
||||
SkPDFUtils::AppendColorComponentF(color.fR, result);
|
||||
result->writeText(" ");
|
||||
SkPDFUtils::AppendColorComponent(SkColorGetG(color), result);
|
||||
SkPDFUtils::AppendColorComponentF(color.fG, result);
|
||||
result->writeText(" ");
|
||||
SkPDFUtils::AppendColorComponent(SkColorGetB(color), result);
|
||||
SkPDFUtils::AppendColorComponentF(color.fB, result);
|
||||
result->writeText(" ");
|
||||
}
|
||||
|
||||
@ -165,7 +165,7 @@ void remove_color_filter(SkPaint* paint) {
|
||||
if (SkShader* shader = paint->getShader()) {
|
||||
paint->setShader(shader->makeWithColorFilter(paint->refColorFilter()));
|
||||
} else {
|
||||
paint->setColor(cf->filterColor(paint->getColor()));
|
||||
paint->setColor4f(cf->filterColor4f(paint->getColor4f(), nullptr), nullptr);
|
||||
}
|
||||
paint->setColorFilter(nullptr);
|
||||
}
|
||||
@ -1699,13 +1699,13 @@ void SkPDFDevice::populateGraphicStateEntryFromPaint(
|
||||
entry->fMatrix = matrix;
|
||||
entry->fClipStackGenID = clipStack ? clipStack->getTopmostGenID()
|
||||
: SkClipStack::kWideOpenGenID;
|
||||
entry->fColor = SkColorSetA(paint.getColor(), 0xFF);
|
||||
SkColor4f color = paint.getColor4f();
|
||||
entry->fColor = {color.fR, color.fG, color.fB, 1};
|
||||
entry->fShaderIndex = -1;
|
||||
|
||||
// PDF treats a shader as a color, so we only set one or the other.
|
||||
sk_sp<SkPDFObject> pdfShader;
|
||||
SkShader* shader = paint.getShader();
|
||||
SkColor color = paint.getColor();
|
||||
if (shader) {
|
||||
if (SkShader::kColor_GradientType == shader->asAGradient(nullptr)) {
|
||||
// We don't have to set a shader just for a color.
|
||||
@ -1715,8 +1715,9 @@ void SkPDFDevice::populateGraphicStateEntryFromPaint(
|
||||
gradientInfo.fColorOffsets = nullptr;
|
||||
gradientInfo.fColorCount = 1;
|
||||
SkAssertResult(shader->asAGradient(&gradientInfo) == SkShader::kColor_GradientType);
|
||||
entry->fColor = SkColorSetA(gradientColor, 0xFF);
|
||||
color = gradientColor;
|
||||
color = SkColor4f::FromColor(gradientColor);
|
||||
entry->fColor ={color.fR, color.fG, color.fB, 1};
|
||||
|
||||
} else {
|
||||
// PDF positions patterns relative to the initial transform, so
|
||||
// we need to apply the current transform to the shader parameters.
|
||||
@ -1744,11 +1745,11 @@ void SkPDFDevice::populateGraphicStateEntryFromPaint(
|
||||
}
|
||||
|
||||
sk_sp<SkPDFDict> newGraphicState;
|
||||
if (color == paint.getColor()) {
|
||||
if (color == paint.getColor4f()) {
|
||||
newGraphicState = SkPDFGraphicState::GetGraphicStateForPaint(fDocument->canon(), paint);
|
||||
} else {
|
||||
SkPaint newPaint = paint;
|
||||
newPaint.setColor(color);
|
||||
newPaint.setColor4f(color, nullptr);
|
||||
newGraphicState = SkPDFGraphicState::GetGraphicStateForPaint(fDocument->canon(), newPaint);
|
||||
}
|
||||
entry->fGraphicStateIndex = find_or_add(&fGraphicStateResources, std::move(newGraphicState));
|
||||
@ -1839,7 +1840,7 @@ void SkPDFDevice::internalDrawImageRect(SkKeyedImage imageSubset,
|
||||
// In the case of alpha images with shaders, the shader's coordinate
|
||||
// system is the image's coordiantes.
|
||||
tmpPaint.setShader(sk_ref_sp(paint.getShader()));
|
||||
tmpPaint.setColor(paint.getColor());
|
||||
tmpPaint.setColor4f(paint.getColor4f(), nullptr);
|
||||
canvas->clear(0x00000000);
|
||||
canvas->drawImage(imageSubset.image().get(), 0, 0, &tmpPaint);
|
||||
paint.setShader(nullptr);
|
||||
|
@ -123,7 +123,7 @@ public:
|
||||
struct GraphicStateEntry {
|
||||
SkMatrix fMatrix = SkMatrix::I();
|
||||
uint32_t fClipStackGenID = SkClipStack::kWideOpenGenID;
|
||||
SkColor fColor = SK_ColorBLACK;
|
||||
SkColor4f fColor = {0, 0, 0, 1};
|
||||
SkScalar fTextScaleX = 1; // Zero means we don't care what the value is.
|
||||
SkPaint::Style fTextFill = SkPaint::kFill_Style; // Only if TextScaleX is non-zero.
|
||||
int fShaderIndex = -1;
|
||||
|
@ -244,21 +244,16 @@ void SkPDFUtils::ApplyPattern(int objectIndex, SkWStream* content) {
|
||||
content->writeText(" scn\n");
|
||||
}
|
||||
|
||||
size_t SkPDFUtils::ColorToDecimal(uint8_t value, char result[5]) {
|
||||
if (value == 255 || value == 0) {
|
||||
result[0] = value ? '1' : '0';
|
||||
result[1] = '\0';
|
||||
return 1;
|
||||
}
|
||||
// int x = 0.5 + (1000.0 / 255.0) * value;
|
||||
int x = SkFixedRoundToInt((SK_Fixed1 * 1000 / 255) * value);
|
||||
// return "x/pow(10, places)", given 0<x<pow(10, places)
|
||||
// result points to places+2 chars.
|
||||
static size_t print_permil_as_decimal(int x, char* result, unsigned places) {
|
||||
result[0] = '.';
|
||||
for (int i = 3; i > 0; --i) {
|
||||
for (int i = places; i > 0; --i) {
|
||||
result[i] = '0' + x % 10;
|
||||
x /= 10;
|
||||
}
|
||||
int j;
|
||||
for (j = 3; j > 1; --j) {
|
||||
for (j = places; j > 1; --j) {
|
||||
if (result[j] != '0') {
|
||||
break;
|
||||
}
|
||||
@ -268,6 +263,36 @@ size_t SkPDFUtils::ColorToDecimal(uint8_t value, char result[5]) {
|
||||
}
|
||||
|
||||
|
||||
static constexpr int int_pow(int base, unsigned exp, int acc = 1) {
|
||||
return exp < 1 ? acc
|
||||
: int_pow(base * base,
|
||||
exp / 2,
|
||||
(exp % 2) ? acc * base : acc);
|
||||
}
|
||||
|
||||
|
||||
size_t SkPDFUtils::ColorToDecimalF(float value, char result[kFloatColorDecimalCount + 2]) {
|
||||
static constexpr int kFactor = int_pow(10, kFloatColorDecimalCount);
|
||||
int x = sk_float_round2int(value * kFactor);
|
||||
if (x >= kFactor || x <= 0) { // clamp to 0-1
|
||||
result[0] = x > 0 ? '1' : '0';
|
||||
result[1] = '\0';
|
||||
return 1;
|
||||
}
|
||||
return print_permil_as_decimal(x, result, kFloatColorDecimalCount);
|
||||
}
|
||||
|
||||
size_t SkPDFUtils::ColorToDecimal(uint8_t value, char result[5]) {
|
||||
if (value == 255 || value == 0) {
|
||||
result[0] = value ? '1' : '0';
|
||||
result[1] = '\0';
|
||||
return 1;
|
||||
}
|
||||
// int x = 0.5 + (1000.0 / 255.0) * value;
|
||||
int x = SkFixedRoundToInt((SK_Fixed1 * 1000 / 255) * value);
|
||||
return print_permil_as_decimal(x, result, 3);
|
||||
}
|
||||
|
||||
bool SkPDFUtils::InverseTransformBBox(const SkMatrix& matrix, SkRect* bbox) {
|
||||
SkMatrix inverse;
|
||||
if (!matrix.invert(&inverse)) {
|
||||
|
@ -66,11 +66,19 @@ void ApplyPattern(int objectIndex, SkWStream* content);
|
||||
// Converts (value / 255.0) with three significant digits of accuracy.
|
||||
// Writes value as string into result. Returns strlen() of result.
|
||||
size_t ColorToDecimal(uint8_t value, char result[5]);
|
||||
|
||||
static constexpr unsigned kFloatColorDecimalCount = 4;
|
||||
size_t ColorToDecimalF(float value, char result[kFloatColorDecimalCount + 2]);
|
||||
inline void AppendColorComponent(uint8_t value, SkWStream* wStream) {
|
||||
char buffer[5];
|
||||
size_t len = SkPDFUtils::ColorToDecimal(value, buffer);
|
||||
wStream->write(buffer, len);
|
||||
}
|
||||
inline void AppendColorComponentF(float value, SkWStream* wStream) {
|
||||
char buffer[kFloatColorDecimalCount + 2];
|
||||
size_t len = SkPDFUtils::ColorToDecimalF(value, buffer);
|
||||
wStream->write(buffer, len);
|
||||
}
|
||||
|
||||
inline void AppendScalar(SkScalar value, SkWStream* stream) {
|
||||
char result[kMaximumSkFloatToDecimalLength];
|
||||
|
Loading…
Reference in New Issue
Block a user