com.intellisrc.img.FileImgTools.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of img Show documentation
Show all versions of img Show documentation
Classes for using Images (BufferedImage, File, FrameShot) and non-opencv related code, trying to keep dependencies to a minimum. It also includes common geometric operations.
The newest version!
package com.intellisrc.img
import com.intellisrc.core.Log
import com.intellisrc.etc.Mime
import groovy.transform.CompileStatic
import net.coobird.thumbnailator.Thumbnails
import net.coobird.thumbnailator.geometry.Positions
import javax.imageio.ImageIO
import javax.imageio.ImageReader
import javax.imageio.stream.ImageInputStream
import java.awt.image.BufferedImage
/**
* @since 18/11/20.
*/
@CompileStatic
class FileImgTools {
static class Size {
int width
int height
}
/**
* Return size of an image based only in image headers (much faster than using ImageIO.read)
* @param image
* @return
*/
static Size getSize(File image) {
int width = 0
int height = 0
String mime = Mime.getType(image)
if(Mime.isImage(mime)) {
InputStream is = new FileInputStream(image)
ImageInputStream imageInputStream = ImageIO.createImageInputStream(is)
try {
ImageReader reader = ImageIO.getImageReadersByMIMEType(mime).next()
reader.setInput(imageInputStream, true)
width = reader.getWidth(0)
height = reader.getHeight(0)
reader.dispose()
} catch (Exception e) {
Log.w("Unable to get image size: ", e)
} finally {
imageInputStream.close()
is.close()
}
} else {
Log.w("File [%s] doesn't seems to be an image (based on mime type)", image)
}
return new Size(
width: width,
height: height
)
}
/**
* Get Format to convert to
* @param imgOut
* @return
*/
protected static String getFormat(File imgOut) {
String mime = Mime.getType(imgOut)
return Mime.isImage(mime) ? mime.replaceAll('image/', "") : 'jpg'
}
/**
* Resize images without cropping
* @param imgIn
* @param imgOut
* @param size
* @return
*/
static boolean resize(File imgIn, File imgOut, int size, format = 'auto') {
String outFormat = format == "auto" ? getFormat(imgOut) : format
Thumbnails.of(imgIn).size(size, size).outputFormat(outFormat).toFile(imgOut)
return imgOut.exists()
}
/**
* Resize images centering on the image and cropping extra parts
* @param imgIn
* @param imgOut
* @param size
* @return
*/
static boolean resizeCentered(File imgIn, File imgOut, int size, format = 'auto') {
String outFormat = format == "auto" ? getFormat(imgOut) : format
Thumbnails.of(imgIn).size(size, size).crop(Positions.CENTER).outputFormat(outFormat).toFile(imgOut)
return imgOut.exists()
}
/**
* Resize images and crop without centering (keeping 0,0)
* @param imgIn
* @param imgOut
* @param size
* @return
*/
static boolean resizeTopLeft(File imgIn, File imgOut, int size, format = 'auto') {
String outFormat = format == "auto" ? getFormat(imgOut) : format
Thumbnails.of(imgIn).size(size, size).crop(Positions.TOP_LEFT).outputFormat(outFormat).toFile(imgOut)
return imgOut.exists()
}
/**
* Resize images and crop based on Width
* @param imgIn
* @param imgOut
* @param size
* @return
*/
static boolean resizeWidth(File imgIn, File imgOut, int size, format = 'auto') {
String outFormat = format == "auto" ? getFormat(imgOut) : format
Thumbnails.of(imgIn).width(size).outputFormat(outFormat).toFile(imgOut)
return imgOut.exists()
}
/**
* Resize images and crop based on Height
* @param imgIn
* @param imgOut
* @param size
* @return
*/
static boolean resizeHeight(File imgIn, File imgOut, int size, format = 'auto') {
String outFormat = format == "auto" ? getFormat(imgOut) : format
Thumbnails.of(imgIn).height(size).outputFormat(outFormat).toFile(imgOut)
return imgOut.exists()
}
/**
* Rotate image from file and save to file
* @param imgIn
* @param imgOut
* @param rotate
* @return
*/
static boolean rotate(File imgIn, File imgOut, int rotate) {
if(imgOut.exists()) {
imgOut.delete()
}
if(imgIn.exists()) {
BufferedImage image = Converter.FileToBuffered(imgIn)
BufferedImage rotated = BuffImgTools.rotate(image, rotate)
Converter.BufferedToFile(rotated, imgOut)
}
return imgOut.exists()
}
/**
* Crop an image and save it in a file
* @param imgIn
* @param imgOut
* @param x
* @param y
* @param width
* @param height
* @return
*/
static boolean crop(File imgIn, File imgOut, int x, int y, int width, int height) {
if(imgOut.exists()) {
imgOut.delete()
}
if(imgIn.exists()) {
BufferedImage image = Converter.FileToBuffered(imgIn)
BufferedImage rotated = BuffImgTools.crop(image, x, y, width, height)
Converter.BufferedToFile(rotated, imgOut)
}
return imgOut.exists()
}
/**
* Checks if an image is a valid JPG
* @param file
* @return
*/
static boolean isValidJPG(File file) {
boolean valid = false
//verify that it is not corrupted
final InputStream digestInputStream = file.newInputStream()
try {
final ImageInputStream imageInputStream = ImageIO.createImageInputStream(digestInputStream)
final Iterator imageReaders = ImageIO.getImageReaders(imageInputStream)
if (imageReaders.hasNext()) {
final ImageReader imageReader = imageReaders.next()
imageReader.setInput(imageInputStream)
imageReader.read(0)?.flush()
if (imageReader.formatName == "JPEG") {
imageInputStream.seek(imageInputStream.streamPosition - 2)
final byte[] lastTwoBytes = new byte[2]
imageInputStream.read(lastTwoBytes)
if (lastTwoBytes[0] == (byte) 0xff || lastTwoBytes[1] == (byte) 0xd9) {
valid = true
} else {
Log.w("File: ${file.name} is not complete.")
}
}
} else {
try {
ImageIO.read(file).flush()
valid = true //ignore it
} catch(Exception | Error ignored) {
Log.w("Simple image verification failed")
}
}
} catch (Exception e) {
Log.w("File: ${file.name} thrown an error: %s", e)
} finally {
digestInputStream.close()
}
return valid
}
}