resizing animated GIF while keeping it's animation using java - java

i am using Graphics2D in java to resize images, it works perfect with jpg,png and other formats.
my problem is the animated GIF images, after re-sizing the animation is gone!
here is the method am using:
private BufferedImage doResize(int newWidth, int newHeight, double scaleX,
double scaleY, BufferedImage source) {
GraphicsConfiguration gc = getDefaultConfiguration();
BufferedImage result = gc.createCompatibleImage(newWidth, newHeight, source.getColorModel().getTransparency());
Graphics2D g2d = null;
try {
g2d = result.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.scale(scaleX, scaleY);
g2d.drawImage(source, 0, 0, null);
} finally {
if (g2d != null) {
g2d.dispose();
}
}
return result;
}
so, any clues how can i keep on the animated gif after re-sizing?
Thanks.

So I know this is old but I found a solution, I am using Java 8 not sure if it will work with other versions.
ImageIcon image = ? (whatever/wherever your gif is)
int width = 100;
int height = 100;
image.setImage(image.getImage().getScaledInstance(width, height, Image.SCALE_DEFAULT));
you can change SCALE_DEFAULT to the ones listed here except for SCALE_SMOOTH and SCALE_AREA_AVREAGING didn't work for me, it was blank
https://docs.oracle.com/javase/7/docs/api/java/awt/Image.html

I found two sources which when combined can be used to resize the image while keeping the animation.
On this question (
Convert each animated GIF frame to a separate BufferedImage ) look for the answer by Alex Orzechowski. His code takes a gif file and converts it to an array of ImageFrames (which is a class he made which wraps a BufferedImage). Then look at this code which converts a sequence of BufferedImages to a gif file
( http://elliot.kroo.net/software/java/GifSequenceWriter/ ).
As you could probably guess, all you need to do is upload the gif, use Alex's code to convert it to an array of ImageFiles/BufferedImages, use your Graphics2D code to resize each frame (you'll need to add a setImage method to Alex's ImageFrame class), then use Elliot's code to convert the array to a gif! Here is what mine looks like:
public static void main( String[] args )
{
try {
File imageFile = new File( "InputFile" );
FileInputStream fiStream = new FileInputStream( imageFile );
ImageFrame[] frames = readGif( fiStream );
for( int i = 0; i < frames.length; i++ ){
//code to resize the image
BufferedImage image = ImageUtilities.resizeImage( frames[ i ].getImage(), newWidth, newHeight);
frames[ i ].setImage( image );
}
ImageOutputStream output =
new FileImageOutputStream( new File( "OutputFile" ) );
GifSequenceWriter writer =
new GifSequenceWriter( output, frames[0].getImage().getType(), frames[0].getDelay(), true );
writer.writeToSequence( frames[0].getImage() );
for ( int i = 1; i < frames.length; i++ ) {
BufferedImage nextImage = frames[i].getImage();
writer.writeToSequence( nextImage );
}
writer.close();
output.close();
}
catch ( FileNotFoundException e ) {
System.out.println( "File not found" );
}
catch ( IOException e ) {
System.out.println( "IO Exception" );
}
}
This code, however, does not account for gif images with different amount of time elapsing between frames.

Jonny March's solution did not work for me because it processes and outputs only the first image of GIF file.
Here is my solution, it keeps the animation while resizing.
File f = new File("path of your animated gif");
URL img = f.toURL();
ImageIcon icon = new ImageIcon(img);
//You have to convert it to URL because ImageIO just ruins the animation
int width = 100;
int height = 100;
icon.setImage(icon.getImage().getScaledInstance(width, height,Image.SCALE_DEFAULT));

BufferedImage origBuffImg = ImageIO.read(orignalImage);
int type = origBuffImg.getType() == 0? BufferedImage.TYPE_INT_ARGB : origBuffImg.getType();
BufferedImage resizedBuffImg = new BufferedImage(width, height, type);
Graphics2D g = resizedBuffImg.createGraphics();
g.drawImage(origBuffImg, 0, 0, width, height, null);
g.dispose();
String newFile = orignalImage.getAbsolutePath().substring(0,orignalImage.getAbsolutePath().lastIndexOf("."))+"_"+width+"x"+height+"."+extension;
ImageIO.write(resizedBuffImg, extension, new File(newFile));
System.out.println("File created : "+newFile);

Related

Apache POI - PPTX to PNG skewing text and shapes

I'm currently using Apache POI 3.16 to take a PPTX slide deck and transform it into a set of .png thumbnails. I modeled my PPTX to PNG function closely off of a few pre-made solutions I found across the web.
I'm having issues primarily with text being rendered about 6-8pt larger in the resulting PNGs. Additionally, complex shapes such as hexagons are extremely skewed when being rendered. Can anyone suggest any fixes? I'm mostly concerned with the font sizes being much larger.
Here is my code, commented for readability:
public List<String> generatePNGThumbnails(String inputFilePath) {
// List of the thumbnail paths that will be returned.
ArrayList<String> thumbnailFilePaths = new ArrayList<>();
// Open the file.
File inputFile = new File(inputFilePath);
try {
// Open the PPTX as an XMLSlideShow.
XMLSlideShow slideShow = new XMLSlideShow(OPCPackage.open(inputFile));
// Output size for rendered images.
Dimension pageSize = slideShow.getPageSize();
int width = (int)(pageSize.width * TRANSFORMATION_SCALE);
int height = (int)(pageSize.height * TRANSFORMATION_SCALE);
// Get a list of the slides in the PPTX.
List<XSLFSlide> slides = slideShow.getSlides();
for (int i = 0; i < slides.size(); i++) {
XSLFSlide slide = slides.get(i);
// Create a new image object and prepare it for rendering.
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = img.createGraphics();
// Set graphics rendering options and draw the PPTX slide to the image.
graphics.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
);
graphics.setRenderingHint(
RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY
);
graphics.setRenderingHint(
RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY
);
graphics.setRenderingHint(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC
);
graphics.setRenderingHint(
RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON
);
graphics.setRenderingHint(
RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY
);
graphics.setColor(Color.white);
graphics.clearRect(0, 0, width, height);
graphics.scale(TRANSFORMATION_SCALE, TRANSFORMATION_SCALE);
// Draw the slide to the 2DGraphics.
slide.draw(graphics);
// Save the newly created image to the local disk.
String slideFileName = "slide" + i + ".pptx";
FileOutputStream fileOutputStream = new FileOutputStream(slideFileName);
ImageIO.write(img, "png", fileOutputStream);
// Add the output file path to the list of paths to be returned.
thumbnailFilePaths.add(slideFileName);
// Clean up before proceeding to the next slide.
graphics.dispose();
img.flush();
fileOutputStream.close();
}
} catch (InvalidFormatException | IOException e) {
// ...
}
}

Image quality reduces (turns reddish) as JPEG with BufferedImage

I am making a program where I extract out pixel array from an image, Take out ARGB values. And write them back again to make another image.
BufferedImage imagebuffer = ImageIO.read(new File("C:\\Users\\Ramandeep\\Downloads\\w3.jpg"));
iw = imagebuffer.getWidth();
ih = imagebuffer.getHeight();
pixels = new int[iw * ih];
PixelGrabber pg = new PixelGrabber(imagebuffer, 0, 0, iw, ih, pixels, 0, iw);
pg.grabPixels();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
image.setRGB(0, 0, width, height, pixels, 0, width);
ImageIO.write(image, "jpg", new File("C:\\Users\\Ramandeep\\Desktop\\out.jpg"));
ImageIO.write(image, "gif", new File("C:\\Users\\Ramandeep\\Desktop\\out.gif"));
ImageIO.write(image, "png", new File("C:\\Users\\Ramandeep\\Desktop\\out.png"));
Now output image for png and gif look fine but the output jpg image turns out quite reddish.
This is the original image
And this is the output jpg image
Any idea what might be causing this? Any push towards the right direction will be appreciated.
I dont know if this will work for you, but I always did it pixel-by-pixel.
So :
BufferedImage imagebuffer = ImageIO.read(new File("C:\\Users\\Ramandeep\\Downloads\\w3.jpg"));
iw = imagebuffer.getWidth();
ih = imagebuffer.getHeight();
BufferedImage image = new BufferedImage(iw,ih,BufferedImage.TYPE_INT_ARGB);
for (int x=0; x < iw; x++) {
for (int y=0; y < ih; y++) {
image.setRGB(x,y,imagebuffer.getRGB(x,y));
}
}
ImageIO.write(image, "jpg", new File("C:\\Users\\Ramandeep\\Desktop\\out.jpg"));
ImageIO.write(image, "gif", new File("C:\\Users\\Ramandeep\\Desktop\\out.gif"));
ImageIO.write(image, "png", new File("C:\\Users\\Ramandeep\\Desktop\\out.png"));
And it this way has a similar count of lines, so I think you could give it a try.
If you'd like to insert text, id ìmport java.awt.*;, what includes Graphics and Graphics2D and Font, and then :
Font font=new Font("Sans,0,20); //Name, type(none, bold, italic), size
Graphics2D imagegraphics=imagebuffer.createGraphics();
imagegraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); //enable antialiasing
imagegraphics.setFont(font);
imagegraphics.setColor(Color.BLACK);
String yourtext="Fighter";
int h=imagegraphics.getFontMetrics().getHeight();
int w=imagegraphics.getFontMetrics().stringWidth(yourtext);
imagegraphics.drawString(yourtext,5,h); //Draw text upper left corner, note that y-value is the bottom line of the string
EDIT :
It was the Alpha value. Fixed by :
BufferedImage image = new
BufferedImage(iw,ih,BufferedImage.TYPE_INT_RGB); //RGB, jpeg hasnt got alpha, ints have been converted as if they contain red first, but its alpha(the first bytes, these ints are interpreted bitwise i think) (argb), so it became more red.

