Do you want your ad here?

Contact us to get your ad seen by thousands of users every day!

[email protected]

Dynamic watermarking on the JVM

  • July 09, 2024
  • 4953 Unique Views
  • 2 min read

Displaying images on your website makes for an interesting problem: on one side, you want to make them publicly available; on the other, you want to protect them against undue use. The age-long method to achieve it is watermarking:

A digital watermark is a kind of marker covertly embedded in a noise-tolerant signal such as audio, video or image data. It is typically used to identify ownership of the copyright of such signal. "Watermarking" is the process of hiding digital information in a carrier signal; the hidden information should, but does not need to, contain a relation to the carrier signal. Digital watermarks may be used to verify the authenticity or integrity of the carrier signal or to show the identity of its owners. It is prominently used for tracing copyright infringements and for banknote authentication.

-- Digital watermarking

The watermark can be visible to act as a deterrent to people stealing the image; alternatively, you can use it to prove its origin after it has been stolen.

However, if there are too many images on a site, it can be a burden to watermark them beforehand. It can be much simpler to watermark them dynamically. I searched for an existing JVM library dedicated to watermarking but surprisingly found nothing. We can achieve that in a Jakarata EE-based web app with the Java 2D API and a simple Filter.

The Java 2D API has been part of the JDK since 1.0, and it shows.

It translates into the following code:

private fun watermark(imageFilename: String): BufferedImage? {
    val watermark = ImageIO.read(ClassPathResource("/static/$imageFilename").inputStream) ?: return null //1
    val watermarker = ImageIO.read(ClassPathResource("/static/apache-apisix.png").inputStream) //2
    watermark.createGraphics().apply {                         //3
        drawImage(watermarker, 20, 20, 300, 300, null)         //4
        dispose()                                              //5
    }
    return watermark
}
  1. Get the original image
  2. Get the watermarking image
  3. Get the canvas of the original image
  4. Draw the watermark. I was too lazy to make it partially transparent
  5. Release system resources associated with this object

Other stacks may have dedicated libraries, such as photon-rs for Rust and WebAssembly. With this in place, we can move to the web part. As mentioned above, we need a Filter.

class WatermarkFilter : Filter {

    override fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
        val req = request as HttpServletRequest
        val imageFilename = req.servletPath.split("/").last()  //1
        val watermarked = watermark(imageFilename)             //2
        response.outputStream.use {
            ImageIO.write(watermarked, "jpeg", it)             //3
        }
    }
}
  1. Get the image filename
  2. Watermark the image
  3. Write the image in the response output stream

I explained how to watermark images on a Java stack in this post. I did the watermark manually because I didn't find any existing library. Next week, I'll show a no-code approach based on infrastructure components.

To go further:


Originally published at A Java Geek on June 30th, 2024

Take the State of Java 2026 Survey!

Share insights about how you're using Java... and win a Switch 2, plus get research results useful for making Java-related decisions in your organization.

Get Started

Dynamic watermarking with imgproxy and Apache APISIX

Let’s implement a watermarking feature with the help of imgproxy. The more I think about it, the more I think they make a match made in Heaven.

A Quick Glance at the Kubernetes Gateway API

The idea behind the Gateway API is to have a clean separation between standard objects and the proprietary implementation.

A Real-World Example of a Stream Collector

You can solve most use cases with one of the out-of-the-box collectors provided in the Collectors class.

However, some require to implement a custom Collector, e.g., when you need to collect more than a single collection or a single scalar.

While it may seem complicated if you never developed one before, it’s not. You only need a bit of practice.

I hope this article might help you with it!

A Tentative Comparison of Fault Tolerance Libraries on the JVM

If you’re implementing microservices or not, chances are that you’re calling HTTP endpoints. With HTTP calls, a lot of things can go wrong.

Alternatives to DTO

I believe that DTOs should be a thing of the past. Yet, it seems their usage is still widespread.

Do you want your ad here?

Contact us to get your ad seen by thousands of users every day!

[email protected]

Comments (0)

Highlight your code snippets using [code lang="language name"] shortcode. Just insert your code between opening and closing tag: [code lang="java"] code [/code]. Or specify another language.

No comments yet. Be the first.

Subscribe to foojay updates:

https://foojay.io/feed/
Copied to the clipboard