I have a simple REST API built in ColdFusion 11 that allows our vendor to update product information. Most of the data they send (about 30 attributes) is simple values - strings and numbers. One attribute is a Base64 encoded string that represents an image file. The REST API updates the simple data values in the database, and then reads the image and resizes it into 4 size that are suitable for use on the website. I've noticed that occasionally the vendor will send large images with some requests (20MB+) and that these requests often result in a "java.lang.OutOfMemoryError: Java heap space" on the line where the ImageReadBase64()
function is called. We have other web apps running on this server and it seems that the memory that gets locked up processing these images causes problem with those apps as well. I'm trying to figure out if there's anything that I can do in the code to reduce these issues, even if it's figuring out a way to NOT process the images if they are "too big" (over a certain size). Here is all the code that is run to process the images:
public struct function getDimensionsToEnlarge(
required numeric imageWidth,
required numeric imageHeight,
required numeric minWidth,
required numeric minHeight
) {
LOCAL.Dimensions={
width=-1,
height=-1
};
if ( ARGUMENTS.minHeight > 0
&& ARGUMENTS.minWidth > 0
&& ARGUMENTS.imageHeight < ARGUMENTS.minHeight
&& ARGUMENTS.imageWidth < ARGUMENTS.minWidth
) {
LOCAL.Dimensions.width=ARGUMENTS.minWidth;
LOCAL.Dimensions.height=ARGUMENTS.minHeight;
}
return LOCAL.Dimensions;
}
public struct function getDimensionsToShrink(
required numeric imageWidth,
required numeric imageHeight,
required numeric maxWidth,
required numeric maxHeight
) {
LOCAL.Dimensions={
width=-1,
height=-1
};
if ( ARGUMENTS.maxHeight > 0
&& ARGUMENTS.maxWidth > 0
&& ( ARGUMENTS.imageHeight > ARGUMENTS.maxHeight
|| ARGUMENTS.imageWidth > ARGUMENTS.maxWidth
)
) {
LOCAL.Dimensions.width=ARGUMENTS.maxWidth;
LOCAL.Dimensions.height=ARGUMENTS.maxHeight;
}
return LOCAL.Dimensions;
}
public struct function getDimensionsToFit(
required numeric imageWidth,
required numeric imageHeight,
required numeric minWidth,
required numeric minHeight,
required numeric maxWidth,
required numeric maxHeight
) {
LOCAL.Dimensions={
width=-1,
height=-1
};
LOCAL.Dimensions =
getDimensionsToEnlarge(
imageHeight=ARGUMENTS.imageHeight,
imageWidth=ARGUMENTS.imageWidth,
minWidth=ARGUMENTS.minWidth,
minHeight=ARGUMENTS.minHeight
);
if (LOCAL.Dimensions.width < 0 && LOCAL.Dimensions.height < 0)
LOCAL.Dimensions =
getDimensionsToShrink(
imageHeight=ARGUMENTS.imageHeight,
imageWidth=ARGUMENTS.imageWidth,
maxWidth=ARGUMENTS.maxWidth,
maxHeight=ARGUMENTS.maxHeight
);
return LOCAL.Dimensions;
}
public any function scale(
required any image,
string action="fit",
numeric minWidth=-1,
numeric minHeight=-1,
numeric maxWidth=-1,
numeric maxHeight=-1
) {
LOCAL.Dimensions={
width=-1,
height=-1
};
LOCAL.Image=Duplicate(ARGUMENTS.image);
switch (ARGUMENTS.action) {
case "shrink":
LOCAL.Dimensions =
getDimensionsToShrink(
imageHeight=LOCAL.Image.getHeight(),
imageWidth=LOCAL.Image.getWidth(),
maxWidth=ARGUMENTS.maxWidth,
maxHeight=ARGUMENTS.maxHeight
);
break;
case "enlarge":
LOCAL.Dimensions =
getDimensionsToEnlarge(
imageHeight=LOCAL.Image.getHeight(),
imageWidth=LOCAL.Image.getWidth(),
minWidth=ARGUMENTS.minWidth,
minHeight=ARGUMENTS.minHeight
);
break;
default:
LOCAL.Dimensions =
getDimensionsToFit(
imageHeight=LOCAL.Image.getHeight(),
imageWidth=LOCAL.Image.getWidth(),
minWidth=ARGUMENTS.minWidth,
minHeight=ARGUMENTS.minHeight,
maxWidth=ARGUMENTS.maxWidth,
maxHeight=ARGUMENTS.maxHeight
);
break;
}
if (LOCAL.Dimensions.width > 0 && LOCAL.Dimensions.height > 0) {
ImageSetAntialiasing(LOCAL.Image, "on");
ImageScaleToFit(
LOCAL.Image,
LOCAL.Dimensions.width,
LOCAL.Dimensions.height
);
}
return LOCAL.Image;
}
public void function createLargeThumbnail(required any image) {
ImageWrite(
scale(image=ARGUMENTS.image, maxHeight=500, maxWidth=700),
getLargeImagePath(),
0.75,
true
);
return;
}
public void function createMediumThumbnail(required any image) {
ImageWrite(
scale(image=ARGUMENTS.image, maxHeight=300, maxWidth=300),
getMediumImagePath(),
0.75,
true
);
return;
}
public void function createSmallThumbnail(required any image) {
ImageWrite(
scale(image=ARGUMENTS.image, maxHeight=50, maxWidth=50),
getSmallImagePath(),
0.75,
true
);
return;
}
public void function createMobileThumbnail(required any image) {
ImageWrite(
scale(image=ARGUMENTS.image, maxHeight=50, maxWidth=300),
getMobileImagePath(),
0.75,
true
);
return;
}
public void function createProductThumbnails(required any image) {
createLargeThumbnail(argumentCollection=ARGUMENTS);
createMediumThumbnail(argumentCollection=ARGUMENTS);
createSmallThumbnail(argumentCollection=ARGUMENTS);
createMobileThumbnail(argumentCollection=ARGUMENTS);
return;
}
createProductThumbnails(ImageReadBase64(ARGUMENTS.ImageUpload));
Is there something that I need to do to initiate the garbage collection?
Appreciate your help!