Skip to content

Instantly share code, notes, and snippets.

@eulereadgbe
Created October 5, 2017 06:27
Show Gist options
  • Save eulereadgbe/a642bfa2c883a3b0d34567f83995b994 to your computer and use it in GitHub Desktop.
Save eulereadgbe/a642bfa2c883a3b0d34567f83995b994 to your computer and use it in GitHub Desktop.
Mediafilter to create diagonal watermarks with Java
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.mediafilter;
import org.dspace.core.ConfigurationManager;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import static org.dspace.app.mediafilter.MediaFilterManager.getCurrentItem;
import javax.swing.ImageIcon;
/**
* Filter image bitstreams, scaling the image to be within the bounds of
* thumbnail.maxwidth, thumbnail.maxheight, the size we want our thumbnail to be
* no bigger than. Creates only JPEGs.
*
* @author Jason Sherman <jsherman@usao.edu>
*/
public class WaterMark extends MediaFilter
{
public String getFilteredName(String oldFilename)
{
return oldFilename + ".preview.jpg";
}
/**
* @return String bundle name
*
*/
public String getBundleName()
{
return "WATERMARK_PREVIEW";
}
/**
* @return String bitstreamformat
*/
public String getFormatString()
{
return "JPEG";
}
/**
* @return String description
*/
public String getDescription()
{
return "Generated Watermarked Preview";
}
/**
* @param source
* source input stream
*
* @return InputStream the resulting input stream
*/
public InputStream getDestinationStream(InputStream source)
throws Exception
{
// read in bitstream's image
BufferedImage buf = ImageIO.read(source);
// get config params
float xmax = (float) ConfigurationManager
.getIntProperty("webui.preview.maxwidth");
float ymax = (float) ConfigurationManager
.getIntProperty("webui.preview.maxheight");
boolean blurring = (boolean) ConfigurationManager
.getBooleanProperty("webui.preview.blurring");
boolean hqscaling = (boolean) ConfigurationManager
.getBooleanProperty("webui.preview.hqscaling");
int brandHeight = ConfigurationManager.getIntProperty("webui.preview.brand.height");
String brandFont = ConfigurationManager.getProperty("webui.preview.brand.font");
int brandFontPoint = ConfigurationManager.getIntProperty("webui.preview.brand.fontpoint");
String waterMarkLabel = ConfigurationManager.getProperty("webui.preview.watermark");
// now get the image dimensions
float xsize = (float) buf.getWidth(null);
float ysize = (float) buf.getHeight(null);
// if verbose flag is set, print out dimensions
// to STDOUT
if (MediaFilterManager.isVerbose)
{
System.out.println("original size: " + xsize + "," + ysize);
}
// scale by x first if needed
if (xsize > xmax)
{
// calculate scaling factor so that xsize * scale = new size (max)
float scaleFactor = xmax / xsize;
// if verbose flag is set, print out extracted text
// to STDOUT
if (MediaFilterManager.isVerbose)
{
System.out.println("x scale factor: " + scaleFactor);
}
// now reduce x size
// and y size
xsize = xsize * scaleFactor;
ysize = ysize * scaleFactor;
// if verbose flag is set, print out extracted text
// to STDOUT
if (MediaFilterManager.isVerbose)
{
System.out.println("new size: " + xsize + "," + ysize);
}
}
// scale by y if needed
if (ysize > ymax)
{
float scaleFactor = ymax / ysize;
// now reduce x size
// and y size
xsize = xsize * scaleFactor;
ysize = ysize * scaleFactor;
}
// if verbose flag is set, print details to STDOUT
if (MediaFilterManager.isVerbose)
{
System.out.println("created thumbnail size: " + xsize + ", "
+ ysize);
}
// create an image buffer for the preview with the new xsize, ysize
// we add
BufferedImage branded = new BufferedImage((int) xsize, (int) ysize + brandHeight,
BufferedImage.TYPE_INT_RGB);
// Use blurring if selected in config.
// a little blur before scaling does wonders for keeping moire in check.
if (blurring)
{
// send the buffered image off to get blurred.
buf = getBlurredInstance((BufferedImage) buf);
}
// Use high quality scaling method if selected in config.
// this has a definite performance penalty.
if (hqscaling)
{
// send the buffered image off to get an HQ downscale.
buf = getScaledInstance((BufferedImage) buf, (int) xsize, (int) ysize,
(Object) RenderingHints.VALUE_INTERPOLATION_BICUBIC, (boolean) true);
}
// now render the image into the preview buffer
//Graphics2D g2d = branded.createGraphics();
//g2d.drawImage(buf, 0, 0, (int) xsize, (int) ysize, null);
//Brand brand = new Brand((int) xsize, brandHeight, new Font(brandFont, Font.PLAIN, brandFontPoint), 5);
//BufferedImage brandImage = brand.create(ConfigurationManager.getProperty("webui.preview.brand"),
// ConfigurationManager.getProperty("webui.preview.brand.abbrev"),
// MediaFilterManager.getCurrentItem() == null ? "" : "hdl:" + MediaFilterManager.getCurrentItem().getHandle());
String watermark = waterMarkLabel;
ImageIcon photo = new ImageIcon(buf);
BufferedImage bufferedImage = new BufferedImage(buf.getWidth(),
buf.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D)bufferedImage.getGraphics();
g2d.drawImage(photo.getImage(), 0, 0, null);
//Create an alpha composite of 60%
AlphaComposite alpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f);
g2d.setComposite(alpha);
g2d.setColor(Color.white);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// Move our origin to the center
g2d.translate(photo.getIconWidth() / 2.0f, photo.getIconHeight() / 2.0f);
//Font f1 = new Font("Arial", Font.BOLD, 24);
Font f1 = new Font(brandFont, Font.BOLD, brandFontPoint);
g2d.setFont(f1);
FontMetrics fontMetrics = g2d.getFontMetrics();
Rectangle2D rect = fontMetrics.getStringBounds(watermark, g2d);
// Create a rotation transform to rotate the text based on the diagonal
// angle of the picture aspect ratio
AffineTransform at2 = new AffineTransform();
double opad = photo.getIconHeight() / (double)photo.getIconWidth();
double angle = Math.toDegrees(Math.atan(opad));
double idegrees = -1 * angle;
double theta = (2 * Math.PI * idegrees) / 360;
at2.rotate(theta);
g2d.transform(at2);
//Now reposition our coordinates based on size (same as we would normally
//do to center on straight line but based on starting at center
float x1 = (int)rect.getWidth() / 2.0f *-1;
float y1 = (int)rect.getHeight() / 2.0f;
g2d.translate(x1, y1);
//finally let's draw the string
g2d.drawString(watermark, 0.0f, 0.0f);
//Free graphic resources
g2d.dispose();
// now create an input stream for the thumbnail buffer and return it
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "jpeg", baos);
// now get the array
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
return bais; // hope this gets written out before its garbage collected!
}
public BufferedImage getNormalizedInstance(BufferedImage buf)
{
int type = (buf.getTransparency() == Transparency.OPAQUE) ?
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB_PRE;
int w, h;
w = buf.getWidth();
h = buf.getHeight();
BufferedImage normal = new BufferedImage(w, h, type);
Graphics2D g2d = normal.createGraphics();
g2d.drawImage(buf, 0, 0, w, h, Color.WHITE, null);
g2d.dispose();
return normal;
}
public BufferedImage getBlurredInstance(BufferedImage buf)
{
/**
* Convenience method that returns a blurred instance of the
* provided {@code BufferedImage}.
*
*/
buf = getNormalizedInstance(buf);
// kernel for blur op
float[] matrix = {
0.111f, 0.111f, 0.111f,
0.111f, 0.111f, 0.111f,
0.111f, 0.111f, 0.111f,
};
// perform the blur and return the blurred version.
BufferedImageOp blur = new ConvolveOp( new Kernel(3, 3, matrix) );
BufferedImage blurbuf = blur.filter(buf, null);
return blurbuf;
}
/**
* Convenience method that returns a scaled instance of the
* provided {@code BufferedImage}.
*
* @param buf the original image to be scaled
* @param targetWidth the desired width of the scaled instance,
* in pixels
* @param targetHeight the desired height of the scaled instance,
* in pixels
* @param hint one of the rendering hints that corresponds to
* {@code RenderingHints.KEY_INTERPOLATION} (e.g.
* {@code RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR},
* {@code RenderingHints.VALUE_INTERPOLATION_BILINEAR},
* {@code RenderingHints.VALUE_INTERPOLATION_BICUBIC})
* @param higherQuality if true, this method will use a multi-step
* scaling technique that provides higher quality than the usual
* one-step technique (only useful in downscaling cases, where
* {@code targetWidth} or {@code targetHeight} is
* smaller than the original dimensions, and generally only when
* the {@code BILINEAR} hint is specified)
* @return a scaled version of the original {@code BufferedImage}
*/
public BufferedImage getScaledInstance(BufferedImage buf,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality)
{
int type = (buf.getTransparency() == Transparency.OPAQUE) ?
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage scalebuf = (BufferedImage)buf;
int w, h;
if (higherQuality) {
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = buf.getWidth();
h = buf.getHeight();
} else {
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2d = tmp.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2d.drawImage(scalebuf, 0, 0, w, h, Color.WHITE, null);
g2d.dispose();
scalebuf = tmp;
} while (w != targetWidth || h != targetHeight);
return scalebuf;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment