Generating thumbnails for images

In this section, we will introduce a way to generate thumbnails for images of extension .jpg, jpeg, and .png. We will create a class called ThumbnailCreator to take care of the thumbnail creation. Figure 13.5 shows its relationship with its dependency, ImageProcessor, which is responsible for the actual image resizing and retrieving the image's actual size:

Figure 13.5: ThumbnailCreator diagram

The following is how the create() method of ThumbnailCreator looks:

...
@Component
public class ThumbnailCreator {
...
public void create(FileStorage fileStorage, TempFile tempImageFile) {
Assert.isTrue(tempImageFile.getFile().exists(), "Image file `" +
tempImageFile.getFile().getAbsolutePath() + "` must exist");

String ext =
FilenameUtils.getExtension(tempImageFile.getFile().getName());
if (!SUPPORTED_EXTENSIONS.contains(ext)) {
throw new ThumbnailCreationException("Not supported image format
for creating thumbnail");
}
...
try {
...
String tempThumbnailFilePath =
ImageUtils.getThumbnailVersion(tempImageFile.getFile()
.getAbsolutePath());
Size resizeTo = getTargetSize(sourceFilePath);
imageProcessor.resize(sourceFilePath, tempThumbnailFilePath,
resizeTo);

fileStorage.saveTempFile(TempFile.create
(tempImageFile.tempRootPath(), Paths.get
(tempThumbnailFilePath)));
// Delete temp thumbnail file
Files.delete(Paths.get(tempThumbnailFilePath));
} catch (Exception e) {
log.error("Failed to create thumbnail for file `" +
tempImageFile.getFile().
getAbsolutePath() + "`", e);
throw new ThumbnailCreationException("Creating thumbnail failed",
e);
}
}
...
}

As you can see, in the beginning, we use assertion to make sure the source file, tempImageFile, exists on the server. Then we check whether we can support creating a thumbnail of the image by checking its extension, and we create the thumbnail's file path based on the source file by adding the .thumbnail part before the extension. For example, the source file path is /data/temp/image.jpg, so the thumbnail file path will be /data/temp/image.thumbnail.jpg.  

We will also need to get the size of the thumbnail that we will create by calling the getTargetSize() method, which calls the getSize() method of ImageProcessor to get the source image file's actual size, and then calculates the thumbnail's size. After that, we invoke the resize() method of ImageProcessor to create the thumbnail that is saved as a temporary image file. After the thumbnail is saved to the file storage, we delete the thumbnail temporary file.

Now, let's take a look at ImageProcessor. Currently, ImageProcessor is defined as a class that relies on GraphicMagick (http://www.graphicsmagick.org/) to do all the heavy lifting. We use the library, im4java, to bridge the call between Java and the GraphicMagick commands.

Here is how the resize() method of ImageProcessor looks:

...
@Component
public class ImageProcessor {
...
public void resize(String sourceFilePath, String targetFilePath, Size
resizeTo) throws Exception {
Assert.isTrue(resizeTo.getHeight() > 0, "Resize height must be
greater than 0");
Assert.isTrue(resizeTo.getWidth() > 0, "Resize width must be
greater than 0");

ConvertCmd cmd = new ConvertCmd(true);
cmd.setSearchPath(commandSearchPath);
IMOperation op = new IMOperation();
op.addImage(sourceFilePath);
op.quality(70d);
op.resize(resizeTo.getWidth(), resizeTo.getHeight());
op.addImage(targetFilePath);
cmd.run(op);
}
...
}

As you can see, all the resize() method does is to build a command similar to the following GraphicMagick convert command using im4java API:

gm convert -resize 300x185 -quality 70 source.jpg  source.thumbnail.jpg

The reason we need to set the search path of the ConvertCmd instance is because on Mac, when GraphicMagick is installed via Homebrew, the GraphicMagick command is in /usr/local/bin, rather than /usr/bin.

The following is how the getSize() method looks:

...
@Component
public class ImageProcessor {
...
public Size getSize(String imagePath) throws IOException {
try {
ImageCommand cmd = new ImageCommand();
cmd.setCommand("gm", "identify");
cmd.setSearchPath(commandSearchPath);

ArrayListOutputConsumer outputConsumer = new
ArrayListOutputConsumer();
cmd.setOutputConsumer(outputConsumer);

IMOperation op = new IMOperation();
op.format("%w,%h");
op.addImage(imagePath);
cmd.run(op);

List<String> cmdOutput = outputConsumer.getOutput();
String result = cmdOutput.get(0);
Assert.hasText(result, "Result of command `gm identify` must not
be blank");

String[] dimensions = result.split(",");
return new Size(NumberUtils.toInt(dimensions[0]),
NumberUtils.toInt(dimensions[1]));
} catch (Exception e) {
throw new IOException("Failed to get image's height/width", e);
}
}
}

As you can see, all the getSize() method does is to build a command similar to the following:

gm identify -format '%w,%h' image.jpg

This command uses the GraphicMagicks identify command to retrieve the image's basic information—width and height.

GraphicMagick is a very powerful tool. Due to the limited scope of this book, we're only touching the surface of its power here. You can find more about what GraphicMagick can do on its home page: http://www.graphicsmagick.org.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.158.36