Last active
October 3, 2017 20:11
-
-
Save patrickfav/5a51566f31c472d02884 to your computer and use it in GitHub Desktop.
StackOverflow Question 36029295
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2017 Patrick Favre-Bulle | |
* | |
* 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 at.favre.tools.dconvert.util; | |
import at.favre.tools.dconvert.arg.Arguments; | |
import at.favre.tools.dconvert.arg.ImageType; | |
import com.twelvemonkeys.imageio.metadata.CompoundDirectory; | |
import com.twelvemonkeys.imageio.metadata.Directory; | |
import com.twelvemonkeys.imageio.metadata.Entry; | |
import com.twelvemonkeys.imageio.metadata.exif.EXIFReader; | |
import com.twelvemonkeys.imageio.metadata.exif.EXIFWriter; | |
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG; | |
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment; | |
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil; | |
import org.imgscalr.Scalr; | |
import javax.imageio.*; | |
import javax.imageio.metadata.IIOMetadata; | |
import javax.imageio.stream.FileImageInputStream; | |
import javax.imageio.stream.FileImageOutputStream; | |
import javax.imageio.stream.ImageInputStream; | |
import javax.imageio.stream.ImageOutputStream; | |
import java.awt.*; | |
import java.awt.image.BufferedImage; | |
import java.awt.image.BufferedImageOp; | |
import java.io.File; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.util.ArrayList; | |
import java.util.Iterator; | |
import java.util.List; | |
/** | |
* Main Util class containing all | |
*/ | |
public class ImageUtil { | |
public static LoadedImage loadImage(File input) throws Exception { | |
if (input == null) { | |
throw new IllegalArgumentException("input == null!"); | |
} | |
if (!input.canRead()) { | |
throw new IIOException("Can't read input file!"); | |
} | |
ImageInputStream stream = ImageIO.createImageInputStream(input); | |
if (stream == null) { | |
throw new IIOException("Can't create an ImageInputStream!"); | |
} | |
LoadedImage image = read(stream, Arguments.getImageType(input)); | |
if (image.getImage() == null) { | |
stream.close(); | |
} | |
return new LoadedImage(input, image.getImage(), image.getMetadata(), readExif(input)); | |
} | |
private static Directory readExif(File input) throws IOException { | |
if(Arguments.getImageType(input) == ImageType.JPG) { | |
try (ImageInputStream stream = ImageIO.createImageInputStream(input)) { | |
List<JPEGSegment> exifSegment = JPEGSegmentUtil.readSegments(stream, JPEG.APP1, "Exif"); | |
InputStream exifData = exifSegment.get(0).data(); | |
exifData.read(); // Skip 0-pad for Exif in JFIF | |
try (ImageInputStream exifStream = ImageIO.createImageInputStream(exifData)) { | |
return new EXIFReader().read(exifStream); | |
} | |
} catch (Exception e) { | |
e.printStackTrace(); | |
return null; | |
} | |
} | |
return null; | |
} | |
private static LoadedImage read(ImageInputStream stream, ImageType imageType) throws IOException { | |
if (stream == null) { | |
throw new IllegalArgumentException("stream == null!"); | |
} | |
Iterator iter = ImageIO.getImageReaders(stream); | |
if (!iter.hasNext()) { | |
return null; | |
} | |
ImageReader reader = (ImageReader) iter.next(); | |
ImageReadParam param = reader.getDefaultReadParam(); | |
reader.setInput(stream, true, true); | |
BufferedImage bi; | |
IIOMetadata metadata; | |
try { | |
metadata = reader.getImageMetadata(0); | |
bi = reader.read(0, param); | |
} finally { | |
reader.dispose(); | |
stream.close(); | |
} | |
return new LoadedImage(null, bi, metadata, null); | |
} | |
public static List<File> compressToFile(File targetFile, List<ImageType.ECompression> compressionList, LoadedImage imageData, Dimension targetDimension, | |
float compressionQuality, boolean skipIfExists, boolean antiAlias, boolean isNinePatch) throws Exception { | |
List<File> files = new ArrayList<>(2); | |
for (ImageType.ECompression compression : compressionList) { | |
File imageFile = new File(targetFile.getAbsolutePath() + "." + compression.extension); | |
if (imageFile.exists() && skipIfExists) { | |
break; | |
} | |
BufferedImage scaledImage; | |
if (isNinePatch && compression == ImageType.ECompression.PNG) { | |
scaledImage = new NinePatchScaler().scale(imageData.getImage(), targetDimension); | |
} else { | |
scaledImage = scale(imageData.getImage(), targetDimension.width, targetDimension.height, compression, Color.white, antiAlias); | |
} | |
if (compression == ImageType.ECompression.JPG) { | |
compressJpeg(imageFile, scaledImage, null, compressionQuality); | |
} else { | |
ImageIO.write(scaledImage, compression.name().toLowerCase(), imageFile); | |
} | |
scaledImage.flush(); | |
files.add(imageFile); | |
} | |
return files; | |
} | |
public static void compressJpeg(File targetFile, BufferedImage bufferedImage, CompoundDirectory exif, float quality) throws IOException { | |
ImageWriter jpgWriter = ImageIO.getImageWritersByFormatName("jpg").next(); | |
ImageWriteParam jpgWriteParam = jpgWriter.getDefaultWriteParam(); | |
jpgWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); | |
jpgWriteParam.setCompressionQuality(quality); | |
ImageWriter writer = null; | |
try (ImageOutputStream outputStream = new FileImageOutputStream(targetFile)) { | |
if (false && exif != null) { | |
EXIFWriter exifWriter = new EXIFWriter(); | |
List<Entry> entryList = new ArrayList<>(); | |
for (int i = 0; i < exif.directoryCount(); i++) { | |
for (Entry entry : exif.getDirectory(i)) { | |
entryList.add(entry); | |
} | |
} | |
//TODO: fix exif writing | |
exifWriter.write(exif, outputStream); | |
} | |
writer = ImageIO.getImageWritersByFormatName("jpg").next(); | |
writer.setOutput(outputStream); | |
writer.write(null, new IIOImage(bufferedImage, null, null), jpgWriteParam); | |
} finally { | |
if (writer != null) writer.dispose(); | |
} | |
} | |
public static BufferedImage scale(BufferedImage imageToScale, int dWidth, int dHeight, ImageType.ECompression compression, Color background, boolean antiAlias) { | |
BufferedImage scaledImage = null; | |
if (imageToScale != null) { | |
BufferedImageOp[] bufferedImageOpArray = new BufferedImageOp[]{}; | |
if (antiAlias) { | |
bufferedImageOpArray = new BufferedImageOp[]{Scalr.OP_ANTIALIAS}; | |
} | |
scaledImage = Scalr.resize(imageToScale, Scalr.Method.ULTRA_QUALITY, Scalr.Mode.FIT_EXACT, dWidth, dHeight, bufferedImageOpArray); | |
if (!compression.hasTransparency) { | |
BufferedImage convertedImg = new BufferedImage(scaledImage.getWidth(), scaledImage.getHeight(), BufferedImage.TYPE_INT_RGB); | |
convertedImg.getGraphics().drawImage(scaledImage, 0, 0, background, null); | |
scaledImage = convertedImg; | |
} | |
} | |
return scaledImage; | |
} | |
/** | |
* Gets image dimensions for given file | |
* | |
* @param imgFile image file | |
* @return dimensions of image | |
* @throws IOException if the file is not a known image | |
*/ | |
public static Dimension getImageDimension(File imgFile) throws IOException { | |
int pos = imgFile.getName().lastIndexOf("."); | |
if (pos == -1) | |
throw new IOException("No extension for file: " + imgFile.getAbsolutePath()); | |
String suffix = imgFile.getName().substring(pos + 1); | |
Iterator<ImageReader> iter = ImageIO.getImageReadersBySuffix(suffix); | |
if (iter.hasNext()) { | |
ImageReader reader = iter.next(); | |
try { | |
ImageInputStream stream = new FileImageInputStream(imgFile); | |
reader.setInput(stream); | |
int width = reader.getWidth(reader.getMinIndex()); | |
int height = reader.getHeight(reader.getMinIndex()); | |
return new Dimension(width, height); | |
} finally { | |
reader.dispose(); | |
} | |
} | |
throw new IOException("Not a known image file: " + imgFile.getAbsolutePath()); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2017 Patrick Favre-Bulle | |
* | |
* 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 at.favre.tools.dconvert.util; | |
import com.twelvemonkeys.imageio.metadata.CompoundDirectory; | |
import javax.imageio.metadata.IIOMetadata; | |
import java.awt.image.BufferedImage; | |
import java.io.File; | |
/** | |
* Wraps a {@link java.awt.image.BufferedImage} and some other meta data | |
*/ | |
public class LoadedImage { | |
private final File sourceFile; | |
private final BufferedImage image; | |
private final IIOMetadata metadata; | |
private final CompoundDirectory directory; | |
public LoadedImage(File sourceFile, BufferedImage image, IIOMetadata metadata, CompoundDirectory directory) { | |
this.sourceFile = sourceFile; | |
this.image = image; | |
this.metadata = metadata; | |
this.directory = directory; | |
} | |
public File getSourceFile() { | |
return sourceFile; | |
} | |
public BufferedImage getImage() { | |
return image; | |
} | |
public IIOMetadata getMetadata() { | |
return metadata; | |
} | |
public CompoundDirectory getExif() { | |
return directory; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment