aboutsummaryrefslogtreecommitdiff
path: root/jdmerge.c
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commitd9bb1510bee7d9bf2a0f2699c647a65e67ab9cf8 (patch)
treea23a17e9a6b51b90db0a8fa1f15423f488814866 /jdmerge.c
parentc6a7fc661d57f86ac08cd637abc881cbe687b11a (diff)
downloadjpeg-d9bb1510bee7d9bf2a0f2699c647a65e67ab9cf8.tar.gz
Diffstat (limited to 'jdmerge.c')
-rw-r--r--jdmerge.c397
1 files changed, 377 insertions, 20 deletions
diff --git a/jdmerge.c b/jdmerge.c
index 3744446..77f3308 100644
--- a/jdmerge.c
+++ b/jdmerge.c
@@ -38,6 +38,24 @@
#ifdef UPSAMPLE_MERGING_SUPPORTED
+#ifdef ANDROID_RGB
+
+/* Declarations for ordered dithering.
+ *
+ * We use 4x4 ordered dither array packed into 32 bits. This array is
+ * sufficent for dithering RGB_888 to RGB_565.
+ */
+
+#define DITHER_MASK 0x3
+#define DITHER_ROTATE(x) (((x)<<24) | (((x)>>8)&0x00FFFFFF))
+static const INT32 dither_matrix[4] = {
+ 0x0008020A,
+ 0x0C040E06,
+ 0x030B0109,
+ 0x0F070D05
+};
+
+#endif
/* Private subobject */
@@ -154,8 +172,14 @@ merged_2v_upsample (j_decompress_ptr cinfo,
if (upsample->spare_full) {
/* If we have a spare row saved from a previous cycle, just return it. */
+ JDIMENSION size = upsample->out_row_width;
+#ifdef ANDROID_RGB
+ if (cinfo->out_color_space == JCS_RGB_565)
+ size = cinfo->output_width*2;
+#endif
jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0,
- 1, upsample->out_row_width);
+ 1, size);
+
num_rows = 1;
upsample->spare_full = FALSE;
} else {
@@ -255,14 +279,14 @@ h2v1_merged_upsample (j_decompress_ptr cinfo,
cblue = Cbbtab[cb];
/* Fetch 2 Y values and emit 2 pixels */
y = GETJSAMPLE(*inptr0++);
- outptr[RGB_RED] = range_limit[y + cred];
+ outptr[RGB_RED] = range_limit[y + cred];
outptr[RGB_GREEN] = range_limit[y + cgreen];
- outptr[RGB_BLUE] = range_limit[y + cblue];
+ outptr[RGB_BLUE] = range_limit[y + cblue];
outptr += RGB_PIXELSIZE;
y = GETJSAMPLE(*inptr0++);
- outptr[RGB_RED] = range_limit[y + cred];
+ outptr[RGB_RED] = range_limit[y + cred];
outptr[RGB_GREEN] = range_limit[y + cgreen];
- outptr[RGB_BLUE] = range_limit[y + cblue];
+ outptr[RGB_BLUE] = range_limit[y + cblue];
outptr += RGB_PIXELSIZE;
}
/* If image width is odd, do the last output column separately */
@@ -273,13 +297,148 @@ h2v1_merged_upsample (j_decompress_ptr cinfo,
cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
cblue = Cbbtab[cb];
y = GETJSAMPLE(*inptr0);
- outptr[RGB_RED] = range_limit[y + cred];
+ outptr[RGB_RED] = range_limit[y + cred];
outptr[RGB_GREEN] = range_limit[y + cgreen];
- outptr[RGB_BLUE] = range_limit[y + cblue];
+ outptr[RGB_BLUE] = range_limit[y + cblue];
+ }
+}
+
+
+#ifdef ANDROID_RGB
+METHODDEF(void)
+h2v1_merged_upsample_565 (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+ JSAMPARRAY output_buf)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ register int y, cred, cgreen, cblue;
+ int cb, cr;
+ register JSAMPROW outptr;
+ JSAMPROW inptr0, inptr1, inptr2;
+ JDIMENSION col;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ int * Crrtab = upsample->Cr_r_tab;
+ int * Cbbtab = upsample->Cb_b_tab;
+ INT32 * Crgtab = upsample->Cr_g_tab;
+ INT32 * Cbgtab = upsample->Cb_g_tab;
+ unsigned int r, g, b;
+ INT32 rgb;
+ SHIFT_TEMPS
+
+ inptr0 = input_buf[0][in_row_group_ctr];
+ inptr1 = input_buf[1][in_row_group_ctr];
+ inptr2 = input_buf[2][in_row_group_ctr];
+ outptr = output_buf[0];
+ /* Loop for each pair of output pixels */
+ for (col = cinfo->output_width >> 1; col > 0; col--) {
+ /* Do the chroma part of the calculation */
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ /* Fetch 2 Y values and emit 2 pixels */
+ y = GETJSAMPLE(*inptr0++);
+ r = range_limit[y + cred];
+ g = range_limit[y + cgreen];
+ b = range_limit[y + cblue];
+ rgb = PACK_SHORT_565(r,g,b);
+ y = GETJSAMPLE(*inptr0++);
+ r = range_limit[y + cred];
+ g = range_limit[y + cgreen];
+ b = range_limit[y + cblue];
+ rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r,g,b));
+ WRITE_TWO_PIXELS(outptr, rgb);
+ outptr += 4;
+ }
+ /* If image width is odd, do the last output column separately */
+ if (cinfo->output_width & 1) {
+ cb = GETJSAMPLE(*inptr1);
+ cr = GETJSAMPLE(*inptr2);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ y = GETJSAMPLE(*inptr0);
+ r = range_limit[y + cred];
+ g = range_limit[y + cgreen];
+ b = range_limit[y + cblue];
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr = rgb;
}
}
+METHODDEF(void)
+h2v1_merged_upsample_565D (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+ JSAMPARRAY output_buf)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ register int y, cred, cgreen, cblue;
+ int cb, cr;
+ register JSAMPROW outptr;
+ JSAMPROW inptr0, inptr1, inptr2;
+ JDIMENSION col;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ int * Crrtab = upsample->Cr_r_tab;
+ int * Cbbtab = upsample->Cb_b_tab;
+ INT32 * Crgtab = upsample->Cr_g_tab;
+ INT32 * Cbgtab = upsample->Cb_g_tab;
+ JDIMENSION col_index = 0;
+ INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
+ unsigned int r, g, b;
+ INT32 rgb;
+ SHIFT_TEMPS
+
+ inptr0 = input_buf[0][in_row_group_ctr];
+ inptr1 = input_buf[1][in_row_group_ctr];
+ inptr2 = input_buf[2][in_row_group_ctr];
+ outptr = output_buf[0];
+ /* Loop for each pair of output pixels */
+ for (col = cinfo->output_width >> 1; col > 0; col--) {
+ /* Do the chroma part of the calculation */
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ /* Fetch 2 Y values and emit 2 pixels */
+ y = GETJSAMPLE(*inptr0++);
+ r = range_limit[DITHER_565_R(y + cred, d0)];
+ g = range_limit[DITHER_565_G(y + cgreen, d0)];
+ b = range_limit[DITHER_565_B(y + cblue, d0)];
+ d0 = DITHER_ROTATE(d0);
+ rgb = PACK_SHORT_565(r,g,b);
+ y = GETJSAMPLE(*inptr0++);
+ r = range_limit[DITHER_565_R(y + cred, d0)];
+ g = range_limit[DITHER_565_G(y + cgreen, d0)];
+ b = range_limit[DITHER_565_B(y + cblue, d0)];
+ d0 = DITHER_ROTATE(d0);
+ rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r,g,b));
+ WRITE_TWO_PIXELS(outptr, rgb);
+ outptr += 4;
+ }
+ /* If image width is odd, do the last output column separately */
+ if (cinfo->output_width & 1) {
+ cb = GETJSAMPLE(*inptr1);
+ cr = GETJSAMPLE(*inptr2);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ y = GETJSAMPLE(*inptr0);
+ r = range_limit[DITHER_565_R(y + cred, d0)];
+ g = range_limit[DITHER_565_G(y + cgreen, d0)];
+ b = range_limit[DITHER_565_B(y + cblue, d0)];
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr = rgb;
+ }
+}
+
+
+#endif
+
/*
* Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical.
*/
@@ -319,24 +478,24 @@ h2v2_merged_upsample (j_decompress_ptr cinfo,
cblue = Cbbtab[cb];
/* Fetch 4 Y values and emit 4 pixels */
y = GETJSAMPLE(*inptr00++);
- outptr0[RGB_RED] = range_limit[y + cred];
+ outptr0[RGB_RED] = range_limit[y + cred];
outptr0[RGB_GREEN] = range_limit[y + cgreen];
- outptr0[RGB_BLUE] = range_limit[y + cblue];
+ outptr0[RGB_BLUE] = range_limit[y + cblue];
outptr0 += RGB_PIXELSIZE;
y = GETJSAMPLE(*inptr00++);
- outptr0[RGB_RED] = range_limit[y + cred];
+ outptr0[RGB_RED] = range_limit[y + cred];
outptr0[RGB_GREEN] = range_limit[y + cgreen];
- outptr0[RGB_BLUE] = range_limit[y + cblue];
+ outptr0[RGB_BLUE] = range_limit[y + cblue];
outptr0 += RGB_PIXELSIZE;
y = GETJSAMPLE(*inptr01++);
- outptr1[RGB_RED] = range_limit[y + cred];
+ outptr1[RGB_RED] = range_limit[y + cred];
outptr1[RGB_GREEN] = range_limit[y + cgreen];
- outptr1[RGB_BLUE] = range_limit[y + cblue];
+ outptr1[RGB_BLUE] = range_limit[y + cblue];
outptr1 += RGB_PIXELSIZE;
y = GETJSAMPLE(*inptr01++);
- outptr1[RGB_RED] = range_limit[y + cred];
+ outptr1[RGB_RED] = range_limit[y + cred];
outptr1[RGB_GREEN] = range_limit[y + cgreen];
- outptr1[RGB_BLUE] = range_limit[y + cblue];
+ outptr1[RGB_BLUE] = range_limit[y + cblue];
outptr1 += RGB_PIXELSIZE;
}
/* If image width is odd, do the last output column separately */
@@ -347,17 +506,197 @@ h2v2_merged_upsample (j_decompress_ptr cinfo,
cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
cblue = Cbbtab[cb];
y = GETJSAMPLE(*inptr00);
- outptr0[RGB_RED] = range_limit[y + cred];
+ outptr0[RGB_RED] = range_limit[y + cred];
outptr0[RGB_GREEN] = range_limit[y + cgreen];
- outptr0[RGB_BLUE] = range_limit[y + cblue];
+ outptr0[RGB_BLUE] = range_limit[y + cblue];
y = GETJSAMPLE(*inptr01);
- outptr1[RGB_RED] = range_limit[y + cred];
+ outptr1[RGB_RED] = range_limit[y + cred];
outptr1[RGB_GREEN] = range_limit[y + cgreen];
- outptr1[RGB_BLUE] = range_limit[y + cblue];
+ outptr1[RGB_BLUE] = range_limit[y + cblue];
+ }
+}
+
+
+#ifdef ANDROID_RGB
+
+METHODDEF(void)
+h2v2_merged_upsample_565 (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+ JSAMPARRAY output_buf)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ register int y, cred, cgreen, cblue;
+ int cb, cr;
+ register JSAMPROW outptr0, outptr1;
+ JSAMPROW inptr00, inptr01, inptr1, inptr2;
+ JDIMENSION col;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ int * Crrtab = upsample->Cr_r_tab;
+ int * Cbbtab = upsample->Cb_b_tab;
+ INT32 * Crgtab = upsample->Cr_g_tab;
+ INT32 * Cbgtab = upsample->Cb_g_tab;
+ unsigned int r, g, b;
+ INT32 rgb;
+ SHIFT_TEMPS
+
+ inptr00 = input_buf[0][in_row_group_ctr*2];
+ inptr01 = input_buf[0][in_row_group_ctr*2 + 1];
+ inptr1 = input_buf[1][in_row_group_ctr];
+ inptr2 = input_buf[2][in_row_group_ctr];
+ outptr0 = output_buf[0];
+ outptr1 = output_buf[1];
+ /* Loop for each group of output pixels */
+ for (col = cinfo->output_width >> 1; col > 0; col--) {
+ /* Do the chroma part of the calculation */
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ /* Fetch 4 Y values and emit 4 pixels */
+ y = GETJSAMPLE(*inptr00++);
+ r = range_limit[y + cred];
+ g = range_limit[y + cgreen];
+ b = range_limit[y + cblue];
+ rgb = PACK_SHORT_565(r,g,b);
+ y = GETJSAMPLE(*inptr00++);
+ r = range_limit[y + cred];
+ g = range_limit[y + cgreen];
+ b = range_limit[y + cblue];
+ rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r,g,b));
+ WRITE_TWO_PIXELS(outptr0, rgb);
+ outptr0 += 4;
+ y = GETJSAMPLE(*inptr01++);
+ r = range_limit[y + cred];
+ g = range_limit[y + cgreen];
+ b = range_limit[y + cblue];
+ rgb = PACK_SHORT_565(r,g,b);
+ y = GETJSAMPLE(*inptr01++);
+ r = range_limit[y + cred];
+ g = range_limit[y + cgreen];
+ b = range_limit[y + cblue];
+ rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r,g,b));
+ WRITE_TWO_PIXELS(outptr1, rgb);
+ outptr1 += 4;
+ }
+ /* If image width is odd, do the last output column separately */
+ if (cinfo->output_width & 1) {
+ cb = GETJSAMPLE(*inptr1);
+ cr = GETJSAMPLE(*inptr2);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ y = GETJSAMPLE(*inptr00);
+ r = range_limit[y + cred];
+ g = range_limit[y + cgreen];
+ b = range_limit[y + cblue];
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr0 = rgb;
+ y = GETJSAMPLE(*inptr01);
+ r = range_limit[y + cred];
+ g = range_limit[y + cgreen];
+ b = range_limit[y + cblue];
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr1 = rgb;
}
}
+
+METHODDEF(void)
+h2v2_merged_upsample_565D (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+ JSAMPARRAY output_buf)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ register int y, cred, cgreen, cblue;
+ int cb, cr;
+ register JSAMPROW outptr0, outptr1;
+ JSAMPROW inptr00, inptr01, inptr1, inptr2;
+ JDIMENSION col;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ int * Crrtab = upsample->Cr_r_tab;
+ int * Cbbtab = upsample->Cb_b_tab;
+ INT32 * Crgtab = upsample->Cr_g_tab;
+ INT32 * Cbgtab = upsample->Cb_g_tab;
+ JDIMENSION col_index = 0;
+ INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
+ INT32 d1 = dither_matrix[(cinfo->output_scanline+1) & DITHER_MASK];
+ unsigned int r, g, b;
+ INT32 rgb;
+ SHIFT_TEMPS
+
+ inptr00 = input_buf[0][in_row_group_ctr*2];
+ inptr01 = input_buf[0][in_row_group_ctr*2 + 1];
+ inptr1 = input_buf[1][in_row_group_ctr];
+ inptr2 = input_buf[2][in_row_group_ctr];
+ outptr0 = output_buf[0];
+ outptr1 = output_buf[1];
+ /* Loop for each group of output pixels */
+ for (col = cinfo->output_width >> 1; col > 0; col--) {
+
+ /* Do the chroma part of the calculation */
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ /* Fetch 4 Y values and emit 4 pixels */
+ y = GETJSAMPLE(*inptr00++);
+ r = range_limit[DITHER_565_R(y + cred, d0)];
+ g = range_limit[DITHER_565_G(y + cgreen, d0)];
+ b = range_limit[DITHER_565_B(y + cblue, d0)];
+ d0 = DITHER_ROTATE(d0);
+ rgb = PACK_SHORT_565(r,g,b);
+ y = GETJSAMPLE(*inptr00++);
+ r = range_limit[DITHER_565_R(y + cred, d1)];
+ g = range_limit[DITHER_565_G(y + cgreen, d1)];
+ b = range_limit[DITHER_565_B(y + cblue, d1)];
+ d1 = DITHER_ROTATE(d1);
+ rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r,g,b));
+ WRITE_TWO_PIXELS(outptr0, rgb);
+ outptr0 += 4;
+ y = GETJSAMPLE(*inptr01++);
+ r = range_limit[DITHER_565_R(y + cred, d0)];
+ g = range_limit[DITHER_565_G(y + cgreen, d0)];
+ b = range_limit[DITHER_565_B(y + cblue, d0)];
+ d0 = DITHER_ROTATE(d0);
+ rgb = PACK_SHORT_565(r,g,b);
+ y = GETJSAMPLE(*inptr01++);
+ r = range_limit[DITHER_565_R(y + cred, d1)];
+ g = range_limit[DITHER_565_G(y + cgreen, d1)];
+ b = range_limit[DITHER_565_B(y + cblue, d1)];
+ d1 = DITHER_ROTATE(d1);
+ rgb = PACK_TWO_PIXELS(rgb, PACK_SHORT_565(r,g,b));
+ WRITE_TWO_PIXELS(outptr1, rgb);
+ outptr1 += 4;
+ }
+ /* If image width is odd, do the last output column separately */
+ if (cinfo->output_width & 1) {
+ cb = GETJSAMPLE(*inptr1);
+ cr = GETJSAMPLE(*inptr2);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ y = GETJSAMPLE(*inptr00);
+ r = range_limit[DITHER_565_R(y + cred, d0)];
+ g = range_limit[DITHER_565_G(y + cgreen, d0)];
+ b = range_limit[DITHER_565_B(y + cblue, d0)];
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr0 = rgb;
+ y = GETJSAMPLE(*inptr01);
+ r = range_limit[DITHER_565_R(y + cred, d1)];
+ g = range_limit[DITHER_565_G(y + cgreen, d1)];
+ b = range_limit[DITHER_565_B(y + cblue, d1)];
+ rgb = PACK_SHORT_565(r,g,b);
+ *(INT16*)outptr1 = rgb;
+ }
+}
+
+#endif
+
/*
* Module initialization routine for merged upsampling/color conversion.
*
@@ -379,10 +718,19 @@ jinit_merged_upsampler (j_decompress_ptr cinfo)
upsample->pub.need_context_rows = FALSE;
upsample->out_row_width = cinfo->output_width * cinfo->out_color_components;
-
+
if (cinfo->max_v_samp_factor == 2) {
upsample->pub.upsample = merged_2v_upsample;
upsample->upmethod = h2v2_merged_upsample;
+#ifdef ANDROID_RGB
+ if (cinfo->out_color_space == JCS_RGB_565) {
+ if (cinfo->dither_mode == JDITHER_NONE) {
+ upsample->upmethod = h2v2_merged_upsample_565;
+ } else {
+ upsample->upmethod = h2v2_merged_upsample_565D;
+ }
+ }
+#endif
/* Allocate a spare row buffer */
upsample->spare_row = (JSAMPROW)
(*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
@@ -390,6 +738,15 @@ jinit_merged_upsampler (j_decompress_ptr cinfo)
} else {
upsample->pub.upsample = merged_1v_upsample;
upsample->upmethod = h2v1_merged_upsample;
+#ifdef ANDROID_RGB
+ if (cinfo->out_color_space == JCS_RGB_565) {
+ if (cinfo->dither_mode == JDITHER_NONE) {
+ upsample->upmethod = h2v1_merged_upsample_565;
+ } else {
+ upsample->upmethod = h2v1_merged_upsample_565D;
+ }
+ }
+#endif
/* No spare row needed */
upsample->spare_row = NULL;
}