Processing images

November 14, 2023

The Jahia Image Processing Service is here to manipulate images from Jahia itself. For licensing reasons, the service is, by default, using a Java native API named imageJ, but this is not a really powerful API nor really efficient.

So if you want to boost the quality of your thumbnails or the result of your other image manipulation operations, Jahia allows you to define the path to your ImageMagick installation so that we can use it instead of the imageJ API.

Installing ImageMagick

Follow the instructions for your system on Image Magick Binary Releases page.

Configuring ImageMagick

Modify your jahia.properties file to activate ImageMagick instead of the imageJ API.

######################################################################
### Image conversion Service #########################################
######################################################################
# The image service to use
# Native java service : "ImageJImageService"
# Set to "ImageMagickImageService" to use ImageMagick. You'll then have to set
# the imageMagick path
imageService = ImageJImageService
# The path to image magick and exiftools
# For windows : C:\\Programs\\ImageMagick;C:\\Programs\\exiftool
imageMagickPath = /usr/bin:/usr/local/bin:/opt/local/bin

Watch out for the path delimiter : on *NIX typically ":", on Windows ";".

Note: ImageMagick's default configuration may use up a lot of memory when processing images. In some environments, such as Docker containers, this may lead to problems such as containers shutting down because of resource limits. It is therefore recommended to limit the amount of memory allowed for processing by setting the following environment variables: export MAGICK_MEMORY_LIMIT=1GiB

Using the ImageService in your module

You can use the org.jahia.services.image.JahiaImageService API to manipulate your images.

try {
  jcrTemplate.doExecuteWithSystemSession(new JCRCallback<Object>() {
    public Object doInJCR(JCRSessionWrapper session) throws RepositoryException {
      try {
        JCRNodeWrapper node = session.getNode(path_first_image)
        Image src = imageService.getImage(node1);
        File resultFile = File.createTempFile("result", null);
        imageService.resizeImage(src,resultFile,100,100);
        InputStream fis = new BufferedInputStream(new FileInputStream(resultFile));
        try {
          node.getParent().uploadFile(result_image_node_name, fis,node.getFileContent().getContentType());
          session.save();
        } finally {
          IOUtils.closeQuietly(fis);
        }
      } catch (IOException e) {
        logger.error(e.getMessage(), e);
      } catch (InterruptedException e) {
        logger.error(e.getMessage(), e);
      }
      return null;
    }
  });
} catch (RepositoryException e) {
  logger.warn("Issue while blending two images : " + e.getMessage(), e);
}

Using the ImageMagick API directly

You can use all the power of ImageMagick scripting by using ImageMagick directly. Jahia uses im4java API to interact with ImageMagick. Here is an example to blend two images together.

final IMOperation operation = new IMOperation();
operation.blend(50);
operation.gravity("Center");
operation.addImage();
operation.addImage();
operation.addImage();
try {
  jcrTemplate.doExecuteWithSystemSession(new JCRCallback<Object>() {
    public Object doInJCR(JCRSessionWrapper session) throws RepositoryException {
      try {
        JCRNodeWrapper node1 = session.getNode(path_first_image)
        JCRNodeWrapper node2 = session.getNode(path_second_image);
        ImageMagickImage src1 = (ImageMagickImage) imageService.getImage(node1);
        ImageMagickImage src2 = (ImageMagickImage) imageService.getImage(node2);
        File resultFile = File.createTempFile("result", null);
        CompositeCmd cmd = new CompositeCmd();
        cmd.run(operation, src1.getFile().getAbsolutePath(),
                src2.getFile().getAbsolutePath(), resultFile.getAbsolutePath());
        InputStream fis = new BufferedInputStream(new FileInputStream(resultFile));
        try {
          node1.getParent().uploadFile(result_image_node_name, fis,node1.getFileContent().getContentType());
          session.save();
        } finally {
          IOUtils.closeQuietly(fis);
        }
      } catch (IOException e) {
        logger.error(e.getMessage(), e);
      } catch (InterruptedException e) {
        logger.error(e.getMessage(), e);
      } catch (IM4JavaException e) {
        logger.error(e.getMessage(), e);
      }
      return null;
    }
  });
} catch (RepositoryException e) {
  logger.warn("Issue while blending two images : " + e.getMessage(), e);
}