summaryrefslogtreecommitdiffstats
path: root/third_party/jpeg-xl/lib/jpegli/color_transform.cc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/jpeg-xl/lib/jpegli/color_transform.cc316
1 files changed, 288 insertions, 28 deletions
diff --git a/third_party/jpeg-xl/lib/jpegli/color_transform.cc b/third_party/jpeg-xl/lib/jpegli/color_transform.cc
index 60a0dc83bb..ec906bedce 100644
--- a/third_party/jpeg-xl/lib/jpegli/color_transform.cc
+++ b/third_party/jpeg-xl/lib/jpegli/color_transform.cc
@@ -26,11 +26,16 @@ using hwy::HWY_NAMESPACE::Mul;
using hwy::HWY_NAMESPACE::MulAdd;
using hwy::HWY_NAMESPACE::Sub;
-void YCbCrToRGB(float* row[kMaxComponents], size_t xsize) {
+template <int kRed, int kGreen, int kBlue, int kAlpha>
+void YCbCrToExtRGB(float* row[kMaxComponents], size_t xsize) {
const HWY_CAPPED(float, 8) df;
- float* JXL_RESTRICT row0 = row[0];
- float* JXL_RESTRICT row1 = row[1];
- float* JXL_RESTRICT row2 = row[2];
+ const float* row_y = row[0];
+ const float* row_cb = row[1];
+ const float* row_cr = row[2];
+ float* row_r = row[kRed];
+ float* row_g = row[kGreen];
+ float* row_b = row[kBlue];
+ float* row_a = row[kAlpha];
// Full-range BT.601 as defined by JFIF Clause 7:
// https://www.itu.int/rec/T-REC-T.871-201105-I/en
@@ -38,20 +43,48 @@ void YCbCrToRGB(float* row[kMaxComponents], size_t xsize) {
const auto cgcb = Set(df, -0.114f * 1.772f / 0.587f);
const auto cgcr = Set(df, -0.299f * 1.402f / 0.587f);
const auto cbcb = Set(df, 1.772f);
+ const auto alpha_opaque = Set(df, 127.0f / 255.0f);
for (size_t x = 0; x < xsize; x += Lanes(df)) {
- const auto y_vec = Load(df, row0 + x);
- const auto cb_vec = Load(df, row1 + x);
- const auto cr_vec = Load(df, row2 + x);
+ const auto y_vec = Load(df, row_y + x);
+ const auto cb_vec = Load(df, row_cb + x);
+ const auto cr_vec = Load(df, row_cr + x);
const auto r_vec = MulAdd(crcr, cr_vec, y_vec);
const auto g_vec = MulAdd(cgcr, cr_vec, MulAdd(cgcb, cb_vec, y_vec));
const auto b_vec = MulAdd(cbcb, cb_vec, y_vec);
- Store(r_vec, df, row0 + x);
- Store(g_vec, df, row1 + x);
- Store(b_vec, df, row2 + x);
+ Store(r_vec, df, row_r + x);
+ Store(g_vec, df, row_g + x);
+ Store(b_vec, df, row_b + x);
+ if (kAlpha >= 0) {
+ Store(alpha_opaque, df, row_a + x);
+ }
}
}
+void YCbCrToRGB(float* row[kMaxComponents], size_t xsize) {
+ YCbCrToExtRGB<0, 1, 2, -1>(row, xsize);
+}
+
+void YCbCrToBGR(float* row[kMaxComponents], size_t xsize) {
+ YCbCrToExtRGB<2, 1, 0, -1>(row, xsize);
+}
+
+void YCbCrToRGBA(float* row[kMaxComponents], size_t xsize) {
+ YCbCrToExtRGB<0, 1, 2, 3>(row, xsize);
+}
+
+void YCbCrToBGRA(float* row[kMaxComponents], size_t xsize) {
+ YCbCrToExtRGB<2, 1, 0, 3>(row, xsize);
+}
+
+void YCbCrToARGB(float* row[kMaxComponents], size_t xsize) {
+ YCbCrToExtRGB<1, 2, 3, 0>(row, xsize);
+}
+
+void YCbCrToABGR(float* row[kMaxComponents], size_t xsize) {
+ YCbCrToExtRGB<3, 2, 1, 0>(row, xsize);
+}
+
void YCCKToCMYK(float* row[kMaxComponents], size_t xsize) {
const HWY_CAPPED(float, 8) df;
float* JXL_RESTRICT row0 = row[0];
@@ -66,11 +99,15 @@ void YCCKToCMYK(float* row[kMaxComponents], size_t xsize) {
}
}
-void RGBToYCbCr(float* row[kMaxComponents], size_t xsize) {
+template <int kRed, int kGreen, int kBlue>
+void ExtRGBToYCbCr(float* row[kMaxComponents], size_t xsize) {
const HWY_CAPPED(float, 8) df;
- float* JXL_RESTRICT row0 = row[0];
- float* JXL_RESTRICT row1 = row[1];
- float* JXL_RESTRICT row2 = row[2];
+ const float* row_r = row[kRed];
+ const float* row_g = row[kGreen];
+ const float* row_b = row[kBlue];
+ float* row_y = row[0];
+ float* row_cb = row[1];
+ float* row_cr = row[2];
// Full-range BT.601 as defined by JFIF Clause 7:
// https://www.itu.int/rec/T-REC-T.871-201105-I/en
const auto c128 = Set(df, 128.0f);
@@ -85,9 +122,9 @@ void RGBToYCbCr(float* row[kMaxComponents], size_t xsize) {
const auto kNormB = Div(Set(df, 1.0f), (Add(kR, Add(kG, kAmpB))));
for (size_t x = 0; x < xsize; x += Lanes(df)) {
- const auto r = Load(df, row0 + x);
- const auto g = Load(df, row1 + x);
- const auto b = Load(df, row2 + x);
+ const auto r = Load(df, row_r + x);
+ const auto g = Load(df, row_g + x);
+ const auto b = Load(df, row_b + x);
const auto r_base = Mul(r, kR);
const auto r_diff = Mul(r, kDiffR);
const auto g_base = Mul(g, kG);
@@ -96,12 +133,28 @@ void RGBToYCbCr(float* row[kMaxComponents], size_t xsize) {
const auto y_base = Add(r_base, Add(g_base, b_base));
const auto cb_vec = MulAdd(Sub(b_diff, y_base), kNormB, c128);
const auto cr_vec = MulAdd(Sub(r_diff, y_base), kNormR, c128);
- Store(y_base, df, row0 + x);
- Store(cb_vec, df, row1 + x);
- Store(cr_vec, df, row2 + x);
+ Store(y_base, df, row_y + x);
+ Store(cb_vec, df, row_cb + x);
+ Store(cr_vec, df, row_cr + x);
}
}
+void RGBToYCbCr(float* row[kMaxComponents], size_t xsize) {
+ ExtRGBToYCbCr<0, 1, 2>(row, xsize);
+}
+
+void BGRToYCbCr(float* row[kMaxComponents], size_t xsize) {
+ ExtRGBToYCbCr<2, 1, 0>(row, xsize);
+}
+
+void ARGBToYCbCr(float* row[kMaxComponents], size_t xsize) {
+ ExtRGBToYCbCr<1, 2, 3>(row, xsize);
+}
+
+void ABGRToYCbCr(float* row[kMaxComponents], size_t xsize) {
+ ExtRGBToYCbCr<3, 2, 1>(row, xsize);
+}
+
void CMYKToYCCK(float* row[kMaxComponents], size_t xsize) {
const HWY_CAPPED(float, 8) df;
float* JXL_RESTRICT row0 = row[0];
@@ -127,7 +180,15 @@ namespace jpegli {
HWY_EXPORT(CMYKToYCCK);
HWY_EXPORT(YCCKToCMYK);
HWY_EXPORT(YCbCrToRGB);
+HWY_EXPORT(YCbCrToBGR);
+HWY_EXPORT(YCbCrToRGBA);
+HWY_EXPORT(YCbCrToBGRA);
+HWY_EXPORT(YCbCrToARGB);
+HWY_EXPORT(YCbCrToABGR);
HWY_EXPORT(RGBToYCbCr);
+HWY_EXPORT(BGRToYCbCr);
+HWY_EXPORT(ARGBToYCbCr);
+HWY_EXPORT(ABGRToYCbCr);
bool CheckColorSpaceComponents(int num_components, J_COLOR_SPACE colorspace) {
switch (colorspace) {
@@ -164,16 +225,73 @@ bool CheckColorSpaceComponents(int num_components, J_COLOR_SPACE colorspace) {
void NullTransform(float* row[kMaxComponents], size_t len) {}
+void FillAlpha(float* row, size_t len) {
+ static const float kAlpha = 127.0f / 255.0f;
+ for (size_t i = 0; i < len; ++i) {
+ row[i] = kAlpha;
+ }
+}
+
+// Works for BGR as well.
void GrayscaleToRGB(float* row[kMaxComponents], size_t len) {
memcpy(row[1], row[0], len * sizeof(row[1][0]));
memcpy(row[2], row[0], len * sizeof(row[2][0]));
}
+// Works for BGRA as well.
+void GrayscaleToRGBA(float* row[kMaxComponents], size_t len) {
+ memcpy(row[1], row[0], len * sizeof(row[1][0]));
+ memcpy(row[2], row[0], len * sizeof(row[2][0]));
+ FillAlpha(row[3], len);
+}
+
+// Works for ABGR as well.
+void GrayscaleToARGB(float* row[kMaxComponents], size_t len) {
+ memcpy(row[1], row[0], len * sizeof(row[1][0]));
+ memcpy(row[2], row[0], len * sizeof(row[2][0]));
+ memcpy(row[3], row[0], len * sizeof(row[1][0]));
+ FillAlpha(row[0], len);
+}
+
void GrayscaleToYCbCr(float* row[kMaxComponents], size_t len) {
memset(row[1], 0, len * sizeof(row[1][0]));
memset(row[2], 0, len * sizeof(row[2][0]));
}
+void RGBToBGR(float* row[kMaxComponents], size_t len) {
+ for (size_t i = 0; i < len; ++i) {
+ std::swap(row[0][i], row[2][i]);
+ }
+}
+
+void RGBToRGBA(float* row[kMaxComponents], size_t len) {
+ FillAlpha(row[3], len);
+}
+
+void RGBToBGRA(float* row[kMaxComponents], size_t len) {
+ static const float kAlpha = 127.0f / 255.0f;
+ for (size_t i = 0; i < len; ++i) {
+ std::swap(row[0][i], row[2][i]);
+ row[3][i] = kAlpha;
+ }
+}
+
+void RGBToARGB(float* row[kMaxComponents], size_t len) {
+ memcpy(row[3], row[2], len * sizeof(row[1][0]));
+ memcpy(row[2], row[1], len * sizeof(row[2][0]));
+ memcpy(row[1], row[0], len * sizeof(row[1][0]));
+ FillAlpha(row[0], len);
+}
+
+void RGBToABGR(float* row[kMaxComponents], size_t len) {
+ static const float kAlpha = 127.0f / 255.0f;
+ for (size_t i = 0; i < len; ++i) {
+ std::swap(row[1][i], row[2][i]);
+ row[3][i] = row[0][i];
+ row[0][i] = kAlpha;
+ }
+}
+
void ChooseColorTransform(j_compress_ptr cinfo) {
jpeg_comp_master* m = cinfo->master;
if (!CheckColorSpaceComponents(cinfo->input_components,
@@ -226,6 +344,43 @@ void ChooseColorTransform(j_compress_ptr cinfo) {
}
}
+ if (cinfo->jpeg_color_space == JCS_GRAYSCALE ||
+ cinfo->jpeg_color_space == JCS_YCbCr) {
+ switch (cinfo->in_color_space) {
+#ifdef JCS_EXTENSIONS
+ case JCS_EXT_RGB:
+ case JCS_EXT_RGBX:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(RGBToYCbCr);
+ break;
+ case JCS_EXT_BGR:
+ case JCS_EXT_BGRX:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(BGRToYCbCr);
+ break;
+ case JCS_EXT_XRGB:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(ARGBToYCbCr);
+ break;
+ case JCS_EXT_XBGR:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(ABGRToYCbCr);
+ break;
+#endif
+#ifdef JCS_ALPHA_EXTENSIONS
+ case JCS_EXT_RGBA:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(RGBToYCbCr);
+ break;
+ case JCS_EXT_BGRA:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(BGRToYCbCr);
+ break;
+ case JCS_EXT_ARGB:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(ARGBToYCbCr);
+ break;
+ case JCS_EXT_ABGR:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(ABGRToYCbCr);
+ break;
+#endif
+ default:; // Nothing to do.
+ }
+ }
+
if (m->color_transform == nullptr) {
// TODO(szabadka) Support more color transforms.
JPEGLI_ERROR("Unsupported color transform %d -> %d", cinfo->in_color_space,
@@ -257,18 +412,123 @@ void ChooseColorTransform(j_decompress_ptr cinfo) {
m->color_transform = nullptr;
if (cinfo->jpeg_color_space == JCS_GRAYSCALE) {
- if (cinfo->out_color_space == JCS_RGB) {
- m->color_transform = GrayscaleToRGB;
+ switch (cinfo->out_color_space) {
+ case JCS_RGB:
+ m->color_transform = GrayscaleToRGB;
+ break;
+#ifdef JCS_EXTENSIONS
+ case JCS_EXT_RGB:
+ case JCS_EXT_BGR:
+ m->color_transform = GrayscaleToRGB;
+ break;
+ case JCS_EXT_RGBX:
+ case JCS_EXT_BGRX:
+ m->color_transform = GrayscaleToRGBA;
+ break;
+ case JCS_EXT_XRGB:
+ case JCS_EXT_XBGR:
+ m->color_transform = GrayscaleToARGB;
+ break;
+#endif
+#ifdef JCS_ALPHA_EXTENSIONS
+ case JCS_EXT_RGBA:
+ case JCS_EXT_BGRA:
+ m->color_transform = GrayscaleToRGBA;
+ break;
+ case JCS_EXT_ARGB:
+ case JCS_EXT_ABGR:
+ m->color_transform = GrayscaleToARGB;
+ break;
+#endif
+ default:
+ m->color_transform = nullptr;
}
} else if (cinfo->jpeg_color_space == JCS_RGB) {
- if (cinfo->out_color_space == JCS_GRAYSCALE) {
- m->color_transform = HWY_DYNAMIC_DISPATCH(RGBToYCbCr);
+ switch (cinfo->out_color_space) {
+ case JCS_GRAYSCALE:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(RGBToYCbCr);
+ break;
+#ifdef JCS_EXTENSIONS
+ case JCS_EXT_RGB:
+ m->color_transform = NullTransform;
+ break;
+ case JCS_EXT_BGR:
+ m->color_transform = RGBToBGR;
+ break;
+ case JCS_EXT_RGBX:
+ m->color_transform = RGBToRGBA;
+ break;
+ case JCS_EXT_BGRX:
+ m->color_transform = RGBToBGRA;
+ break;
+ case JCS_EXT_XRGB:
+ m->color_transform = RGBToARGB;
+ break;
+ case JCS_EXT_XBGR:
+ m->color_transform = RGBToABGR;
+ break;
+#endif
+#ifdef JCS_ALPHA_EXTENSIONS
+ case JCS_EXT_RGBA:
+ m->color_transform = RGBToRGBA;
+ break;
+ case JCS_EXT_BGRA:
+ m->color_transform = RGBToBGRA;
+ break;
+ case JCS_EXT_ARGB:
+ m->color_transform = RGBToARGB;
+ break;
+ case JCS_EXT_ABGR:
+ m->color_transform = RGBToABGR;
+ break;
+#endif
+ default:
+ m->color_transform = nullptr;
}
} else if (cinfo->jpeg_color_space == JCS_YCbCr) {
- if (cinfo->out_color_space == JCS_RGB) {
- m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToRGB);
- } else if (cinfo->out_color_space == JCS_GRAYSCALE) {
- m->color_transform = NullTransform;
+ switch (cinfo->out_color_space) {
+ case JCS_GRAYSCALE:
+ m->color_transform = NullTransform;
+ break;
+ case JCS_RGB:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToRGB);
+ break;
+#ifdef JCS_EXTENSIONS
+ case JCS_EXT_RGB:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToRGB);
+ break;
+ case JCS_EXT_BGR:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToBGR);
+ break;
+ case JCS_EXT_RGBX:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToRGBA);
+ break;
+ case JCS_EXT_BGRX:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToBGRA);
+ break;
+ case JCS_EXT_XRGB:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToARGB);
+ break;
+ case JCS_EXT_XBGR:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToABGR);
+ break;
+#endif
+#ifdef JCS_ALPHA_EXTENSIONS
+ case JCS_EXT_RGBA:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToRGBA);
+ break;
+ case JCS_EXT_BGRA:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToBGRA);
+ break;
+ case JCS_EXT_ARGB:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToARGB);
+ break;
+ case JCS_EXT_ABGR:
+ m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToABGR);
+ break;
+#endif
+ default:
+ m->color_transform = nullptr;
}
} else if (cinfo->jpeg_color_space == JCS_YCCK) {
if (cinfo->out_color_space == JCS_CMYK) {