in api_dev/src/main/java/com/google/appengine/api/images/dev/LocalImagesService.java [564:686]
public BufferedImage processTransform(BufferedImage image, Transform transform, Status status) {
AffineTransform affine = null;
BufferedImage constraintImage = null;
if (transform.hasWidth() || transform.hasHeight()) {
if (transform.getWidth() < 0 || transform.getHeight() < 0
|| transform.getWidth() > ImagesService.MAX_RESIZE_DIMENSIONS
|| transform.getHeight() > ImagesService.MAX_RESIZE_DIMENSIONS) {
status.setSuccessful(false);
status.setErrorCode(ErrorCode.BAD_TRANSFORM_DATA.getNumber());
throw new ApiProxy.ApplicationException(ErrorCode.BAD_TRANSFORM_DATA.getNumber(),
String.format("Invalid resize: width and height must be in range [0,%d]",
ImagesService.MAX_RESIZE_DIMENSIONS));
}
if (transform.getWidth() == 0 && transform.getHeight() == 0) {
status.setSuccessful(false);
status.setErrorCode(ErrorCode.BAD_TRANSFORM_DATA.getNumber());
throw new ApiProxy.ApplicationException(ErrorCode.BAD_TRANSFORM_DATA.getNumber(),
"Invalid resize: width and height cannot both be 0.");
}
if (transform.getCropToFit() && (transform.getWidth() == 0 || transform.getHeight() == 0)) {
status.setSuccessful(false);
status.setErrorCode(ErrorCode.BAD_TRANSFORM_DATA.getNumber());
throw new ApiProxy.ApplicationException(ErrorCode.BAD_TRANSFORM_DATA.getNumber(),
"Invalid resize: neither width nor height can be 0 with crop to fit.");
}
if (transform.getAllowStretch()
&& (transform.getWidth() == 0 || transform.getHeight() == 0)) {
status.setSuccessful(false);
status.setErrorCode(ErrorCode.BAD_TRANSFORM_DATA.getNumber());
throw new ApiProxy.ApplicationException(ErrorCode.BAD_TRANSFORM_DATA.getNumber(),
"Invalid resize: neither width nor height can be 0 with allow stretch.");
}
if (transform.getCropToFit() && (!validCropArgument(transform.getCropOffsetX())
|| !validCropArgument(transform.getCropOffsetY()))) {
status.setSuccessful(false);
status.setErrorCode(ErrorCode.BAD_TRANSFORM_DATA.getNumber());
throw new ApiProxy.ApplicationException(ErrorCode.BAD_TRANSFORM_DATA.getNumber(),
"Invalid resize: crop offsets must be in the range 0.0 to 1.0.");
}
double aspectRatio = (double) image.getWidth() / (double) image.getHeight();
double xFactor = (double) transform.getWidth() / (double) image.getWidth();
double yFactor = (double) transform.getHeight() / (double) image.getHeight();
double transformFactor;
ImageTypeSpecifier imageSpecifier = ImageTypeSpecifier.createFromRenderedImage(image);
if (transform.getAllowStretch()) {
constraintImage = imageSpecifier.createBufferedImage(transform.getWidth(),
transform.getHeight());
affine = AffineTransform.getScaleInstance(xFactor, yFactor);
} else if (transform.getCropToFit()) {
transformFactor = Math.max(xFactor, yFactor);
constraintImage = imageSpecifier.createBufferedImage(transform.getWidth(),
transform.getHeight());
double uncroppedWidth = image.getWidth() * transformFactor;
double uncroppedHeight = image.getHeight() * transformFactor;
affine = new AffineTransform(
transformFactor, 0, 0, transformFactor,
(transform.getWidth() - uncroppedWidth) * transform.getCropOffsetX(),
(transform.getHeight() - uncroppedHeight) * transform.getCropOffsetY());
} else {
if (xFactor < yFactor && xFactor != 0) {
transformFactor = xFactor;
constraintImage = imageSpecifier.createBufferedImage(
transform.getWidth(),
(int) Math.round(transform.getWidth() / aspectRatio));
} else {
transformFactor = yFactor;
constraintImage = imageSpecifier.createBufferedImage(
(int) Math.round(transform.getHeight() * aspectRatio),
transform.getHeight());
}
affine = AffineTransform.getScaleInstance(transformFactor, transformFactor);
}
} else if (transform.hasRotate()) {
if ((transform.getRotate() % 90) != 0 || transform.getRotate() >= 360
|| transform.getRotate() < 0) {
status.setSuccessful(false);
status.setErrorCode(ErrorCode.BAD_TRANSFORM_DATA.getNumber());
throw new ApiProxy.ApplicationException(
ErrorCode.BAD_TRANSFORM_DATA.getNumber(), "Invalid rotate.");
}
affine = AffineTransform.getRotateInstance(Math.toRadians(transform.getRotate()));
if (transform.getRotate() == 90) {
affine.translate(0, -image.getHeight());
} else if (transform.getRotate() == 180) {
affine.translate(-image.getWidth(), -image.getHeight());
} else if (transform.getRotate() == 270) {
affine.translate(-image.getWidth(), 0);
}
} else if (transform.hasHorizontalFlip()) {
affine = new AffineTransform(-1.0, 0.0, 0.0, 1.0, image.getWidth(), 0.0);
} else if (transform.hasVerticalFlip()) {
affine = new AffineTransform(1.0, 0.0, 0.0, -1.0, 0.0, image.getHeight());
} else if (transform.hasCropLeftX() || transform.hasCropTopY() || transform.hasCropRightX()
|| transform.hasCropBottomY()) {
if (!validCropArgs(transform)) {
status.setSuccessful(false);
status.setErrorCode(ErrorCode.BAD_TRANSFORM_DATA.getNumber());
throw new ApiProxy.ApplicationException(
ErrorCode.BAD_TRANSFORM_DATA.getNumber(), "Invalid crop.");
}
int startX = Math.round(transform.getCropLeftX() * image.getWidth());
int startY = Math.round(transform.getCropTopY() * image.getHeight());
int width = Math.min(
Math.round((transform.getCropRightX() - transform.getCropLeftX()) * image.getWidth()),
image.getWidth() - startX);
int height = Math.min(
Math.round((transform.getCropBottomY() - transform.getCropTopY()) * image.getHeight()),
image.getHeight() - startY);
return image.getSubimage(startX, startY, width, height);
} else if (transform.hasAutolevels()) {
log.warning("I'm Feeling Lucky is not available in the SDK.");
} else {
status.setSuccessful(false);
status.setErrorCode(ErrorCode.BAD_TRANSFORM_DATA.getNumber());
throw new ApiProxy.ApplicationException(ErrorCode.BAD_TRANSFORM_DATA.getNumber());
}
if (affine != null) {
AffineTransformOp op = new AffineTransformOp(affine, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
return op.filter(image, constraintImage);
}
return image;
}