diff -b -u -r jpeg-6b/jpegtran.c jpeg-6b-me/jpegtran.c --- jpeg-6b/jpegtran.c Wed Jul 23 19:37:26 1997 +++ jpeg-6b-me/jpegtran.c Thu Mar 4 00:53:46 1999 @@ -70,6 +70,7 @@ 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,6 +186,30 @@ } 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,6 +350,13 @@ 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. diff -b -u -r jpeg-6b/transupp.c jpeg-6b-me/transupp.c --- jpeg-6b/transupp.c Sat Aug 9 17:15:26 1997 +++ jpeg-6b-me/transupp.c Thu Mar 4 06:16:17 1999 @@ -181,6 +181,35 @@ } } +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 < jround_up(compptr->height_in_blocks, compptr->v_samp_factor); 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,6 +616,8 @@ 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,6 +747,68 @@ 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; + dstinfo->image_height = info->newheight + (info->yoffs % factor); + if (!dstinfo->image_height) /* can't trim to 0 pixels */ + 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; + dstinfo->image_width = info->newwidth + (info->xoffs % factor); + if (!dstinfo->image_width) /* can't trim to 0 pixels */ + jpegtran_error("degenerate -cut width"); +} /* Adjust output image parameters as needed. * @@ -762,6 +855,9 @@ 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,6 +921,9 @@ 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); diff -b -u -r jpeg-6b/transupp.h jpeg-6b-me/transupp.h --- jpeg-6b/transupp.h Wed Jul 23 19:39:12 1997 +++ jpeg-6b-me/transupp.h Thu Mar 4 00:53:46 1999 @@ -39,6 +39,7 @@ 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,6 +89,8 @@ 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 */