Convert color image into black and white using java created from scratch

I want to convert my picture from colored to Black and white which seems to be created from scratch.
Here is the code which i tried as described on the different post:
BufferedImage bi = ImageIO.read(new File("/Users/***/Documents/Photograph.jpg"));
ColorConvertOp op =
new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
ImageIO.write(bi, "PNG", new File("/Users/bng/Documents/rendered2.png"));
op.filter(bi, bi);
But still my image is not converted to the Black and white. Additionally, this code is increasing the rendered2.png image size to 10 folds.
Also, it would be great if i could find some Java 8 way of doing this.
Any suggestions?
Here is the code which worked for me:
BufferedImage input = ImageIO.read(new File("/Users/bng/Documents/Photograph.jpg"));
// Create a black-and-white image of the same size.
BufferedImage im = new BufferedImage(input.getWidth(), input.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
// Get the graphics context for the black-and-white image.
Graphics2D g2d = im.createGraphics();
// Render the input image on it.
g2d.drawImage(input, 0, 0, null);
// Store the resulting image using the PNG format.
ImageIO.write(im, "PNG", new File("/Users/bng/Documents/rendered.png"));
It was BufferedImage.TYPE_BYTE_BINARY which provided me the exact solution.
Lokking for the Java 8 Version for above code.
You have to find RGB of the existing colors of the image you want to change it.
Fyi, you want to change it as white RGB value is (255,255,255) and for black RGB value is (0,0,0)
Following method easily do the color change if you apply correct way of your requirement
private BufferedImage changeColor(BufferedImage image, int srcColor, int replaceColor)
{
BufferedImage destImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = destImage.createGraphics();
g.drawImage(image, null, 0, 0);
g.dispose();
for (int width = 0; width < image.getWidth(); width++)
{
for (int height = 0; height < image.getHeight(); height++)
{
if (destImage.getRGB(width, height) == srcColor)
{
destImage.setRGB(width, height, replaceColor);
}
}
}
return destImage;
}
you have to use the ColorConvertOp in a proper way:
create Source image
apply filter
save dest
example:
BufferedImage src = ImageIO.read(new File("/Users/***/Documents/Photograph.jpg"));
ColorConvertOp op =
new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
BufferedImage dest = op.filter(src, null);
ImageIO.write(dest, "PNG", new File("/Users/bng/Documents/rendered2.png"));
src:
dest:

Find format of clipboard image in Java

I'm getting images from clipboard using this:
if(Toolkit.getDefaultToolkit().getSystemClipboard().isDataFlavorAvailable(DataFlavor.imageFlavor)){
ImageIcon IMG = new ImageIcon((BufferedImage) Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.imageFlavor));
}
Now I want to save this image in disk using ImageIO.write;
How can I find image format (JPG,PNG,GIF,...) to use in ImageIO.write as formatName ?
Thanks
The mime type of the content of the clipboard when checked via
.isDataFlavorAvailable(DataFlavor.imageFlavor)
is image/x-java-image (but OS vendors do not need to follow MIME types for clipboards).
I found two ways to supposedly get an image from a clipboard and write it to a file:
Using a helper method found in this blog post: The nightmares of getting images from the Mac OS X clipboard using Java.
Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard()
ImageIcon IMG = new ImageIcon((BufferedImage)
clip.getData(DataFlavor.imageFlavor));
BufferedImage bImage = getBufferedImage(IMG.getImage());
ImageIO.write(bImage, "png", new File("/tmp/test.png"));
The getBufferedImage method looks like this:
public static BufferedImage getBufferedImage(Image img) {
if (img == null) {
return null;
}
int w = img.getWidth(null);
int h = img.getHeight(null);
// draw original image to thumbnail image object and
// scale it to the new size on-the-fly
BufferedImage bufimg = new BufferedImage(w, h,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = bufimg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(img, 0, 0, w, h, null);
g2.dispose();
return bufimg;
}
Via Transferable. Note that this runs on OS X but produces an empty image of the correct size:
Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard()
Transferable content =
clip.getContents(null);
BufferedImage img = (BufferedImage) content.getTransferData(
DataFlavor.imageFlavor);
ImageIO.write(img, "png", new File("/tmp/test.png"));

What's wrong with my java code to rotate a jpeg photo?

I simply want to enable the user of my web site to change the orientation of a submitted photo from horizontal to vertical. Here's my code:
public static final void rotatePhoto(String jpgFilename){
BufferedImage originalImage = null, newImage=null;
try{
File file = new File(jpgFilename);
originalImage = ImageIO.read(file);
System.out.println("Photo.rotatePhoto(" +jpgFilename +") originalImage.getWidth(null)=" +originalImage.getWidth(null) +" originalImage.getHeight(null)=" +originalImage.getHeight(null) );
java.awt.image.AffineTransformOp opRotated = new java.awt.image.AffineTransformOp( java.awt.geom.AffineTransform.getQuadrantRotateInstance(1), null );
newImage = opRotated.createCompatibleDestImage(originalImage, originalImage.getColorModel());
opRotated.filter(originalImage, newImage);
}catch (IOException e){
}
/// Write result to file::::::::::::::::::::::::::::::::::::::::::::::::::::
try{
File outputfile = new File(testFilename);
ImageIO.write(newImage, "jpg", outputfile);
}catch(IOException ioE){
}
}
Problem is I get this error even though the System.out.println shows the width and height to be 640x480
java.awt.image.RasterFormatException: Transformed width (0) is less than or equal to 0.
java.awt.image.AffineTransformOp.createCompatibleDestImage(AffineTransformOp.java:447)
base.Photo.rotatePhoto(Photo.java:135)
base.ProcessContent.handleInput(ProcessContent.java:245)
servlets.ProcessServlet.doPost(ProcessServlet.java:74)
servlets.ProcessServlet.doGet(ProcessServlet.java:33)
javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
Any ideas or workarounds?
Try creating a new AffineTransform from scratch and using it in your AffineTransformOp constructor:
AffineTransform tx = new AffineTransform();
tx.rotate(Math.PI / 2, originalImage.getWidth() / 2, originalImage.getHeight() / 2);
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
newImage = op.filter(originalImage, newImage);
You also have to make sure newImage contains the data returned by the filter() method.
Oddly enough, this will only work when you set the formatName in ImageIO.write() to "png". I tried using jpg and the result was a black picture.
By using: AffineTransform.getQuadrantRotateInstance(1);
Your AffineTransform is rotating by a positive number of quadrants by axis. That will mess up the Transform Operation since it depends on the x and y, whenever it creates the compatible image.
int w = r.x + r.width;
int h = r.y + r.height;
if (w <= 0) {
throw new RasterFormatException("Transformed width ("+w+
") is less than or equal to 0.");
}
I would recommend doing it yourself:
public final void rotatePhoto(String jpgFilename) throws IOException {
File file = new File(jpgFilename);
BufferedImage originalImage = ImageIO.read(file);
// You could use Math.PI / 2, depends on your input.
AffineTransform affineTransform = new AffineTransform();
affineTransform.rotate(Math.toRadians(90), originalImage.getWidth() / 2, originalImage.getHeight() / 2);
// Now lets make that transform an operation, and we use it.
AffineTransformOp opRotated = new AffineTransformOp(affineTransform, AffineTransformOp.TYPE_BILINEAR);
BufferedImage newImage = opRotated.filter(originalImage, null);
// Save the image.
File outputfile = new File("rotated.jpg");
ImageIO.write(newImage, "jpg", outputfile);
}
UPDATE: Btw, it has been answered before on How do I write a servlet which rotates images?

Categories