Integrate Hippo CMS with Cloudinary Imaging services 

Michiel Rop is a Solution Architect for   Professional Services at Hippo. He loves python and fractals and is an ardent sailor who also makes his own lamps. He   blogs and shares his code   here . Code for this lab and more useful information can be found in Github  here.

Various clients expressed the need for more advanced image manipulation possibilities in Hippo CMS. Hippo's pluggable architecture makes it possible to integrate external image manipulation tools. This post describes how to extend the Gallery Processor and how to let Cloudinary transform your images in Hippo CMS.

Cloudinary

Cloudinary is a software–as-a-service (SaaS) imaging solution hosted in the cloud. It provides an api for manipulating images via a REST-service. This lab requires a Cloudinary account. An account can be acquired at   http://cloudinary.com/. Their free plan will be sufficient to explore the basic functionalities.

The following image is taken from Hippo CMS. Here Cloudinary is used to created a thumbnail using face detection and to apply a "sepia" effect.

 

//onehippo-prod.global.ssl.fastly.net/binaries/ninecolumn/content/gallery/showcase.png

 

Try it yourself

 

  • Clone the demo project at   https://github.com/onehippo/labs/tree/master/cloudinary
  • build and run the project
  • create a   Cloudinary account
  • Open the cms of the running project
  • open the update editor perspective
  • enter your Cloudinary Cloud name, API Key and API Secret in the useCloudinaryGalleryProcessor groovy script ( see screenshot below )
  • save and run the script
  • log out of the cms and log in again for the services to reload
  • create an image using the image Gallery !!!

 

//onehippo-prod.global.ssl.fastly.net/binaries/ninecolumn/content/gallery/updateeditor.png

 

Deep dive

 

A service initializes the Cloudinary Singleton at login into the cms. The plugin uses the credentials supplied in the above mentioned groovy script.

 

CloudinaryService.java:

public class CloudinaryService extends Plugin {

    private static final Logger LOGGER = LoggerFactory.getLogger(CloudinaryService.class);
    public static final String CLOUD_NAME = "cloud_name";
    public static final String API_KEY = "api_key";
    public static final String API_SECRET = "api_secret";

    private Cloudinary cloudinary;

    public CloudinaryService(final IPluginContext context, final IPluginConfig config) {
        super(context, config);
        context.registerService(this, config.getString("cloudinary.service.id", CloudinaryService.class.getName()));
        init();
    }

    public Cloudinary getCloudinary() {
        return cloudinary;
    }

    private void init() {
        String cloudName = getPluginConfig().getString(CLOUD_NAME);
        String apiKey = getPluginConfig().getString(API_KEY);
        String apiSecret = getPluginConfig().getString(API_SECRET);

        if (StringUtils.isEmpty(cloudName)||StringUtils.isEmpty(apiKey)|| StringUtils.isEmpty(apiSecret)){
            LOGGER.warn("Cloudinary initialization parameters has not been set, "
                    + "Cloudinary can not be used. "
                    + "Please set the parameters cloud_name, api_key and api_secret");
        }

        cloudinary = new Cloudinary(Cloudinary.asMap(
                "cloud_name", cloudName,
                "api_key", apiKey,
                "api_secret", apiSecret));
    }
}

 

 

//onehippo-prod.global.ssl.fastly.net/binaries/ninecolumn/content/gallery/image-processing.png

After uploading the original image, each image variant is created using the properties defined on the subnodes of /hippo:configuration/hippo:frontend/cms/cms-services/cloudinaryGalleryProcessorService. With these properties a com.cloudinary.Transformation instance is created. As described on   http://cloudinary.com/documentation/java_integration a java.util.Map is returned containing all properties of the image. The "public_id" property is at least needed to generate the image URL. Using that URL the manipulated image is requested.  That variant is stored in the CMS. 

 

CloudinaryImageOperation.java:

 

upload = cloudinary.uploader().upload(tmpFile, Cloudinary.asMap(
        "transformation", transformation));

String format = getFormat();
if (StringUtils.isEmpty(format)) {
    format = (String) upload.get("format");
}

String url = cloudinary.url().format(format).generate((String) upload.get("public_id"));
scaledData = new URL(url).openStream();

Conclusion

This lab helps you tap into the extensive imaging capabilities of Cloudinary from within Hippo. It requires a Cloudinary subscription and server side access to Cloudinary. In this example images are still served from the CMS. This enables editors to use the default functionality for cropping and uploading a different version for image variants. 

The approach can be generalized: Use Hippo's modular architecture to connect to external services to modify content and possibly serve it from the cloud.