#include "lcms2.h"
#endif
+static void fz_premultiply_row(fz_context *ctx, int n, int c, int w, unsigned char *s)
+{
+ unsigned char a;
+ int k;
+ int n1 = n-1;
+ for (; w > 0; w--)
+ {
+ a = s[n1];
+ if (a == 0)
+ memset(s, 0, c);
+ else if (a != 255)
+ for (k = 0; k < c; k++)
+ s[k] = fz_mul255(s[k], a);
+ s += n;
+ }
+}
+
+static void fz_premultiply_row_0or1(fz_context *ctx, int n, int c, int w, unsigned char *s)
+{
+ unsigned char a;
+ int n1 = n-1;
+ for (; w > 0; w--)
+ {
+ a = s[n1];
+ if (a == 0)
+ memset(s, 0, c);
+ s += n;
+ }
+}
+
+/* Returns 0 for all the alphas being 0, 1 for them being 0 or 255, 2 otherwise. */
+static int fz_unmultiply_row(fz_context *ctx, int n, int c, int w, unsigned char *s, const unsigned char *in)
+{
+ int a, inva;
+ int k;
+ int n1 = n-1;
+ for (; w > 0; w--)
+ {
+ a = in[n1];
+ if (a != 0)
+ goto nonzero;
+ for (k = 0; k < c; k++)
+ s[k] = 0;
+ for (;k < n1; k++)
+ s[k] = in[k];
+ s[n1] = 0;
+ s += n;
+ in += n;
+ }
+ return 0;
+ for (; w > 0; w--)
+ {
+ a = in[n1];
+nonzero:
+ if (a != 0 && a != 255)
+ goto varying;
+ k = 0;
+ if (a == 0)
+ for (; k < c; k++)
+ s[k] = 0;
+ for (;k < n; k++)
+ s[k] = in[k];
+ s += n;
+ in += n;
+ }
+ return 1;
+ for (; w > 0; w--)
+ {
+ a = in[n1];
+varying:
+ if (a == 0)
+ {
+ for (k = 0; k < c; k++)
+ s[k] = 0;
+ for (;k < n1; k++)
+ s[k] = in[k];
+ s[k] = 0;
+ }
+ else if (a == 255)
+ {
+ memcpy(s, in, n);
+ }
+ else
+ {
+ inva = 255 * 256 / a;
+ for (k = 0; k < c; k++)
+ s[k] = (in[k] * inva) >> 8;
+ for (;k < n1; k++)
+ s[k] = in[k];
+ s[n1] = a;
+ }
+ s += n;
+ in += n;
+ }
+ return 2;
+}
+
struct fz_icc_link
{
fz_storable storable;
{
GLOINIT
int cmm_num_src, cmm_num_dst, cmm_extras;
- unsigned char *inputpos, *outputpos;
+ unsigned char *inputpos, *outputpos, *buffer;
int ss = src->stride;
int ds = dst->stride;
int sw = src->w;
+ int dw = dst->w;
int sn = src->n;
int dn = dst->n;
int sa = src->alpha;
inputpos = src->samples;
outputpos = dst->samples;
- for (; h > 0; h--)
+ /* LCMS can only handle premultiplied data if the number of 'extra'
+ * channels is the same. If not, do it by steam. */
+ if (sa && cmm_extras != (int)T_EXTRA(dst_format))
{
- cmsDoTransform(GLO link->handle, inputpos, outputpos, sw);
- inputpos += ss;
- outputpos += ds;
+ buffer = fz_malloc(ctx, ss);
+ for (; h > 0; h--)
+ {
+ int mult = fz_unmultiply_row(ctx, sn, sc, sw, buffer, inputpos);
+ if (mult == 0)
+ {
+ /* Solid transparent row. No point in doing the transform
+ * because it will premultiplied back to 0. */
+ memset(outputpos, 0, ds);
+ }
+ else
+ {
+ cmsDoTransform(GLO link->handle, buffer, outputpos, sw);
+ if (mult == 1)
+ fz_premultiply_row_0or1(ctx, dn, dc, dw, outputpos);
+ else if (mult == 2)
+ fz_premultiply_row(ctx, dn, dc, dw, outputpos);
+ }
+ inputpos += ss;
+ outputpos += ds;
+ }
+ fz_free(ctx, buffer);
}
+ else
+ for (; h > 0; h--)
+ {
+ cmsDoTransform(GLO link->handle, inputpos, outputpos, sw);
+ inputpos += ss;
+ outputpos += ds;
+ }
}
#endif
{
int sx = src->s + src->alpha;
int dx = dst->s + dst->alpha;
- link = fz_find_icc_link(ctx, ss, sx, ds, dx, prf, params, 0, copy_spots, src->alpha);
+ /* If we have alpha, we're preserving spots and we have the same number
+ * of 'extra' (non process, spots+alpha) channels (i.e. sx == dx), then
+ * we get lcms2 to do the premultiplication handling for us. If not,
+ * fz_icc_transform_pixmap will have to do it by steam. */
+ int premult = src->alpha && (sx == dx) && copy_spots;
+ link = fz_find_icc_link(ctx, ss, sx, ds, dx, prf, params, 0, copy_spots, premult);
fz_icc_transform_pixmap(ctx, link, src, dst, copy_spots);
}
fz_catch(ctx)