jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor, boolean force_baseline) { static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = { 16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, 14, 13, 16, 24, 40, 57, 69, 56, 14, 17, 22, 29, 51, 87, 80, 62, 18, 22, 37, 56, 68, 109, 103, 77, 24, 35, 55, 64, 81, 104, 113, 92, 49, 64, 78, 87, 103, 121, 120, 101, 72, 92, 95, 98, 112, 100, 103, 99 }; static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = { 17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99, 24, 26, 56, 99, 99, 99, 99, 99, 47, 66, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99 }; jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl, scale_factor, force_baseline); jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl, scale_factor, force_baseline); }
jpeg_default_qtables (j_compress_ptr cinfo, boolean force_baseline) /* Set or change the 'quality' (quantization) setting, using default tables * and straight percentage-scaling quality scales. * This entry point allows different scalings for luminance and chrominance. */ { /* Set up two quantization tables using the specified scaling */ jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl, cinfo->q_scale_factor[0], force_baseline); jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl, cinfo->q_scale_factor[1], force_baseline); }
jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor, boolean force_baseline) /* Set or change the 'quality' (quantization) setting, using default tables * and a straight percentage-scaling quality scale. In most cases it's better * to use jpeg_set_quality (below); this entry point is provided for * applications that insist on a linear percentage scaling. */ { /* Set up two quantization tables using the specified scaling */ jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl, scale_factor, force_baseline); jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl, scale_factor, force_baseline); }
void pxl_set_jpeg_custom_params(i_job_info_t *job_info) { int i,j; /* the driver uses 1 for auto setting, 6 for max compression */ int qfactor = job_info->qfactor; for(i = 0; i < 3; i++) { jpeg_add_quant_table(job_info->cinfo, i, qtable, 0, FALSE); for(j =0; j < 64; j++) { job_info->cinfo->quant_tbl_ptrs[i]->quantval[j] = qtable[j] * qfactor ; } job_info->cinfo->quant_tbl_ptrs[i]->quantval[0] = qtable[0]; job_info->cinfo->quant_tbl_ptrs[i]->quantval[1] = qtable[1] * (1 + (qfactor - 1) * 0.25) + 0.5; job_info->cinfo->quant_tbl_ptrs[i]->quantval[8] = qtable[8] * (1 + (qfactor - 1) * 0.25) + 0.5; job_info->cinfo->quant_tbl_ptrs[i]->quantval[2] = qtable[2] * (1 + (qfactor - 1) * 0.5) + 0.5; job_info->cinfo->quant_tbl_ptrs[i]->quantval[9] = qtable[9] * (1 + (qfactor - 1) * 0.5) + 0.5; job_info->cinfo->quant_tbl_ptrs[i]->quantval[16] = qtable[16] * (1 + (qfactor - 1) * 0.5) + 0.5; } job_info->cinfo->comp_info[0].h_samp_factor = 1; job_info->cinfo->comp_info[0].v_samp_factor = 1; return; }
GLOBAL void jpeg_set_linear_quality(j_compress_ptr cinfo, int scale_factor, boolean force_baseline) { /* Set or change the 'quality' (quantization) setting, using default tables * and a straight percentage-scaling quality scale. In most cases it's better * to use jpeg_set_quality (below); this entry point is provided for * applications that insist on a linear percentage scaling. */ /* This is the sample quantization table given in the JPEG spec section K.1, * but expressed in zigzag order (as are all of our quant. tables). * The spec says that the values given produce "good" quality, and * when divided by 2, "very good" quality. */ static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = { 16, 11, 12, 14, 12, 10, 16, 14, 13, 14, 18, 17, 16, 19, 24, 40, 26, 24, 22, 22, 24, 49, 35, 37, 29, 40, 58, 51, 61, 60, 57, 51, 56, 55, 64, 72, 92, 78, 64, 68, 87, 69, 55, 56, 80, 109, 81, 87, 95, 98, 103, 104, 103, 62, 77, 113, 121, 112, 100, 120, 92, 101, 103, 99 }; static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = { 17, 18, 18, 24, 21, 24, 47, 26, 26, 47, 99, 66, 56, 66, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99 }; /* Set up two quantization tables using the specified scaling */ jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl, scale_factor, force_baseline); jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl, scale_factor, force_baseline); }
read_quant_tables (j_compress_ptr cinfo, char * filename, boolean force_baseline) /* Read a set of quantization tables from the specified file. * The file is plain ASCII text: decimal numbers with whitespace between. * Comments preceded by '#' may be included in the file. * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values. * The tables are implicitly numbered 0,1,etc. * NOTE: does not affect the qslots mapping, which will default to selecting * table 0 for luminance (or primary) components, 1 for chrominance components. * You must use -qslots if you want a different component->table mapping. */ { FILE * fp; int tblno, i, termchar; long val; unsigned int table[DCTSIZE2]; if ((fp = fopen(filename, "r")) == NULL) { fprintf(stderr, "Can't open table file %s\n", filename); return FALSE; } tblno = 0; while (read_text_integer(fp, &val, &termchar)) { /* read 1st element of table */ if (tblno >= NUM_QUANT_TBLS) { fprintf(stderr, "Too many tables in file %s\n", filename); fclose(fp); return FALSE; } table[0] = (unsigned int) val; for (i = 1; i < DCTSIZE2; i++) { if (! read_text_integer(fp, &val, &termchar)) { fprintf(stderr, "Invalid table data in file %s\n", filename); fclose(fp); return FALSE; } table[i] = (unsigned int) val; } jpeg_add_quant_table(cinfo, tblno, table, cinfo->q_scale_factor[tblno], force_baseline); tblno++; } if (termchar != EOF) { fprintf(stderr, "Non-numeric data in file %s\n", filename); fclose(fp); return FALSE; } fclose(fp); return TRUE; }
gboolean save_image (const gchar *filename, gint32 image_ID, gint32 drawable_ID, gint32 orig_image_ID, gboolean preview, GError **error) { GimpImageType drawable_type; GeglBuffer *buffer = NULL; const Babl *format; GimpParasite *parasite; static struct jpeg_compress_struct cinfo; static struct my_error_mgr jerr; JpegSubsampling subsampling; FILE * volatile outfile; guchar *data; guchar *src; gboolean has_alpha; gint rowstride, yend; drawable_type = gimp_drawable_type (drawable_ID); buffer = gimp_drawable_get_buffer (drawable_ID); if (! preview) gimp_progress_init_printf (_("Saving '%s'"), gimp_filename_to_utf8 (filename)); /* Step 1: allocate and initialize JPEG compression object */ /* We have to set up the error handler first, in case the initialization * step fails. (Unlikely, but it could happen if you are out of memory.) * This routine fills in the contents of struct jerr, and returns jerr's * address which we place into the link field in cinfo. */ cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; outfile = NULL; /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp (jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ jpeg_destroy_compress (&cinfo); if (outfile) fclose (outfile); if (buffer) g_object_unref (buffer); return FALSE; } /* Now we can initialize the JPEG compression object. */ jpeg_create_compress (&cinfo); /* Step 2: specify data destination (eg, a file) */ /* Note: steps 2 and 3 can be done in either order. */ /* Here we use the library-supplied code to send compressed data to a * stdio stream. You can also write your own code to do something else. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to write binary files. */ if ((outfile = g_fopen (filename, "wb")) == NULL) { g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), _("Could not open '%s' for writing: %s"), gimp_filename_to_utf8 (filename), g_strerror (errno)); return FALSE; } jpeg_stdio_dest (&cinfo, outfile); /* Get the input image and a pointer to its data. */ switch (drawable_type) { case GIMP_RGB_IMAGE: /* # of color components per pixel */ cinfo.input_components = 3; has_alpha = FALSE; format = babl_format ("R'G'B' u8"); break; case GIMP_GRAY_IMAGE: /* # of color components per pixel */ cinfo.input_components = 1; has_alpha = FALSE; format = babl_format ("Y' u8"); break; case GIMP_RGBA_IMAGE: /* # of color components per pixel (minus the GIMP alpha channel) */ cinfo.input_components = 4 - 1; has_alpha = TRUE; format = babl_format ("R'G'B' u8"); break; case GIMP_GRAYA_IMAGE: /* # of color components per pixel (minus the GIMP alpha channel) */ cinfo.input_components = 2 - 1; has_alpha = TRUE; format = babl_format ("Y' u8"); break; case GIMP_INDEXED_IMAGE: default: return FALSE; } /* Step 3: set parameters for compression */ /* First we supply a description of the input image. * Four fields of the cinfo struct must be filled in: */ /* image width and height, in pixels */ cinfo.image_width = gegl_buffer_get_width (buffer); cinfo.image_height = gegl_buffer_get_height (buffer); /* colorspace of input image */ cinfo.in_color_space = (drawable_type == GIMP_RGB_IMAGE || drawable_type == GIMP_RGBA_IMAGE) ? JCS_RGB : JCS_GRAYSCALE; /* Now use the library's routine to set default compression parameters. * (You must set at least cinfo.in_color_space before calling this, * since the defaults depend on the source color space.) */ jpeg_set_defaults (&cinfo); jpeg_set_quality (&cinfo, (gint) (jsvals.quality + 0.5), jsvals.baseline); if (jsvals.use_orig_quality && num_quant_tables > 0) { guint **quant_tables; gint t; /* override tables generated by jpeg_set_quality() with custom tables */ quant_tables = jpeg_restore_original_tables (image_ID, num_quant_tables); if (quant_tables) { for (t = 0; t < num_quant_tables; t++) { jpeg_add_quant_table (&cinfo, t, quant_tables[t], 100, jsvals.baseline); g_free (quant_tables[t]); } g_free (quant_tables); } } if (arithc_supported) { cinfo.arith_code = jsvals.arithmetic_coding; if (!jsvals.arithmetic_coding) cinfo.optimize_coding = jsvals.optimize; } else cinfo.optimize_coding = jsvals.optimize; subsampling = (gimp_drawable_is_rgb (drawable_ID) ? jsvals.subsmp : JPEG_SUBSAMPLING_1x1_1x1_1x1); /* smoothing is not supported with nonstandard sampling ratios */ if (subsampling != JPEG_SUBSAMPLING_2x1_1x1_1x1 && subsampling != JPEG_SUBSAMPLING_1x2_1x1_1x1) { cinfo.smoothing_factor = (gint) (jsvals.smoothing * 100); } if (jsvals.progressive) { jpeg_simple_progression (&cinfo); } switch (subsampling) { case JPEG_SUBSAMPLING_2x2_1x1_1x1: default: cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 2; cinfo.comp_info[1].h_samp_factor = 1; cinfo.comp_info[1].v_samp_factor = 1; cinfo.comp_info[2].h_samp_factor = 1; cinfo.comp_info[2].v_samp_factor = 1; break; case JPEG_SUBSAMPLING_2x1_1x1_1x1: cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 1; cinfo.comp_info[1].h_samp_factor = 1; cinfo.comp_info[1].v_samp_factor = 1; cinfo.comp_info[2].h_samp_factor = 1; cinfo.comp_info[2].v_samp_factor = 1; break; case JPEG_SUBSAMPLING_1x1_1x1_1x1: cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 1; cinfo.comp_info[1].h_samp_factor = 1; cinfo.comp_info[1].v_samp_factor = 1; cinfo.comp_info[2].h_samp_factor = 1; cinfo.comp_info[2].v_samp_factor = 1; break; case JPEG_SUBSAMPLING_1x2_1x1_1x1: cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 2; cinfo.comp_info[1].h_samp_factor = 1; cinfo.comp_info[1].v_samp_factor = 1; cinfo.comp_info[2].h_samp_factor = 1; cinfo.comp_info[2].v_samp_factor = 1; break; } cinfo.restart_interval = 0; cinfo.restart_in_rows = jsvals.restart; switch (jsvals.dct) { case 0: default: cinfo.dct_method = JDCT_ISLOW; break; case 1: cinfo.dct_method = JDCT_IFAST; break; case 2: cinfo.dct_method = JDCT_FLOAT; break; } { gdouble xresolution; gdouble yresolution; gimp_image_get_resolution (orig_image_ID, &xresolution, &yresolution); if (xresolution > 1e-5 && yresolution > 1e-5) { gdouble factor; factor = gimp_unit_get_factor (gimp_image_get_unit (orig_image_ID)); if (factor == 2.54 /* cm */ || factor == 25.4 /* mm */) { cinfo.density_unit = 2; /* dots per cm */ xresolution /= 2.54; yresolution /= 2.54; } else { cinfo.density_unit = 1; /* dots per inch */ } cinfo.X_density = xresolution; cinfo.Y_density = yresolution; } } /* Step 4: Start compressor */ /* TRUE ensures that we will write a complete interchange-JPEG file. * Pass TRUE unless you are very sure of what you're doing. */ jpeg_start_compress (&cinfo, TRUE); /* Step 4.1: Write the comment out - pw */ if (image_comment && *image_comment) { #ifdef GIMP_UNSTABLE g_print ("jpeg-save: saving image comment (%d bytes)\n", (int) strlen (image_comment)); #endif jpeg_write_marker (&cinfo, JPEG_COM, (guchar *) image_comment, strlen (image_comment)); } /* Step 4.2: store the color profile if there is one */ parasite = gimp_image_get_parasite (orig_image_ID, "icc-profile"); if (parasite) { jpeg_icc_write_profile (&cinfo, gimp_parasite_data (parasite), gimp_parasite_data_size (parasite)); gimp_parasite_free (parasite); } /* Step 5: while (scan lines remain to be written) */ /* jpeg_write_scanlines(...); */ /* Here we use the library's state variable cinfo.next_scanline as the * loop counter, so that we don't have to keep track ourselves. * To keep things simple, we pass one scanline per call; you can pass * more if you wish, though. */ /* JSAMPLEs per row in image_buffer */ rowstride = cinfo.input_components * cinfo.image_width; data = g_new (guchar, rowstride * gimp_tile_height ()); /* fault if cinfo.next_scanline isn't initially a multiple of * gimp_tile_height */ src = NULL; /* * sg - if we preview, we want this to happen in the background -- do * not duplicate code in the future; for now, it's OK */ if (preview) { PreviewPersistent *pp = g_new (PreviewPersistent, 1); /* pass all the information we need */ pp->cinfo = cinfo; pp->tile_height = gimp_tile_height(); pp->data = data; pp->outfile = outfile; pp->has_alpha = has_alpha; pp->rowstride = rowstride; pp->data = data; pp->buffer = buffer; pp->format = format; pp->src = NULL; pp->file_name = filename; pp->abort_me = FALSE; g_warn_if_fail (prev_p == NULL); prev_p = pp; pp->cinfo.err = jpeg_std_error(&(pp->jerr)); pp->jerr.error_exit = background_error_exit; gtk_label_set_text (GTK_LABEL (preview_size), _("Calculating file size...")); pp->source_id = g_idle_add ((GSourceFunc) background_jpeg_save, pp); /* background_jpeg_save() will cleanup as needed */ return TRUE; } while (cinfo.next_scanline < cinfo.image_height) { if ((cinfo.next_scanline % gimp_tile_height ()) == 0) { yend = cinfo.next_scanline + gimp_tile_height (); yend = MIN (yend, cinfo.image_height); gegl_buffer_get (buffer, GEGL_RECTANGLE (0, cinfo.next_scanline, cinfo.image_width, (yend - cinfo.next_scanline)), 1.0, format, data, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); src = data; } jpeg_write_scanlines (&cinfo, (JSAMPARRAY) &src, 1); src += rowstride; if ((cinfo.next_scanline % 32) == 0) gimp_progress_update ((gdouble) cinfo.next_scanline / (gdouble) cinfo.image_height); } /* Step 6: Finish compression */ jpeg_finish_compress (&cinfo); /* After finish_compress, we can close the output file. */ fclose (outfile); /* Step 7: release JPEG compression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_compress (&cinfo); /* free the temporary buffer */ g_free (data); /* And we're done! */ gimp_progress_update (1.0); g_object_unref (buffer); return TRUE; }
int ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) { JPEGENCODERSTATE* context = (JPEGENCODERSTATE*) state->context; int ok; if (setjmp(context->error.setjmp_buffer)) { /* JPEG error handler */ jpeg_destroy_compress(&context->cinfo); state->errcode = IMAGING_CODEC_BROKEN; return -1; } if (!state->state) { /* Setup compression context (very similar to the decoder) */ context->cinfo.err = jpeg_std_error(&context->error.pub); context->error.pub.error_exit = error; jpeg_create_compress(&context->cinfo); jpeg_buffer_dest(&context->cinfo, &context->destination); context->extra_offset = 0; /* Ready to encode */ state->state = 1; } /* Load the destination buffer */ context->destination.pub.next_output_byte = buf; context->destination.pub.free_in_buffer = bytes; switch (state->state) { case 1: context->cinfo.image_width = state->xsize; context->cinfo.image_height = state->ysize; switch (state->bits) { case 8: context->cinfo.input_components = 1; context->cinfo.in_color_space = JCS_GRAYSCALE; break; case 24: context->cinfo.input_components = 3; if (strcmp(im->mode, "YCbCr") == 0) context->cinfo.in_color_space = JCS_YCbCr; else context->cinfo.in_color_space = JCS_RGB; break; case 32: context->cinfo.input_components = 4; context->cinfo.in_color_space = JCS_CMYK; break; default: state->errcode = IMAGING_CODEC_CONFIG; return -1; } /* Compressor configuration */ jpeg_set_defaults(&context->cinfo); /* Use custom quantization tables */ if (context->qtables) { int i; int quality = 100; if (context->quality > 0) { quality = context->quality; } for (i = 0; i < sizeof(context->qtables)/sizeof(unsigned int); i++) { // TODO: Should add support for none baseline jpeg_add_quant_table(&context->cinfo, i, context->qtables[i], quality, TRUE); } } else if (context->quality > 0) { jpeg_set_quality(&context->cinfo, context->quality, 1); } /* Set subsampling options */ switch (context->subsampling) { case 0: /* 1x1 1x1 1x1 (4:4:4) : None */ { context->cinfo.comp_info[0].h_samp_factor = 1; context->cinfo.comp_info[0].v_samp_factor = 1; context->cinfo.comp_info[1].h_samp_factor = 1; context->cinfo.comp_info[1].v_samp_factor = 1; context->cinfo.comp_info[2].h_samp_factor = 1; context->cinfo.comp_info[2].v_samp_factor = 1; break; } case 1: /* 2x1, 1x1, 1x1 (4:2:2) : Medium */ { context->cinfo.comp_info[0].h_samp_factor = 2; context->cinfo.comp_info[0].v_samp_factor = 1; context->cinfo.comp_info[1].h_samp_factor = 1; context->cinfo.comp_info[1].v_samp_factor = 1; context->cinfo.comp_info[2].h_samp_factor = 1; context->cinfo.comp_info[2].v_samp_factor = 1; break; } case 2: /* 2x2, 1x1, 1x1 (4:1:1) : High */ { context->cinfo.comp_info[0].h_samp_factor = 2; context->cinfo.comp_info[0].v_samp_factor = 2; context->cinfo.comp_info[1].h_samp_factor = 1; context->cinfo.comp_info[1].v_samp_factor = 1; context->cinfo.comp_info[2].h_samp_factor = 1; context->cinfo.comp_info[2].v_samp_factor = 1; break; } default: { /* Use the lib's default */ break; } } if (context->progressive) jpeg_simple_progression(&context->cinfo); context->cinfo.smoothing_factor = context->smooth; context->cinfo.optimize_coding = (boolean) context->optimize; if (context->xdpi > 0 && context->ydpi > 0) { context->cinfo.density_unit = 1; /* dots per inch */ context->cinfo.X_density = context->xdpi; context->cinfo.Y_density = context->ydpi; } switch (context->streamtype) { case 1: /* tables only -- not yet implemented */ state->errcode = IMAGING_CODEC_CONFIG; return -1; case 2: /* image only */ jpeg_suppress_tables(&context->cinfo, TRUE); jpeg_start_compress(&context->cinfo, FALSE); /* suppress extra section */ context->extra_offset = context->extra_size; //add exif header if (context->rawExifLen > 0) jpeg_write_marker(&context->cinfo, JPEG_APP0+1, (unsigned char*)context->rawExif, context->rawExifLen); break; default: /* interchange stream */ jpeg_start_compress(&context->cinfo, TRUE); //add exif header if (context->rawExifLen > 0) jpeg_write_marker(&context->cinfo, JPEG_APP0+1, (unsigned char*)context->rawExif, context->rawExifLen); break; } state->state++; /* fall through */ case 2: if (context->extra) { /* copy extra buffer to output buffer */ unsigned int n = context->extra_size - context->extra_offset; if (n > context->destination.pub.free_in_buffer) n = context->destination.pub.free_in_buffer; memcpy(context->destination.pub.next_output_byte, context->extra + context->extra_offset, n); context->destination.pub.next_output_byte += n; context->destination.pub.free_in_buffer -= n; context->extra_offset += n; if (context->extra_offset >= context->extra_size) state->state++; else break; } else state->state++; case 3: ok = 1; while (state->y < state->ysize) { state->shuffle(state->buffer, (UINT8*) im->image[state->y + state->yoff] + state->xoff * im->pixelsize, state->xsize); ok = jpeg_write_scanlines(&context->cinfo, &state->buffer, 1); if (ok != 1) break; state->y++; } if (ok != 1) break; state->state++; /* fall through */ case 4: /* Finish compression */ if (context->destination.pub.free_in_buffer < 100) break; jpeg_finish_compress(&context->cinfo); /* Clean up */ if (context->extra) free(context->extra); jpeg_destroy_compress(&context->cinfo); /* if (jerr.pub.num_warnings) return BROKEN; */ state->errcode = IMAGING_CODEC_END; break; } /* Return number of bytes in output buffer */ return context->destination.pub.next_output_byte - buf; }
void ModeJpeg::jpegCompressForJetReady() { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; jmp_buf setjmp_buffer; // Use the modified Mojave CSC table hp_rgb_ycc_setup (1); compressedsize = 0; memset (compressBuf, 0xFF, m_max_file_size); cinfo.err = jpeg_std_error (&jerr); jerr.error_exit = HPJpeg_error; if (setjmp (setjmp_buffer)) { jpeg_destroy_compress (&cinfo); return; } jpeg_create_compress (&cinfo); cinfo.in_color_space = (m_iColorMode == 0) ? JCS_RGB : JCS_GRAYSCALE; jpeg_set_defaults (&cinfo); cinfo.image_width = m_iRowWidth / 3; cinfo.image_height = m_iBandHeight; cinfo.input_components = (m_iColorMode == 0) ? 3 : 1; cinfo.data_precision = 8; // Create a static quant table here. static unsigned int mojave_quant_table1[64] = { 2,3,4,5,5,5,5,5, 3,6,5,8,5,8,5,8, 4,5,5,5,5,5,5,5, 5,8,5,8,5,8,5,8, 5,5,5,5,5,5,5,5, 5,8,5,8,5,8,5,8, 5,5,5,5,5,5,5,5, 5,8,5,8,5,8,5,8 }; // // JetReady specific Q-Tables will be added here. We do the following: // 1. Add three Q-Tables. // 2. Scale the Q-Table elemets with the given scale factor. // 3. Check to see if any of the element in the table is greater than 255 // reset that elemet to 255. // 5. There is a specific scaling needed to be done to the first 6 // elements in the matrix. This is required to achieve better // compression ratio. // 4. Check to see if any the of the recently modified element is // greater than 255, reset that to 255. // // Please refer to sRGBLaserHostBasedSoftwareERS.doc v9.0 section 5.2.5.3.1.1 // for more details. // // [NOTE] These loop needs to be further optimized. // for (int i = 0; i < 3; i++) { // Adding Q-Table. jpeg_add_quant_table(&cinfo, i, mojave_quant_table1, 0, FALSE ); // // Scaling the Q-Table elements. // Reset the element to 255, if it is greater than 255. // for(int j = 1; j < 64; j++) { cinfo.quant_tbl_ptrs[i]->quantval[j] = (UINT16)((mojave_quant_table1[j] * m_pQTableInfo->qFactor) & 0xFF); } // for (int j = 1; j < 64; j++) // // Special scaling for first 6 elements in the table. // Reset the specially scaled elements 255, if it is greater than 255. // // // 1st component in the table. Unchanged, I need not change anything here. // cinfo.quant_tbl_ptrs[i]->quantval[0] = (UINT16)mojave_quant_table1[0]; // // 2nd and 3rd components in the zig zag order // // The following dTemp is being used to ceil the vales: e.g 28.5 to 29 // double dTemp = mojave_quant_table1[1] * (1 + 0.25 * (m_pQTableInfo->qFactor - 1)) + 0.5; cinfo.quant_tbl_ptrs[i]->quantval[1] = (UINT16)dTemp & 0xFF; dTemp = mojave_quant_table1[8] * (1 + 0.25 * (m_pQTableInfo->qFactor - 1)) + 0.5; cinfo.quant_tbl_ptrs[i]->quantval[8] = (UINT16)dTemp & 0xFF; // // 4th, 5th and 6th components in the zig zag order // dTemp = mojave_quant_table1[16] * (1 + 0.50 * (m_pQTableInfo->qFactor - 1)) + 0.5; cinfo.quant_tbl_ptrs[i]->quantval[16] = (UINT16)dTemp & 0xFF; dTemp = mojave_quant_table1[9] * (1 + 0.50 * (m_pQTableInfo->qFactor - 1)) + 0.5; cinfo.quant_tbl_ptrs[i]->quantval[9] = (UINT16)dTemp & 0xFF; dTemp = mojave_quant_table1[2] * (1 + 0.50 * (m_pQTableInfo->qFactor - 1)) + 0.5; cinfo.quant_tbl_ptrs[i]->quantval[2] = (UINT16)dTemp & 0xFF; } // for (i = 0; i < 3; i++) // Hard code to use sampling mode 4:4:4 cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 1; jpeg_buffer_dest (&cinfo, (JOCTET *) this, (void *) (output_buffer_callback)); int row_width = m_iRowWidth; if (m_iColorMode != 0) { row_width = m_iRowWidth / 3; cinfo.write_JFIF_header = FALSE; cinfo.write_Adobe_marker = FALSE; jpeg_suppress_tables(&cinfo, TRUE); } jpeg_start_compress (&cinfo, TRUE); JSAMPROW pRowArray[1]; BYTE *pScanLine = m_pbyInputBuffer; int i; for (i = 0; i < m_iBandHeight; i++) { pRowArray[0] = (JSAMPROW) pScanLine; jpeg_write_scanlines (&cinfo, pRowArray, 1); pScanLine += (row_width); } jpeg_finish_compress (&cinfo); // Read the quantization table used for this compression if (cinfo.quant_tbl_ptrs[0] != NULL) { // memcpy(m_pQTableInfo->qtable0, cinfo.quant_tbl_ptrs[0]->quantval, QTABLE_SIZE); for (i = 0; i < QTABLE_SIZE; i++) { m_pQTableInfo->qtable0[i] = cinfo.quant_tbl_ptrs[0]->quantval[i]; } } if (cinfo.quant_tbl_ptrs[1] != NULL) { // memcpy(m_pQTableInfo->qtable1, cinfo.quant_tbl_ptrs[1]->quantval, QTABLE_SIZE); for (i = 0; i < QTABLE_SIZE; i++) { m_pQTableInfo->qtable1[i] = cinfo.quant_tbl_ptrs[1]->quantval[i]; } } if (cinfo.quant_tbl_ptrs[2] != NULL) { // memcpy(m_pQTableInfo->qtable2, cinfo.quant_tbl_ptrs[2]->quantval, QTABLE_SIZE); for (i = 0; i < QTABLE_SIZE; i++) { m_pQTableInfo->qtable2[i] = cinfo.quant_tbl_ptrs[2]->quantval[i]; } } jpeg_destroy_compress (&cinfo); if (m_iColorMode != 0) { unsigned int l = 0; while (l < compressedsize) { if (compressBuf[l] == 0xFF && compressBuf[l+1] == 0xDA) break; l++; } if (l != compressedsize) { m_uiGrayscaleOffset = l + 10; } } }
read_quant_tables (j_compress_ptr cinfo, char * filename, int scale_factor, boolean force_baseline) /* Read a set of quantization tables from the specified file. * The file is plain ASCII text: decimal numbers with whitespace between. * Comments preceded by '#' may be included in the file. * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values. * The tables are implicitly numbered 0,1,etc. * NOTE: does not affect the qslots mapping, which will default to selecting * table 0 for luminance (or primary) components, 1 for chrominance components. * You must use -qslots if you want a different component->table mapping. */ { FILE * fp; __boundcheck_metadata_store((void *)(&fp),(void *)((size_t)(&fp)+sizeof(fp)*8-1)); int tblno; __boundcheck_metadata_store((void *)(&tblno),(void *)((size_t)(&tblno)+sizeof(tblno)*8-1)); int i; __boundcheck_metadata_store((void *)(&i),(void *)((size_t)(&i)+sizeof(i)*8-1)); int termchar; __boundcheck_metadata_store((void *)(&termchar),(void *)((size_t)(&termchar)+sizeof(termchar)*8-1)); long val; __boundcheck_metadata_store((void *)(&val),(void *)((size_t)(&val)+sizeof(val)*8-1)); unsigned int table[DCTSIZE2];__boundcheck_metadata_store(&table[0],&table[64-1]); if ((fp = fopen(filename, "r")) == NULL) { fprintf(stderr, "Can't open table file %s\n", filename); return FALSE; } tblno = 0; while (read_text_integer(fp, &val, &termchar)) { /* read 1st element of table */ if (tblno >= NUM_QUANT_TBLS) { fprintf(stderr, "Too many tables in file %s\n", filename); fclose(fp); return FALSE; } table[_RV_insert_check(0,64,102,5,"read_quant_tables",0)] = (unsigned int) val; for (i = 1; i < DCTSIZE2; i++) { if (! read_text_integer(fp, &val, &termchar)) { fprintf(stderr, "Invalid table data in file %s\n", filename); fclose(fp); return FALSE; } table[_RV_insert_check(0,64,109,7,"read_quant_tables",i)] = (unsigned int) val; } jpeg_add_quant_table(cinfo, tblno, table, scale_factor, force_baseline); tblno++; } if (termchar != EOF) { fprintf(stderr, "Non-numeric data in file %s\n", filename); fclose(fp); return FALSE; } fclose(fp); return TRUE; }