Expose SkColorSpaceTransferFn inversion function
Also adds tolerance to checks against zero BUG=skia: Change-Id: I2ad5737c6eef7e3ed52a685dceb347a434607336 Reviewed-on: https://skia-review.googlesource.com/9643 Commit-Queue: Brian Osman <brianosman@google.com> Reviewed-by: Matt Sarett <msarett@google.com>
This commit is contained in:
parent
dce25909ac
commit
73e6270748
@ -48,6 +48,12 @@ struct SK_API SkColorSpaceTransferFn {
|
||||
float fD;
|
||||
float fE;
|
||||
float fF;
|
||||
|
||||
/**
|
||||
* Produces a new parametric transfer function equation that is the mathematical inverse of
|
||||
* this one.
|
||||
*/
|
||||
SkColorSpaceTransferFn invert() const;
|
||||
};
|
||||
|
||||
class SK_API SkColorSpace : public SkRefCnt {
|
||||
|
@ -632,3 +632,47 @@ bool SkColorSpace::Equals(const SkColorSpace* src, const SkColorSpace* dst) {
|
||||
serializedSrcData->size());
|
||||
}
|
||||
}
|
||||
|
||||
SkColorSpaceTransferFn SkColorSpaceTransferFn::invert() const {
|
||||
// Original equation is: y = (ax + b)^g + e for x >= d
|
||||
// y = cx + f otherwise
|
||||
//
|
||||
// so 1st inverse is: (y - e)^(1/g) = ax + b
|
||||
// x = ((y - e)^(1/g) - b) / a
|
||||
//
|
||||
// which can be re-written as: x = (1/a)(y - e)^(1/g) - b/a
|
||||
// x = ((1/a)^g)^(1/g) * (y - e)^(1/g) - b/a
|
||||
// x = ([(1/a)^g]y + [-((1/a)^g)e]) ^ [1/g] + [-b/a]
|
||||
//
|
||||
// and 2nd inverse is: x = (y - f) / c
|
||||
// which can be re-written as: x = [1/c]y + [-f/c]
|
||||
//
|
||||
// and now both can be expressed in terms of the same parametric form as the
|
||||
// original - parameters are enclosed in square brackets.
|
||||
SkColorSpaceTransferFn inv = { 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
// find inverse for linear segment (if possible)
|
||||
if (!transfer_fn_almost_equal(0.f, fC)) {
|
||||
inv.fC = 1.f / fC;
|
||||
inv.fF = -fF / fC;
|
||||
} else {
|
||||
// otherwise assume it should be 0 as it is the lower segment
|
||||
// as y = f is a constant function
|
||||
}
|
||||
|
||||
// find inverse for the other segment (if possible)
|
||||
if (transfer_fn_almost_equal(0.f, fA) || transfer_fn_almost_equal(0.f, fG)) {
|
||||
// otherwise assume it should be 1 as it is the top segment
|
||||
// as you can't invert the constant functions y = b^g + c, or y = 1 + c
|
||||
inv.fG = 1.f;
|
||||
inv.fE = 1.f;
|
||||
} else {
|
||||
inv.fG = 1.f / fG;
|
||||
inv.fA = powf(1.f / fA, fG);
|
||||
inv.fB = -inv.fA * fE;
|
||||
inv.fE = -fB / fA;
|
||||
}
|
||||
inv.fD = fC * fD + fF;
|
||||
|
||||
return inv;
|
||||
}
|
||||
|
@ -88,52 +88,6 @@ static inline bool gamma_to_parametric(SkColorSpaceTransferFn* coeffs, const SkG
|
||||
return false;
|
||||
}
|
||||
}
|
||||
static inline SkColorSpaceTransferFn invert_parametric(const SkColorSpaceTransferFn& fn) {
|
||||
// Original equation is: y = (ax + b)^g + e for x >= d
|
||||
// y = cx + f otherwise
|
||||
//
|
||||
// so 1st inverse is: (y - e)^(1/g) = ax + b
|
||||
// x = ((y - e)^(1/g) - b) / a
|
||||
//
|
||||
// which can be re-written as: x = (1/a)(y - e)^(1/g) - b/a
|
||||
// x = ((1/a)^g)^(1/g) * (y - e)^(1/g) - b/a
|
||||
// x = ([(1/a)^g]y + [-((1/a)^g)e]) ^ [1/g] + [-b/a]
|
||||
//
|
||||
// and 2nd inverse is: x = (y - f) / c
|
||||
// which can be re-written as: x = [1/c]y + [-f/c]
|
||||
//
|
||||
// and now both can be expressed in terms of the same parametric form as the
|
||||
// original - parameters are enclosed in square brackets.
|
||||
|
||||
// find inverse for linear segment (if possible)
|
||||
float c, f;
|
||||
if (0.f == fn.fC) {
|
||||
// otherwise assume it should be 0 as it is the lower segment
|
||||
// as y = f is a constant function
|
||||
c = 0.f;
|
||||
f = 0.f;
|
||||
} else {
|
||||
c = 1.f / fn.fC;
|
||||
f = -fn.fF / fn.fC;
|
||||
}
|
||||
// find inverse for the other segment (if possible)
|
||||
float g, a, b, e;
|
||||
if (0.f == fn.fA || 0.f == fn.fG) {
|
||||
// otherwise assume it should be 1 as it is the top segment
|
||||
// as you can't invert the constant functions y = b^g + c, or y = 1 + c
|
||||
g = 1.f;
|
||||
a = 0.f;
|
||||
b = 0.f;
|
||||
e = 1.f;
|
||||
} else {
|
||||
g = 1.f / fn.fG;
|
||||
a = powf(1.f / fn.fA, fn.fG);
|
||||
b = -a * fn.fE;
|
||||
e = -fn.fB / fn.fA;
|
||||
}
|
||||
const float d = fn.fC * fn.fD + fn.fF;
|
||||
return {g, a, b, c, d, e, f};
|
||||
}
|
||||
|
||||
SkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace,
|
||||
SkColorSpace_XYZ* dstSpace)
|
||||
@ -279,7 +233,7 @@ SkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace,
|
||||
} else {
|
||||
SkColorSpaceTransferFn fn;
|
||||
SkAssertResult(gamma_to_parametric(&fn, gammas, channel));
|
||||
this->addTransferFn(invert_parametric(fn), channel);
|
||||
this->addTransferFn(fn.invert(), channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user