h2v2_upsample( j_decompress_ptr cinfo, jpeg_component_info*, JSAMPARRAY input_data, JSAMPARRAY* output_data_ptr) { JSAMPARRAY output_data = *output_data_ptr; JSAMPROW inptr, outptr; JSAMPLE invalue; JSAMPROW outend; int inrow, outrow; inrow = outrow = 0; while (outrow < cinfo->max_v_samp_factor) { inptr = input_data[inrow]; outptr = output_data[outrow]; outend = outptr + cinfo->output_width; while (outptr < outend) { invalue = *inptr++; /* don't need GETJSAMPLE() here */ *outptr++ = invalue; *outptr++ = invalue; } jcopy_sample_rows( output_data, outrow, output_data, outrow + 1, 1, cinfo->output_width); inrow++; outrow += 2; } }
void grayscale_convert (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows) { jcopy_sample_rows(input_buf[0], (int) input_row, output_buf, 0, num_rows, cinfo->output_width); }
expand_bottom_edge (JSAMPARRAY image_data, JDIMENSION num_cols, int input_rows, int output_rows) { register int row; for (row = input_rows; row < output_rows; row++) { jcopy_sample_rows(image_data, input_rows-1, image_data, row, 1, num_cols); } }
fullsize_downsample( j_compress_ptr cinfo, jpeg_component_info *compptr, JSAMPARRAY input_data, JSAMPARRAY output_data ) { /* Copy the data */ jcopy_sample_rows( input_data, 0, output_data, 0, cinfo->max_v_samp_factor, cinfo->image_width ); /* Edge-expand */ expand_right_edge( output_data, cinfo->max_v_samp_factor, cinfo->image_width, compptr->width_in_blocks * compptr->DCT_h_scaled_size ); }
LOCAL void duplicate_row (JSAMPARRAY image_data, long num_cols, int source_row, int num_rows) /* Duplicate the source_row at source_row+1 .. source_row+num_rows */ /* This happens only at the bottom of the image, */ /* so it needn't be super-efficient */ { register int row; for (row = 1; row <= num_rows; row++) { jcopy_sample_rows(image_data, source_row, image_data, source_row + row, 1, num_cols); } }
merged_2v_upsample (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail) /* 2:1 vertical sampling case: may need a spare row. */ { my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; JSAMPROW work_ptrs[2]; JDIMENSION num_rows; /* number of rows returned to caller */ if (upsample->spare_full) { /* If we have a spare row saved from a previous cycle, just return it. */ JDIMENSION size = upsample->out_row_width; if (cinfo->out_color_space == JCS_RGB565) size = cinfo->output_width * 2; jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0, 1, size); num_rows = 1; upsample->spare_full = FALSE; } else { /* Figure number of rows to return to caller. */ num_rows = 2; /* Not more than the distance to the end of the image. */ if (num_rows > upsample->rows_to_go) num_rows = upsample->rows_to_go; /* And not more than what the client can accept: */ out_rows_avail -= *out_row_ctr; if (num_rows > out_rows_avail) num_rows = out_rows_avail; /* Create output pointer array for upsampler. */ work_ptrs[0] = output_buf[*out_row_ctr]; if (num_rows > 1) { work_ptrs[1] = output_buf[*out_row_ctr + 1]; } else { work_ptrs[1] = upsample->spare_row; upsample->spare_full = TRUE; } /* Now do the upsampling. */ (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs); } /* Adjust counts */ *out_row_ctr += num_rows; upsample->rows_to_go -= num_rows; /* When the buffer is emptied, declare this input row group consumed */ if (! upsample->spare_full) (*in_row_group_ctr)++; }
METHODDEF void int_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr, JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr) { my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; JSAMPARRAY output_data = *output_data_ptr; register JSAMPROW inptr, outptr; register JSAMPLE invalue; register int h; JSAMPROW outend; int h_expand, v_expand; int inrow, outrow; h_expand = upsample->h_expand[compptr->component_index]; v_expand = upsample->v_expand[compptr->component_index]; inrow = outrow = 0; while(outrow < cinfo->max_v_samp_factor) { /* Generate one output row with proper horizontal expansion */ inptr = input_data[inrow]; outptr = output_data[outrow]; outend = outptr + cinfo->output_width; while(outptr < outend) { invalue = *inptr++; /* don't need GETJSAMPLE() here */ for(h = h_expand; h > 0; h--) { *outptr++ = invalue; } } /* Generate any additional output rows by duplicating the first one */ if(v_expand > 1) { jcopy_sample_rows(output_data, outrow, output_data, outrow + 1, v_expand - 1, cinfo->output_width); } inrow++; outrow += v_expand; } }
edge_expand (compress_info_ptr cinfo, long input_cols, int input_rows, long output_cols, int output_rows, JSAMPIMAGE image_data) #endif /* XIE_SUPPORTED */ { /* Expand horizontally */ if (input_cols < output_cols) { register JSAMPROW ptr; register JSAMPLE pixval; register long count; register int row; short ci; long numcols = output_cols - input_cols; for (ci = 0; ci < cinfo->num_components; ci++) { for (row = 0; row < input_rows; row++) { ptr = image_data[ci][row] + (input_cols-1); pixval = GETJSAMPLE(*ptr++); for (count = numcols; count > 0; count--) *ptr++ = pixval; } } } /* Expand vertically */ /* This happens only once at the bottom of the image, */ /* so it needn't be super-efficient */ if (input_rows < output_rows) { register int row; short ci; JSAMPARRAY this_component; for (ci = 0; ci < cinfo->num_components; ci++) { this_component = image_data[ci]; for (row = input_rows; row < output_rows; row++) { jcopy_sample_rows(this_component, input_rows-1, this_component, row, 1, output_cols); } } } }
pre_process_context (j_compress_ptr cinfo, JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail, JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, JDIMENSION out_row_groups_avail) { my_prep_ptr prep = (my_prep_ptr) cinfo->prep; int numrows, ci; int buf_height = cinfo->max_v_samp_factor * 3; JDIMENSION inrows; while (*out_row_group_ctr < out_row_groups_avail) { if (*in_row_ctr < in_rows_avail) { /* Do color conversion to fill the conversion buffer. */ inrows = in_rows_avail - *in_row_ctr; numrows = prep->next_buf_stop - prep->next_buf_row; numrows = (int) MIN((JDIMENSION) numrows, inrows); (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr, prep->color_buf, (JDIMENSION) prep->next_buf_row, numrows); /* Pad at top of image, if first time through */ if (prep->rows_to_go == cinfo->image_height) { for (ci = 0; ci < cinfo->num_components; ci++) { int row; for (row = 1; row <= cinfo->max_v_samp_factor; row++) { jcopy_sample_rows(prep->color_buf[ci], 0, prep->color_buf[ci], -row, 1, cinfo->image_width); } } } *in_row_ctr += numrows; prep->next_buf_row += numrows; prep->rows_to_go -= numrows; } else { /* Return for more data, unless we are at the bottom of the image. */ if (prep->rows_to_go != 0) break; /* When at bottom of image, pad to fill the conversion buffer. */ if (prep->next_buf_row < prep->next_buf_stop) { for (ci = 0; ci < cinfo->num_components; ci++) { expand_bottom_edge(prep->color_buf[ci], cinfo->image_width, prep->next_buf_row, prep->next_buf_stop); } prep->next_buf_row = prep->next_buf_stop; } } /* If we've gotten enough data, downsample a row group. */ if (prep->next_buf_row == prep->next_buf_stop) { (*cinfo->downsample->downsample) (cinfo, prep->color_buf, (JDIMENSION) prep->this_row_group, output_buf, *out_row_group_ctr); (*out_row_group_ctr)++; /* Advance pointers with wraparound as necessary. */ prep->this_row_group += cinfo->max_v_samp_factor; if (prep->this_row_group >= buf_height) prep->this_row_group = 0; if (prep->next_buf_row >= buf_height) prep->next_buf_row = 0; prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor; } } }
METHODDEF void pre_process_context( j_compress_ptr cinfo, JSAMPARRAY input_buf, JDIMENSION * in_row_ctr, JDIMENSION in_rows_avail, JSAMPIMAGE output_buf, JDIMENSION * out_row_group_ctr, JDIMENSION out_row_groups_avail ) { my_prep_ptr prep = (my_prep_ptr) cinfo->prep; int numrows, ci; int buf_height = cinfo->max_v_samp_factor * 3; JDIMENSION inrows; jpeg_component_info * compptr; while ( *out_row_group_ctr < out_row_groups_avail ) { if ( *in_row_ctr < in_rows_avail ) { /* Do color conversion to fill the conversion buffer. */ inrows = in_rows_avail - *in_row_ctr; numrows = prep->next_buf_stop - prep->next_buf_row; numrows = (int) MIN( (JDIMENSION) numrows, inrows ); ( *cinfo->cconvert->color_convert )( cinfo, input_buf + *in_row_ctr, prep->color_buf, (JDIMENSION) prep->next_buf_row, numrows ); /* Pad at top of image, if first time through */ if ( prep->rows_to_go == cinfo->image_height ) { for ( ci = 0; ci < cinfo->num_components; ci++ ) { int row; for ( row = 1; row <= cinfo->max_v_samp_factor; row++ ) { jcopy_sample_rows( prep->color_buf[ci], 0, prep->color_buf[ci], -row, 1, cinfo->image_width ); } } } *in_row_ctr += numrows; prep->next_buf_row += numrows; prep->rows_to_go -= numrows; } else { /* Return for more data, unless we are at the bottom of the image. */ if ( prep->rows_to_go != 0 ) { break; } } /* If at bottom of image, pad to fill the conversion buffer. */ if ( ( prep->rows_to_go == 0 ) && ( prep->next_buf_row < prep->next_buf_stop ) ) { for ( ci = 0; ci < cinfo->num_components; ci++ ) { expand_bottom_edge( prep->color_buf[ci], cinfo->image_width, prep->next_buf_row, prep->next_buf_stop ); } prep->next_buf_row = prep->next_buf_stop; } /* If we've gotten enough data, downsample a row group. */ if ( prep->next_buf_row == prep->next_buf_stop ) { ( *cinfo->downsample->downsample )( cinfo, prep->color_buf, (JDIMENSION) prep->this_row_group, output_buf, *out_row_group_ctr ); ( *out_row_group_ctr )++; /* Advance pointers with wraparound as necessary. */ prep->this_row_group += cinfo->max_v_samp_factor; if ( prep->this_row_group >= buf_height ) { prep->this_row_group = 0; } if ( prep->next_buf_row >= buf_height ) { prep->next_buf_row = 0; } prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor; } /* If at bottom of image, pad the output to a full iMCU height. * Note we assume the caller is providing a one-iMCU-height output buffer! */ if ( ( prep->rows_to_go == 0 ) && ( *out_row_group_ctr < out_row_groups_avail ) ) { for ( ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; ci++, compptr++ ) { expand_bottom_edge( output_buf[ci], compptr->width_in_blocks * DCTSIZE, (int) ( *out_row_group_ctr * compptr->v_samp_factor ), (int) ( out_row_groups_avail * compptr->v_samp_factor ) ); } *out_row_group_ctr = out_row_groups_avail; break; /* can exit outer loop without test */ } } }
DLLEXPORT int DLLCALL tjCompress(tjhandle h, unsigned char *srcbuf, int width, int pitch, int height, int ps, unsigned char *dstbuf, unsigned long *size, int jpegsub, int qual, int flags) { int i, retval=0; JSAMPROW *row_pointer=NULL; JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS]; JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS]; JSAMPROW *outbuf[MAX_COMPONENTS]; checkhandle(h); for(i=0; i<MAX_COMPONENTS; i++) { tmpbuf[i]=NULL; _tmpbuf[i]=NULL; tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL; } if(srcbuf==NULL || width<=0 || pitch<0 || height<=0 || dstbuf==NULL || size==NULL || jpegsub<0 || jpegsub>=NUMSUBOPT || qual<0 || qual>100) _throw("Invalid argument in tjCompress()"); if(ps!=3 && ps!=4 && ps!=1) _throw("This compressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale input"); if(!j->initc) _throw("Instance has not been initialized for compression"); if(pitch==0) pitch=width*ps; j->cinfo.image_width = width; j->cinfo.image_height = height; j->cinfo.input_components = ps; if(ps==1) j->cinfo.in_color_space = JCS_GRAYSCALE; #if JCS_EXTENSIONS==1 else j->cinfo.in_color_space = JCS_EXT_RGB; if(ps==3 && (flags&TJ_BGR)) j->cinfo.in_color_space = JCS_EXT_BGR; else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST)) j->cinfo.in_color_space = JCS_EXT_RGBX; else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST)) j->cinfo.in_color_space = JCS_EXT_BGRX; else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST)) j->cinfo.in_color_space = JCS_EXT_XBGR; else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST)) j->cinfo.in_color_space = JCS_EXT_XRGB; #else #error "TurboJPEG requires JPEG colorspace extensions" #endif if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1"); else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); if(setjmp(j->jerr.jb)) { // this will execute if LIBJPEG has an error retval=-1; goto bailout; } jpeg_set_defaults(&j->cinfo); jpeg_set_quality(&j->cinfo, qual, TRUE); if(jpegsub==TJ_GRAYSCALE) jpeg_set_colorspace(&j->cinfo, JCS_GRAYSCALE); else jpeg_set_colorspace(&j->cinfo, JCS_YCbCr); if(qual>=96) j->cinfo.dct_method=JDCT_ISLOW; else j->cinfo.dct_method=JDCT_FASTEST; j->cinfo.comp_info[0].h_samp_factor=hsampfactor[jpegsub]; j->cinfo.comp_info[1].h_samp_factor=1; j->cinfo.comp_info[2].h_samp_factor=1; j->cinfo.comp_info[0].v_samp_factor=vsampfactor[jpegsub]; j->cinfo.comp_info[1].v_samp_factor=1; j->cinfo.comp_info[2].v_samp_factor=1; j->jdms.next_output_byte = dstbuf; j->jdms.free_in_buffer = TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height); jpeg_start_compress(&j->cinfo, TRUE); if(flags&TJ_YUV) { j_compress_ptr cinfo=&j->cinfo; int row; int pw=PAD(width, cinfo->max_h_samp_factor); int ph=PAD(height, cinfo->max_v_samp_factor); int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS]; jpeg_component_info *compptr; JSAMPLE *ptr=dstbuf; unsigned long yuvsize=0; if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL) _throw("Memory allocation failed in tjCompress()"); for(i=0; i<height; i++) { if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch]; else row_pointer[i]= &srcbuf[i*pitch]; } if(height<ph) for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1]; for(i=0; i<cinfo->num_components; i++) { compptr=&cinfo->comp_info[i]; _tmpbuf[i]=(JSAMPLE *)malloc( PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE) /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16); if(!_tmpbuf[i]) _throw("Memory allocation failure"); tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor); if(!tmpbuf[i]) _throw("Memory allocation failure"); for(row=0; row<cinfo->max_v_samp_factor; row++) { unsigned char *_tmpbuf_aligned= (unsigned char *)PAD((size_t)_tmpbuf[i], 16); tmpbuf[i][row]=&_tmpbuf_aligned[ PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE) /compptr->h_samp_factor, 16) * row]; } _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16) * compptr->v_samp_factor + 16); if(!_tmpbuf2[i]) _throw("Memory allocation failure"); tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor); if(!tmpbuf2[i]) _throw("Memory allocation failure"); for(row=0; row<compptr->v_samp_factor; row++) { unsigned char *_tmpbuf2_aligned= (unsigned char *)PAD((size_t)_tmpbuf2[i], 16); tmpbuf2[i][row]=&_tmpbuf2_aligned[ PAD(compptr->width_in_blocks*DCTSIZE, 16) * row]; } cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor; ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor; outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]); if(!outbuf[i]) _throw("Memory allocation failure"); for(row=0; row<ch[i]; row++) { outbuf[i][row]=ptr; ptr+=PAD(cw[i], 4); } } yuvsize=(unsigned long)(ptr-dstbuf); for(row=0; row<ph; row+=cinfo->max_v_samp_factor) { (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0, cinfo->max_v_samp_factor); (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0); for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++) jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i], row*compptr->v_samp_factor/cinfo->max_v_samp_factor, compptr->v_samp_factor, cw[i]); } *size=yuvsize; cinfo->next_scanline+=height; } else { if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL) _throw("Memory allocation failed in tjCompress()"); for(i=0; i<height; i++) { if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch]; else row_pointer[i]= &srcbuf[i*pitch]; } while(j->cinfo.next_scanline<j->cinfo.image_height) { jpeg_write_scanlines(&j->cinfo, &row_pointer[j->cinfo.next_scanline], j->cinfo.image_height-j->cinfo.next_scanline); } } jpeg_finish_compress(&j->cinfo); if(!(flags&TJ_YUV)) *size=TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height) -(unsigned long)(j->jdms.free_in_buffer); bailout: if(j->cinfo.global_state>CSTATE_START) jpeg_abort_compress(&j->cinfo); if(row_pointer) free(row_pointer); for(i=0; i<MAX_COMPONENTS; i++) { if(tmpbuf[i]!=NULL) free(tmpbuf[i]); if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]); if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]); if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]); if(outbuf[i]!=NULL) free(outbuf[i]); } return retval; }