Added image utilities

This commit is contained in:
nathan 2017-05-10 15:20:59 +02:00
parent 8a529731b7
commit bec29c4cd3
1 changed files with 219 additions and 0 deletions

View File

@ -0,0 +1,219 @@
/*
* Copyright 2016 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.swing.ImageIcon;
@SuppressWarnings("WeakerAccess")
public
class ImageUtil {
/**
* Resizes the image, as either a a FILE on disk, or as a RESOURCE name, and saves the new size as a file on disk. This new file will
* replace any other file with the same name.
*
* @return the file string on disk that is the resized icon
*/
public static
String resizeFileOrResource(final int sizeWidth, final String fileName) throws IOException {
FileInputStream fileInputStream = new FileInputStream(fileName);
Dimension imageSize = getImageSize(fileInputStream);
//noinspection NumericCastThatLosesPrecision
if (sizeWidth == ((int) imageSize.getWidth())) {
// we can reuse this file.
return fileName;
}
// have to resize the file (and return the new path)
String extension = FileUtil.getExtension(fileName);
if (extension.isEmpty()) {
extension = "png"; // made up
}
// now have to resize this file.
File newFile = new File(FileUtil.TEMP_DIR, "temp_resize." + extension).getAbsoluteFile();
Image image;
// is file sitting on drive
File iconTest = new File(fileName);
if (iconTest.isFile() && iconTest.canRead()) {
final String absolutePath = iconTest.getAbsolutePath();
// resize the image, keep aspect
image = new ImageIcon(absolutePath).getImage().getScaledInstance(sizeWidth, -1, Image.SCALE_SMOOTH);
image.flush();
}
else {
// suck it out of a URL/Resource (with debugging if necessary)
final URL systemResource = LocationResolver.getResource(fileName);
// resize the image, keep aspect
image = new ImageIcon(systemResource).getImage().getScaledInstance(sizeWidth, -1, Image.SCALE_SMOOTH);
image.flush();
}
// have to do this twice, so that it will finish loading the image (weird callback stuff is required if we don't do this)
image = new ImageIcon(image).getImage();
image.flush();
// make whatever dirs we need to.
boolean mkdirs = newFile.getParentFile()
.mkdirs();
if (!mkdirs) {
throw new IOException("Unable to create directories for " + newFile.getParentFile());
}
// if it's already there, we have to delete it
boolean delete = newFile.delete();
if (!delete) {
throw new IOException("Temporary file already in use, cannot delete it " + newFile);
}
// now write out the new one
BufferedImage bufferedImage = getBufferedImage(image);
ImageIO.write(bufferedImage, extension, newFile);
return newFile.getAbsolutePath();
}
@SuppressWarnings("ResultOfMethodCallIgnored")
public static
File getTransparentImage(final int size, final File fileToUse) throws IOException {
if (fileToUse.canRead() && fileToUse.isFile()) {
return fileToUse;
}
// make sure the directory exists
fileToUse.getParentFile().mkdirs();
final BufferedImage image = getTransparentImageAsBufferedImage(size);
ImageIO.write(image, "png", fileToUse);
return fileToUse;
}
@SuppressWarnings("WeakerAccess")
public static
BufferedImage getTransparentImageAsBufferedImage(final int size) {
final BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = image.createGraphics();
g2d.setColor(new Color(0, 0, 0, 0));
g2d.fillRect(0, 0, size, size);
g2d.dispose();
return image;
}
/**
* @return the image as a Buffered Image
*/
public static
BufferedImage getBufferedImage(Image image) {
if (image instanceof BufferedImage) {
return (BufferedImage) image;
}
BufferedImage bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D bGr = bimage.createGraphics();
bGr.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY));
bGr.drawImage(image, 0, 0, null);
bGr.dispose();
// Return the buffered image
return bimage;
}
/**
* Reads the image size information from the specified file, without loading the entire file.
*
* @param fileStream the input stream of the file
*
* @return the image size dimensions. IOException if it could not be read
*/
public static
Dimension getImageSize(InputStream fileStream) throws IOException {
ImageInputStream in = null;
ImageReader reader = null;
try {
// This will ONLY work for File, InputStream, and RandomAccessFile
in = ImageIO.createImageInputStream(fileStream);
final Iterator<ImageReader> readers = ImageIO.getImageReaders(in);
if (readers.hasNext()) {
reader = readers.next();
reader.setInput(in);
return new Dimension(reader.getWidth(0), reader.getHeight(0));
}
} finally {
// `ImageInputStream` is not a closeable in 1.6, so we do this manually.
if (in != null) {
try {
in.close();
} catch (IOException ignored) {
}
}
if (reader != null) {
reader.dispose();
}
}
throw new IOException("Unable to read file inputStream for image size data.");
}
/**
* Because of the way image loading works in Java, if one wants to IMMEDIATELY get a fully loaded image, one must resort to "hacks"
* by loading the image twice.
*
* @param image the image you want load immediately
*
* @return a fully loaded image
*/
public static
Image getImageImmediate(final Image image) {
// have to do this twice, so that it will finish loading the image (weird callback stuff is required if we don't do this)
image.flush();
final Image loadedImage = new ImageIcon(image).getImage();
loadedImage.flush();
return loadedImage;
}
}