in imagetool/commands/resize.cpp [169:439]
int ResizeCommand::performResize(const char** args, unsigned int numArgs)
{
ImageReader* reader = ImageReader::create(m_Source);
if( reader == NULL ) {
fprintf(stderr, "error: unknown or corrupt image format for '%s'\n", m_InputFilePath);
return IMAGECORE_INVALID_FORMAT;
}
const char* outputSize = args[2];
unsigned int parseWidth = reader->getOrientedWidth();
unsigned int parseHeight = reader->getOrientedHeight();
unsigned int outputWidth = 0;
unsigned int outputHeight = 0;
if( !parseOutputSize(outputSize, parseWidth, parseHeight, outputWidth, outputHeight) ) {
fprintf(stderr, "error: bad size parameter\n");
delete reader;
return IMAGECORE_INVALID_OUTPUT_SIZE;
}
bool shouldCrop = true;
ECropGravity cropGravity = kGravityHeuristic;
bool minAxis = false;
EResizeQuality resizeQuality = kResizeQuality_High;
unsigned int compressionQuality = 75;
ImageRegion* cropRegion = NULL;
bool allowYUV = true;
bool allowUpsample = true;
bool allowDownsample = true;
EResizeMode resizeMode = kResizeMode_ExactCrop;
const char* format = NULL;
bool didSetMode = false;
bool forceRGB = false;
bool forceRLE = false;
bool progressive = false;
bool backfill = false;
unsigned int backfillWidth = 0;
unsigned int backfillHeight = 0;
unsigned char backfillR = 0;
unsigned char backfillG = 0;
unsigned char backfillB = 0;
unsigned int mod = 1;
const char* writerArgNames[32];
const char* writerArgValues[32];
unsigned int numWriterArgs = 0;
// Optional args.
unsigned int numOptional = numArgs - 3;
if( numOptional > 0 ) {
unsigned int numPairs = numOptional / 2;
for( unsigned int i = 0; i < numPairs; i++ ) {
const char* argName = args[3 + i * 2 + 0];
const char* argValue = args[3 + i * 2 + 1];
if( strcmp(argName, "-crop") == 0 ) {
shouldCrop = strcmp(argValue, "true") == 0;
} else if( strcmp(argName, "-gravity") == 0 ) {
if( strcmp(argValue, "center") == 0 ) {
cropGravity = kGravityCenter;
} else if( strcmp(argValue, "left") == 0 ) {
cropGravity = kGravityLeft;
} else if( strcmp(argValue, "top") == 0 ) {
cropGravity = kGravityTop;
} else if( strcmp(argValue, "right") == 0 ) {
cropGravity = kGravityRight;
} else if( strcmp(argValue, "bottom") == 0 ) {
cropGravity = kGravityBottom;
}
} else if( strcmp(argName, "-region") == 0 ) {
// because this flag causes a new ImageRegion to be allocated,
// make sure to free the previous allocation in the case that
// this is not the first -region flag.
if( cropRegion != NULL ) {
delete cropRegion;
cropRegion = NULL;
}
if( (cropRegion = ImageRegion::fromString(argValue)) == NULL ) {
fprintf(stderr, "error: invalid crop region given as '%s'\n", argValue);
delete reader;
return IMAGECORE_INVALID_USAGE;
}
if( cropRegion != NULL && ( !Image::validateSize(cropRegion->width(), cropRegion->height())
|| SafeUAdd(cropRegion->left(), cropRegion->width()) > parseWidth
|| SafeUAdd(cropRegion->top(), cropRegion->height()) > parseHeight) ) {
fprintf(stderr, "error: crop region not within image dimensions\n");
delete reader;
return IMAGECORE_INVALID_OUTPUT_SIZE;
}
} else if( strcmp(argName, "-minaxis") == 0 ) {
minAxis = strcmp(argValue, "true") == 0;
} else if( strcmp(argName, "-resizequality") == 0 ) {
resizeQuality = getResizeQuality(argValue);
} else if( strcmp(argName, "-filequality") == 0 || strcmp(argName, "-quality") == 0 ) {
compressionQuality = clamp(0, 100, atoi(argValue));
} else if( strcmp(argName, "-pad") == 0 ) {
int ret = populateBuckets(argValue);
if (ret != IMAGECORE_SUCCESS) {
delete reader;
return ret;
}
} else if( strcmp(argName, "-forcergb") == 0 ) {
forceRGB = strcmp(argValue, "true") == 0;
if( forceRGB ) {
reader->setReadOptions(ImageReader::kReadOption_ApplyColorProfile);
}
} else if( strcmp(argName, "-yuvpath") == 0 ) {
allowYUV = strcmp(argValue, "true") == 0;
} else if( strcmp(argName, "-upsample") == 0 ) {
allowUpsample = strcmp(argValue, "true") == 0;
} else if( strcmp(argName, "-downsample") == 0 ) {
allowDownsample = strcmp(argValue, "true") == 0;
} else if( strcmp(argName, "-format") == 0 ) {
format = argValue;
} else if( strcmp(argName, "-progressive") == 0 ) {
progressive = strcmp(argValue, "true") == 0;
} else if( strcmp(argName, "-mode") == 0 ) {
if( strcmp(argValue, "fit") == 0 ) {
resizeMode = kResizeMode_AspectFit;
} else if( strcmp(argValue, "fill") == 0 ) {
resizeMode = kResizeMode_AspectFill;
} else if( strcmp(argValue, "crop") == 0 ) {
resizeMode = kResizeMode_ExactCrop;
} else if( strcmp(argValue, "stretch") == 0 ) {
resizeMode = kResizeMode_Stretch;
} else {
fprintf(stderr, "error: bad resize mode\n");
delete reader;
return IMAGECORE_INVALID_USAGE;
}
didSetMode = true;
} else if( strcmp(argName, "-mod") == 0 ) {
mod = atoi(argValue);
} else if( strcmp(argName, "-png:forceRLE") == 0 ) {
forceRLE = strcmp(argValue, "true") == 0;
} else if( strcmp(argName, "-backfillsize") == 0 ) {
if ( !parseBackgroundfillSize(argValue, outputWidth, outputHeight, backfillWidth, backfillHeight) ) {
fprintf(stderr, "error: bad backfill size\n");
delete reader;
return IMAGECORE_INVALID_OUTPUT_SIZE;
}
backfill = true;
} else if( strcmp(argName, "-backfillcolor") == 0 ) {
if ( !parseBackfillColor(argValue, backfillR, backfillG, backfillB) ) {
fprintf(stderr, "error: bad backfill color\n");
delete reader;
return IMAGECORE_INVALID_COLOR;
}
} else if( strncmp(argName, "-encoder:", 9) == 0 ) {
size_t argLen = strlen(argName) - 9;
if( argLen > 0 ) {
writerArgNames[numWriterArgs] = argName + 9;
writerArgValues[numWriterArgs] = argValue;
numWriterArgs++;
} else {
fprintf(stderr, "error: bad encoder argument\n");
delete reader;
return IMAGECORE_INVALID_USAGE;
}
}
}
}
if (!didSetMode) {
// Legacy params.
if (shouldCrop) {
resizeMode = kResizeMode_ExactCrop;
} else if (minAxis) {
resizeMode = kResizeMode_AspectFit;
} else {
resizeMode = kResizeMode_AspectFill;
}
}
EImageFormat outputFormat = ImageWriter::formatFromExtension(format != NULL ? format : args[1], reader->getFormat());
ResizeCropOperation resizeCrop;
resizeCrop.setImageReader(reader);
resizeCrop.setCropGravity(cropGravity);
resizeCrop.setResizeQuality(resizeQuality);
resizeCrop.setCropRegion(cropRegion);
resizeCrop.setOutputSize(outputWidth, outputHeight);
resizeCrop.setResizeMode(resizeMode);
resizeCrop.setAllowUpsample(allowUpsample);
resizeCrop.setAllowDownsample(allowDownsample);
resizeCrop.setOutputMod(mod);
if( backfill ) {
resizeCrop.setBackgroundFillColor(backfillR, backfillG, backfillB);
}
// Reader and writer agree on a more optimal mutual color model and no backfill color is specified use native,
// otherwise use default (rgb).
EImageColorModel nativeColorModel = reader->getNativeColorModel();
if( ImageWriter::outputFormatSupportsColorModel(outputFormat, nativeColorModel) && !backfill ) {
// Some further restrictions, the YUV path isn't optimized for anything but high quality.
// Also, color profiles cannot be applied.
if( Image::colorModelIsYUV(nativeColorModel) ) {
if( allowYUV && resizeQuality >= kResizeQuality_High && !forceRGB ) {
resizeCrop.setOutputColorModel(nativeColorModel);
}
} else {
resizeCrop.setOutputColorModel(nativeColorModel);
}
}
Image* resizedImage = NULL;
int ret = resizeCrop.performResizeCrop(resizedImage);
if( ret != IMAGECORE_SUCCESS ) {
delete reader;
return ret;
}
START_CLOCK(compress);
ImageWriter* writer = ImageWriter::createWithFormat(outputFormat, m_Output);
if (writer == NULL) {
fprintf(stderr, "error: unable to create ImageWriter\n");
delete reader;
return IMAGECORE_OUT_OF_MEMORY;
}
unsigned int writeOptions = 0;
if( forceRGB ) {
writeOptions |= ImageWriter::kWriteOption_WriteDefaultColorProfile;
} else {
writeOptions |= ImageWriter::kWriteOption_CopyColorProfile;;
}
if( progressive ) {
writeOptions |= ImageWriter::kWriteOption_Progressive;
}
if( forceRLE ) {
writeOptions |= ImageWriter::kWriteOption_ForcePNGRunLengthEncoding;
}
writer->setWriteOptions(writeOptions);
// Allows certain formats to re-use information from the input image, like color profiles.
writer->setSourceReader(reader);
writer->setQuality(compressionQuality);
if( !writer->applyExtraOptions(writerArgNames, writerArgValues, numWriterArgs) ) {
fprintf(stderr, "error: unable to apply writer-specific options\n");
delete reader;
delete writer;
return IMAGECORE_INVALID_USAGE;
}
// handle backfill requests
Image* backfilledImage = NULL;
Image* finalImage;
if( backfill ) {
backfilledImage = backfillImage(resizedImage, backfillWidth, backfillHeight, backfillR, backfillG, backfillB);
finalImage = backfilledImage;
} else {
finalImage = resizedImage;
}
if( !writer->writeImage(finalImage) ) {
fprintf(stderr, "error: failed to compress image\n");
delete reader;
delete writer;
return IMAGECORE_WRITE_ERROR;
}
END_CLOCK(compress);
delete backfilledImage;
delete writer;
delete reader;
return IMAGECORE_SUCCESS;
}