*** jpeg-6b-beta1/jpegtran.c Wed Jul 23 19:37:26 1997 --- TMP/jpegtran.c Thu Jun 4 16:44:42 1998 *************** *** 70,75 **** --- 70,76 ---- fprintf(stderr, " -transpose Transpose image\n"); fprintf(stderr, " -transverse Transverse transpose image\n"); fprintf(stderr, " -trim Drop non-transformable edge blocks\n"); + fprintf(stderr, " -cut WxH+X+Y Cut out a subset of the image\n"); #endif /* TRANSFORMS_SUPPORTED */ fprintf(stderr, "Switches for advanced users:\n"); fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n"); *************** *** 185,190 **** --- 186,215 ---- } cinfo->err->trace_level++; + } else if (keymatch(arg, "cut", 1)) { + /* Cut out a region of the image specified by an X geometry-like string */ + char *p; + + if (++argn >= argc) + usage(); + select_transform(JXFORM_CUT); + p = argv[argn]; + transformoption.newwidth = strtol(p, &p, 10); + if (*p++ != 'x') + usage(); + transformoption.newheight = strtol(p, &p, 10); + if (*p != '+' && *p != '-') + usage(); + transformoption.xoffs = strtol(p, &p, 10); + if (*p != '+' && *p != '-') + usage(); + transformoption.yoffs = strtol(p, &p, 10); + + if (!transformoption.newwidth || !transformoption.newheight) { + fprintf(stderr, "%s: degenerate -cut size in %s\n", + progname, argv[argn]); + exit(EXIT_FAILURE); + } } else if (keymatch(arg, "flip", 1)) { /* Mirror left-right or top-bottom. */ if (++argn >= argc) /* advance to next argument */ *************** *** 325,330 **** --- 350,362 ---- return argn; /* return index of next arg (file name) */ } + + GLOBAL(void) + jpegtran_error(char *str) + { + fprintf(stderr, "%s: %s\n", progname, str); + exit(EXIT_FAILURE); + } /* * The main program. *** jpeg-6b-beta1/transupp.c Sat Aug 9 17:15:26 1997 --- TMP/transupp.c Thu Jun 4 17:09:37 1998 *************** *** 181,186 **** --- 181,215 ---- } } + LOCAL(void) + do_transform (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays, + JDIMENSION xoffs, JDIMENSION yoffs) + /* transform src_coef_arrays so that the xoffs,yoffs (rounded to an even + * dct block) are the new origin of the image. copy rather than move because + * I'd never finish if I tried to understand the byzantine memory management. + */ + { + int ci; + jpeg_component_info *compptr; + JBLOCKARRAY src_buffer, dst_buffer; + JDIMENSION dst_blk_x, dst_blk_y; + + xoffs /= dstinfo->max_h_samp_factor * DCTSIZE; + yoffs /= dstinfo->max_v_samp_factor * DCTSIZE; + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y++) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, 1, TRUE); + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y + yoffs * compptr->v_samp_factor, 1, FALSE); + jcopy_block_row(&src_buffer[0][xoffs * compptr->h_samp_factor], dst_buffer[0], compptr->width_in_blocks); + } + } + } LOCAL(void) do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, *************** *** 587,592 **** --- 616,623 ---- case JXFORM_FLIP_H: /* Don't need a workspace array */ break; + case JXFORM_CUT: + /* really cut needs smaller arrays if you want to figure it out */ case JXFORM_FLIP_V: case JXFORM_ROT_180: /* Need workspace arrays having same dimensions as source image. *************** *** 716,721 **** --- 747,822 ---- dstinfo->image_height = MCU_rows * (max_v_samp_factor * DCTSIZE); } + /* For cropping, realize and constrain the target area, and reshape the + * dstinfo to hold the resulting image. + * + * Input was supplied as WxH[+-]X[+-]Y offsets. Negative offsets are + * relative to the lower righthand corner of the image. The region is + * expanded so that all boundaries fall on even MCU blocks by rounding + * the offsets *down* (at the do_transform() step) and the size *up*. + */ + LOCAL(void) + set_dest_size(j_compress_ptr dstinfo, jpeg_transform_info *info) + { + int ci, max_samp_factor; + JDIMENSION MCU_size, newsize, offset, factor; + + /* Initially the dstinfo is the same size as the srcinfo. + * Use it to constrain the offsets: + */ + if (info->xoffs < 0) + info->xoffs += dstinfo->image_width; + if (info->yoffs < 0) + info->yoffs += dstinfo->image_height; + if (info->xoffs < 0 || info->xoffs >= dstinfo->image_width || + info->yoffs < 0 || info->yoffs >= dstinfo->image_height) { + jpegtran_error("-cut offsets fall outside source image"); + } + + /* use it to constrain the size: */ + if (info->newwidth + info->xoffs > dstinfo->image_width) + info->newwidth = dstinfo->image_width - info->xoffs; + if (info->newheight + info->yoffs > dstinfo->image_height) + info->newheight = dstinfo->image_height - info->yoffs; + + /* We have to compute max_v/h_samp_factors ourselves, + * because it hasn't been set yet in the destination + * (and we don't want to use the source's value). + */ + max_samp_factor = 1; + for (ci = 0; ci < dstinfo->num_components; ci++) { + int samp_factor = dstinfo->comp_info[ci].v_samp_factor; + max_samp_factor = MAX(max_samp_factor, samp_factor); + } + /* Find original (rounded down) and new (rounded up) heights in full + * dct blocks, choose the smaller of the two. + */ + factor = max_samp_factor * DCTSIZE; + MCU_size = dstinfo->image_height / factor; + newsize = (info->newheight + (info->yoffs % factor) + factor - 1) / factor; + MCU_size = MIN(MCU_size, newsize); + if (MCU_size > 0) /* can't trim to 0 pixels */ + dstinfo->image_height = MCU_size * factor; + else + jpegtran_error("degenerate -cut height"); + + max_samp_factor = 1; + for (ci = 0; ci < dstinfo->num_components; ci++) { + int samp_factor = dstinfo->comp_info[ci].h_samp_factor; + max_samp_factor = MAX(max_samp_factor, samp_factor); + } + /* Find original (rounded down) and new (rounded up) heights in full + * dct blocks, choose the smaller of the two. + */ + factor = max_samp_factor * DCTSIZE; + MCU_size = dstinfo->image_width / factor; + newsize = (info->newwidth + (info->xoffs % factor) + factor - 1) / factor; + MCU_size = MIN(MCU_size, newsize); + if (MCU_size > 0) /* can't trim to 0 pixels */ + dstinfo->image_width = MCU_size * factor; + else + jpegtran_error("degenerate -cut width"); + } /* Adjust output image parameters as needed. * *************** *** 762,767 **** --- 863,871 ---- case JXFORM_NONE: /* Nothing to do */ break; + case JXFORM_CUT: + set_dest_size(dstinfo, info); + break; case JXFORM_FLIP_H: if (info->trim) trim_right_edge(dstinfo); *************** *** 825,830 **** --- 929,937 ---- switch (info->transform) { case JXFORM_NONE: + break; + case JXFORM_CUT: + do_transform(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays, info->xoffs, info->yoffs); break; case JXFORM_FLIP_H: do_flip_h(srcinfo, dstinfo, src_coef_arrays); *** jpeg-6b-beta1/transupp.h Wed Jul 23 19:39:12 1997 --- TMP/transupp.h Thu Jun 4 00:40:58 1998 *************** *** 39,44 **** --- 39,45 ---- typedef enum { JXFORM_NONE, /* no transformation */ + JXFORM_CUT, /* cut out part of the image */ JXFORM_FLIP_H, /* horizontal flip */ JXFORM_FLIP_V, /* vertical flip */ JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ *************** *** 88,93 **** --- 89,96 ---- JXFORM_CODE transform; /* image transform operator */ boolean trim; /* if TRUE, trim partial MCUs as needed */ boolean force_grayscale; /* if TRUE, convert color image to grayscale */ + + JDIMENSION xoffs, yoffs, newwidth, newheight; /* Internal workspace: caller should not touch these */ int num_components; /* # of components in workspace */