in turbojpeg.c [2665:2865]
DLLEXPORT int tj3Transform(tjhandle handle, const unsigned char *jpegBuf,
size_t jpegSize, int n, unsigned char **dstBufs,
size_t *dstSizes, const tjtransform *t)
{
static const char FUNCTION_NAME[] = "tj3Transform";
jpeg_transform_info *xinfo = NULL;
jvirt_barray_ptr *srccoefs, *dstcoefs;
int retval = 0, i, saveMarkers = 0, srcSubsamp;
boolean alloc = TRUE;
struct my_progress_mgr progress;
GET_INSTANCE(handle);
if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
THROW("Instance has not been initialized for transformation");
if (jpegBuf == NULL || jpegSize <= 0 || n < 1 || dstBufs == NULL ||
dstSizes == NULL || t == NULL)
THROW("Invalid argument");
if (this->scanLimit) {
memset(&progress, 0, sizeof(struct my_progress_mgr));
progress.pub.progress_monitor = my_progress_monitor;
progress.this = this;
dinfo->progress = &progress.pub;
} else
dinfo->progress = NULL;
dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
if ((xinfo =
(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL)
THROW("Memory allocation failure");
memset(xinfo, 0, sizeof(jpeg_transform_info) * n);
if (setjmp(this->jerr.setjmp_buffer)) {
/* If we get here, the JPEG code has signaled an error. */
retval = -1; goto bailout;
}
if (dinfo->global_state <= DSTATE_INHEADER)
jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
for (i = 0; i < n; i++) {
if (t[i].op < 0 || t[i].op >= TJ_NUMXOP)
THROW("Invalid transform operation");
xinfo[i].transform = xformtypes[t[i].op];
xinfo[i].perfect = (t[i].options & TJXOPT_PERFECT) ? 1 : 0;
xinfo[i].trim = (t[i].options & TJXOPT_TRIM) ? 1 : 0;
xinfo[i].force_grayscale = (t[i].options & TJXOPT_GRAY) ? 1 : 0;
xinfo[i].crop = (t[i].options & TJXOPT_CROP) ? 1 : 0;
if (n != 1 && t[i].op == TJXOP_HFLIP) xinfo[i].slow_hflip = 1;
else xinfo[i].slow_hflip = 0;
if (xinfo[i].crop) {
if (t[i].r.x < 0 || t[i].r.y < 0 || t[i].r.w < 0 || t[i].r.h < 0)
THROW("Invalid cropping region");
xinfo[i].crop_xoffset = t[i].r.x; xinfo[i].crop_xoffset_set = JCROP_POS;
xinfo[i].crop_yoffset = t[i].r.y; xinfo[i].crop_yoffset_set = JCROP_POS;
if (t[i].r.w != 0) {
xinfo[i].crop_width = t[i].r.w; xinfo[i].crop_width_set = JCROP_POS;
} else
xinfo[i].crop_width = JCROP_UNSET;
if (t[i].r.h != 0) {
xinfo[i].crop_height = t[i].r.h; xinfo[i].crop_height_set = JCROP_POS;
} else
xinfo[i].crop_height = JCROP_UNSET;
}
if (!(t[i].options & TJXOPT_COPYNONE)) saveMarkers = 1;
}
jcopy_markers_setup(dinfo, saveMarkers ? JCOPYOPT_ALL : JCOPYOPT_NONE);
if (dinfo->global_state <= DSTATE_INHEADER)
jpeg_read_header(dinfo, TRUE);
if (this->maxPixels &&
(unsigned long long)dinfo->image_width * dinfo->image_height >
(unsigned long long)this->maxPixels)
THROW("Image is too large");
srcSubsamp = getSubsamp(&this->dinfo);
for (i = 0; i < n; i++) {
if (!jtransform_request_workspace(dinfo, &xinfo[i]))
THROW("Transform is not perfect");
if (xinfo[i].crop) {
int dstSubsamp = (t[i].options & TJXOPT_GRAY) ? TJSAMP_GRAY : srcSubsamp;
if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
if (dstSubsamp == TJSAMP_422) dstSubsamp = TJSAMP_440;
else if (dstSubsamp == TJSAMP_440) dstSubsamp = TJSAMP_422;
else if (dstSubsamp == TJSAMP_411) dstSubsamp = TJSAMP_441;
else if (dstSubsamp == TJSAMP_441) dstSubsamp = TJSAMP_411;
}
if (dstSubsamp == TJSAMP_UNKNOWN)
THROW("Could not determine subsampling level of destination image");
if ((t[i].r.x % tjMCUWidth[dstSubsamp]) != 0 ||
(t[i].r.y % tjMCUHeight[dstSubsamp]) != 0)
THROWI("To crop this JPEG image, x must be a multiple of %d\n"
"and y must be a multiple of %d.", tjMCUWidth[dstSubsamp],
tjMCUHeight[dstSubsamp]);
}
}
srccoefs = jpeg_read_coefficients(dinfo);
for (i = 0; i < n; i++) {
JDIMENSION dstWidth = dinfo->image_width, dstHeight = dinfo->image_height;
if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
dstWidth = dinfo->image_height; dstHeight = dinfo->image_width;
}
if (xinfo[i].crop) {
if ((JDIMENSION)t[i].r.x >= dstWidth ||
t[i].r.x + xinfo[i].crop_width > dstWidth ||
(JDIMENSION)t[i].r.y >= dstHeight ||
t[i].r.y + xinfo[i].crop_height > dstHeight)
THROW("The cropping region exceeds the destination image dimensions");
dstWidth = xinfo[i].crop_width; dstHeight = xinfo[i].crop_height;
}
if (this->noRealloc) {
int dstSubsamp = (t[i].options & TJXOPT_GRAY) ? TJSAMP_GRAY : srcSubsamp;
if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
if (dstSubsamp == TJSAMP_422) dstSubsamp = TJSAMP_440;
else if (dstSubsamp == TJSAMP_440) dstSubsamp = TJSAMP_422;
else if (dstSubsamp == TJSAMP_411) dstSubsamp = TJSAMP_441;
else if (dstSubsamp == TJSAMP_441) dstSubsamp = TJSAMP_411;
}
if (dstSubsamp == TJSAMP_UNKNOWN)
THROW("Could not determine subsampling level of destination image");
alloc = FALSE;
dstSizes[i] = tj3JPEGBufSize(dstWidth, dstHeight, dstSubsamp);
}
if (!(t[i].options & TJXOPT_NOOUTPUT))
jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
jpeg_copy_critical_parameters(dinfo, cinfo);
dstcoefs = jtransform_adjust_parameters(dinfo, cinfo, srccoefs, &xinfo[i]);
if (this->optimize || t[i].options & TJXOPT_OPTIMIZE)
cinfo->optimize_coding = TRUE;
#ifdef C_PROGRESSIVE_SUPPORTED
if (this->progressive || t[i].options & TJXOPT_PROGRESSIVE)
jpeg_simple_progression(cinfo);
#endif
if (this->arithmetic || t[i].options & TJXOPT_ARITHMETIC) {
cinfo->arith_code = TRUE;
cinfo->optimize_coding = FALSE;
}
if (!(t[i].options & TJXOPT_NOOUTPUT)) {
jpeg_write_coefficients(cinfo, dstcoefs);
jcopy_markers_execute(dinfo, cinfo, t[i].options & TJXOPT_COPYNONE ?
JCOPYOPT_NONE : JCOPYOPT_ALL);
} else
jinit_c_master_control(cinfo, TRUE);
jtransform_execute_transformation(dinfo, cinfo, srccoefs, &xinfo[i]);
if (t[i].customFilter) {
int ci, y;
JDIMENSION by;
for (ci = 0; ci < cinfo->num_components; ci++) {
jpeg_component_info *compptr = &cinfo->comp_info[ci];
tjregion arrayRegion = { 0, 0, 0, 0 };
tjregion planeRegion = { 0, 0, 0, 0 };
arrayRegion.w = compptr->width_in_blocks * DCTSIZE;
arrayRegion.h = DCTSIZE;
planeRegion.w = compptr->width_in_blocks * DCTSIZE;
planeRegion.h = compptr->height_in_blocks * DCTSIZE;
for (by = 0; by < compptr->height_in_blocks;
by += compptr->v_samp_factor) {
JBLOCKARRAY barray = (dinfo->mem->access_virt_barray)
((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
TRUE);
for (y = 0; y < compptr->v_samp_factor; y++) {
if (t[i].customFilter(barray[y][0], arrayRegion, planeRegion, ci,
i, (tjtransform *)&t[i]) == -1)
THROW("Error in custom filter");
arrayRegion.y += DCTSIZE;
}
}
}
}
if (!(t[i].options & TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
}
jpeg_finish_decompress(dinfo);
bailout:
if (cinfo->global_state > CSTATE_START) {
if (alloc) (*cinfo->dest->term_destination) (cinfo);
jpeg_abort_compress(cinfo);
}
if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
free(xinfo);
if (this->jerr.warning) retval = -1;
return retval;
}