I am attempting to display a .tif in Java using a minimal number of additional libraries:
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.WindowConstants;
import javax.media.jai.widget.*;
import it.geosolutions.imageio.utilities.*;
import it.geosolutions.imageioimpl.plugins.tiff.*;
import com.sun.media.imageioimpl.common.*;
public static void main(String[] args) {
try {
File f = new File("image.tif");
BufferedImage tif = ImageIO.read(f);
ImageIcon ic = new ImageIcon(tif);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JLabel label = new JLabel(ic);
frame.add(label);
frame.setVisible(true);
} catch (IOException e) {
e.printStackTrace();
}
}
The libraries I'm using are:
jai-core-1.1.3.jar
jai-imageio-1.1.jar
imageio-ext-tiff.1.1.3.jar
imageio-ext-utilities.1.1.3.jar
From here: http://java.net/projects/imageio-ext (Downloads link on right side)
However, the displayed image is:
which is decidedly not the original image. Nor are any errors being thrown that I know of. Furthermore, the original image is fine, and doesn't change.
However, the original code is small. I don't actually use the imageio-ext imports, but the program will fail without them. I also haven't used imageio-ext before either.
Please help! I need to be able to use .tif images in Java without installing software.
If you already use all JAI/ImageIO libraries, you might want to try the following (which works fine for me):
import com.sun.media.jai.codec.FileSeekableStream;
import com.sun.media.jai.codec.ImageCodec;
import com.sun.media.jai.codec.ImageDecoder;
// This function is minimal, you should add exceptions and error handling
public RenderedImage read(String filename)
FileSeekableStream fss = new FileSeekableStream(filename);
ImageDecoder decoder = ImageCodec.createImageDecoder("tiff", fss, null);
RenderedImage image = decoder.decodeAsRenderedImage()
fss.close();
return image;
}
If you need a BufferedImage instead of a RenderedImage, the only solution I found is to use this function:
public static BufferedImage Rendered2Buffered(RenderedImage image) {
BufferedImage bi = new BufferedImage(image.getWidth(), image.getHeight(), image.getSampleModel().getDataType());
bi.setData(image.getData());
return bi;
}
Be careful though, the image.getSampleModel().getDataType() usually returns a BufferedImage.TYPE_CUSTOM, which makes it impossible for the BufferedImage to be created! In my case I had to "guess" the type according to the sample size returned by image.getSampleModel().getSampleSize(0) (because I know the image format I'm working with).
If you know a better way to transform a RenderedImage to a BufferedImage, please enlighten me :)
You're correct in thinking that you need the JAI libraries to decode and use TIFF files, but even though you've imported them, you aren't actually using them!
Here is a short tutorial showing how you to create a TIFFDecodeParam object (from the JAI library), and then use that to decode (and display) a TIFF image.
You might also find the JAI API Library useful too.
I ended up going with the most-recent version of Apache-Commons Imaging (formerly Sanselan). Imaging offers out of the box support for TIFF files (I had as little bit of trouble at first, but that was solved by switching from the older Sanselan to the newer Commons Imaging).
There was a little bit of functionality I had to reverse-engineer myself (loading a single sub-TIFF at a specified width while maintaining aspect ratio):
/**
* Load a scaled sub-TIFF image. Loads nth sub-image and scales to given width; preserves aspect ratio.
*
* #param fileName String filename
* #param index Index of sub-TIFF; will throw ArrayIndexOutOfBoundsException if sub-image doesn't exist
* #param w Desired width of image; height will scale
* #return Image (BufferedImage)
* #throws IOException
* #throws ImageReadException
*/
public static Image loadScaledSubTIFF(String fileName, int index, int w) throws IOException, ImageReadException {
File imageFile = new File(fileName);
ByteSourceFile bsf = new ByteSourceFile(imageFile);
FormatCompliance formatCompliance = FormatCompliance.getDefault();
TiffReader tiffReader = new TiffReader(true);
TiffContents contents = tiffReader.readDirectories(bsf, true, formatCompliance);
TiffDirectory td = contents.directories.get(index);
Image bi = td.getTiffImage(tiffReader.getByteOrder(), null);
Object width = td.getFieldValue(new TagInfo("", 256, TiffFieldTypeConstants.FIELD_TYPE_SHORT) {/**/});
Object height = td.getFieldValue(new TagInfo("", 257, TiffFieldTypeConstants.FIELD_TYPE_SHORT) {/**/});
int newWidth = w;
int newHeight = (int) ((newWidth * ((Number)height).doubleValue()) / (((Number)width).doubleValue()));
bi = bi.getScaledInstance(w, newHeight, java.awt.Image.SCALE_FAST);
height = null;
width = null;
td = null;
contents = null;
tiffReader = null;
formatCompliance = null;
bsf = null;
return bi;
}
Related
I am attempting to merge a number of input TIFF files into a single multi-page output TIFF file using the open JDK 11 imageIO ImageReader and ImageWriter classes. My routine works correctly for almost all of my sample input files created from a number of different brands of scanning devices. These devices produce a variety of TIFF files using old and new JPEG compression. However, the TIFF files from one particular device result in an incorrect output that has a pink background. Even stranger, the TIFF produced with a portrait scan creates the correct output, while the TIFF produced with a landscape scan from the same device produces the incorrect output with a pink background. I can see no obvious difference between the 2 input files that would cause the difference in behaviour when processed by the ImageIO library.
I know that a pink background in the output usually indicates that there is a problem with transparency interpretation. I found a number of references to this issue when reading and writing JEPG images. However, I have not found any references to similar issues with TIFF images. When I walk through the ImageReader and ImageWriter in the debugger I can find no obvious difference between the input TIFF file that works and the file that produces the bad pink coloured output. Neither file has transparency. Both have the same YCbCr photometric interpretation, bands, and sub-sampling. The problematic TIFF file uses old JPEG compression, so the image write parameters explicitly specify new JPEG compression for ImageWriter. However, this is true for the similar portrait TIFF file that works correctly, so the problem must be more subtle than just the output compression.
Below is a simple command-line application that reproduces my issue.
package com.example;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataFormatImpl;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
public class Main {
private static final String TIFF_FORMAT = "tiff";
private static final String IMAGEIO_PLUGIN_PACKAGE = "com.sun.imageio.plugins.tiff";
//private static final String IMAGEIO_PLUGIN_PACKAGE = "com.github.jaiimageio.impl.plugins.tiff";
public static void main(String[] args) {
if (args.length != 2) {
System.out.println("You must specify an input directory and output filename");
return;
}
File sourceDirectory = new File(args[0]);
if (!sourceDirectory.exists() || !sourceDirectory.isDirectory()) {
System.out.println(String.format("Source directory '%s' is invalid", args[0]));
}
File outputFile = new File(args[1]);
if (outputFile.exists()) {
outputFile.delete();
}
File inputFiles[] = sourceDirectory.listFiles();
mergeTiffFiles(inputFiles, outputFile);
}
/**
* Merge a list of TIFF files into a single output TIFF file using the Java ImageIO utilities.
*
* #param inputFilePaths list of input file paths to merge
* #param mergedFilePath destination path for the merged output file
*/
private static void mergeTiffFiles(
final File[] inputFilePaths,
final File mergedFilePath) {
ImageReader reader = null;
ImageWriter writer = null;
File inputFilePath = null;
try (
OutputStream outputStream = new FileOutputStream(mergedFilePath);
ImageOutputStream ios = ImageIO.createImageOutputStream(outputStream)
) {
// Initialise the output writer
writer = getTiffWriter();
writer.setOutput(ios);
writer.prepareWriteSequence(null);
// Iterate through the source files appending the pages in order within and across files
reader = getTiffReader();
for (final File filePath : inputFilePaths) {
inputFilePath = filePath;
try (
FileInputStream inputFile = new FileInputStream(filePath);
ImageInputStream inputStream = ImageIO.createImageInputStream(inputFile)
) {
reader.setInput(inputStream);
int numImages = reader.getNumImages(true);
for (int j = 0; j < numImages; j++) {
IIOMetadata imageMetadata = reader.getImageMetadata(j); // 0, first image
ImageWriteParam writeParams = getTiffWriteParams(writer, imageMetadata);
BufferedImage image = reader.read(j);
writer.writeToSequence(new IIOImage(image, null, imageMetadata), writeParams);
}
}
}
inputFilePath = null;
// Finalize the output file
writer.endWriteSequence();
} catch (Exception e) {
if (inputFilePath != null) {
throw new IllegalStateException(String.format("Error while merging TIFF file: %s", inputFilePath), e);
} else {
throw new IllegalStateException("Failed to merge TIFFs files", e);
}
} finally {
// Cleanup the reader and writer
if (writer != null) {
writer.dispose();
}
if (reader != null) {
reader.dispose();
}
}
}
/**
* Get an TIFF reader used to read the source pages - ensure we use the imageIO plugin.
*
* #return an TIFF image reader.
* #throws IOException if an reader plugin cannot be found
*/
private static ImageReader getTiffReader() throws IOException {
ImageReader reader = null;
Iterator readers = ImageIO.getImageReadersByFormatName(TIFF_FORMAT);
if (readers.hasNext()) {
do {
reader = (ImageReader) readers.next();
} while (!reader.getClass().getPackage().getName().equals(IMAGEIO_PLUGIN_PACKAGE) && readers.hasNext());
}
if (reader == null) {
throw new IOException("No imageio readers for format: " + TIFF_FORMAT);
}
return reader;
}
/**
* Get a TIFF writer used to create the merged page - ensure we use the imageIO plugin
*
* #return a TIFF image writer
* #throws IOException if an writer plugin cannot be found
*/
private static ImageWriter getTiffWriter() throws IOException {
ImageWriter writer = null;
Iterator writers = ImageIO.getImageWritersByFormatName(TIFF_FORMAT);
if (writers.hasNext()) {
do {
writer = (ImageWriter) writers.next();
} while (!writer.getClass().getPackage().getName().equals(IMAGEIO_PLUGIN_PACKAGE) && writers.hasNext());
}
if (writer == null) {
throw new IOException("No imageio writers for format: " + TIFF_FORMAT);
}
return writer;
}
/**
* Get the appropriate TIFF write parameters to apply for an input with the given image meta-data.
* Check the source image compression. If possible use the same compression settings as those from the
* input image. However, the ImageIO library doesn't support the legacy JPEG compression format for TIFF
* images. Unfortunately, there are a number of devices that create scanned TIFF images of this type
* (Xerox, HP OXP). To support the merge operation explicitly force the new JPEG compression with a high
* quality value.
*
* #param writer TIFF image writer that will use the returned image parameters
* #param imageMetadata meta-data associated with the image to write
* #return the adjusted image write parameters
*/
private static ImageWriteParam getTiffWriteParams(ImageWriter writer, IIOMetadata imageMetadata) {
// Determine the source compression type
IIOMetadataNode root =
(IIOMetadataNode) imageMetadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
IIOMetadataNode compression =
(IIOMetadataNode) root.getElementsByTagName("CompressionTypeName").item(0);
String compressionName = compression.getAttribute("value");
ImageWriteParam writeParams = writer.getDefaultWriteParam();
if (compressionName.equalsIgnoreCase("Old JPEG")) {
// Convert to modern JPEG encoding if the source uses old JPEG compression.
writeParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
writeParams.setCompressionType("JPEG");
double quality = 0.95;
quality = Math.max(0, Math.min(1, quality));
writeParams.setCompressionQuality((float) quality);
} else {
// Otherwise use the source image compression if possible
writeParams.setCompressionMode(ImageWriteParam.MODE_COPY_FROM_METADATA);
}
writeParams.setTilingMode(ImageWriteParam.MODE_COPY_FROM_METADATA);
return writeParams;
}
}
I expect the output of the similar landscape and portrait TIFFs to have the correct white background. I am obviously doing something wrong with the setup of the reading or writing procedure. However, there are not many options to try. The ImageReader only supports one image destination type for the TIFF files. The problem happens with the latest open JDK 11.0.4_11 version.
Okay, by inspecting the sample files, I think I have found the problem. And it's not in your code*.
When reading and writing TIFF with JPEG compression, the TIFF plugin will delegate decoding/encoding of the embedded JPEG stream to the JPEG plugin. In theory, this is simple, because the JPEG contains no color information, and the TIFF container contains the correct color information in the 262/PhotometricInterpretation tag.
In real life, this is much more complex, because sometimes the TIFF tag is missing or incorrect (especially in combination with 259/Compression tag with value 6 ("Old JPEG"). Or the JPEG encoder/decoder will make its own assumptions about color space (based on conventions for standalone JPEGs, typically JFIF or Exif), which is what I believe is the case here. The JPEG plugin bundled with the JRE uses the conventions documented here, and color space is inferred from the component ids in the SOFn marker.
For your files, we can see that the component ids differ.
Portrait file:
SOF0[ffc0, precision: 8, lines: 3520, samples/line: 2496,
components: [id: 1, sub: 1/1, sel: 0, id: 2, sub: 1/1, sel: 1, id: 3, sub: 1/1, sel: 1]]
Landscape file:
SOF0[ffc0, precision: 8, lines: 2496, samples/line: 3520,
components: [id: 0, sub: 1/1, sel: 0, id: 1, sub: 1/1, sel: 1, id: 2, sub: 1/1, sel: 1]]
The component ids in the portrait file are the normal 1, 2, and 3, while the landscape has ids 0, 1, and 2. Both files has no subsampling (ie. 1:1).
From the conventions:
If these values are 1-3 for a 3-channel image, then the image is assumed to be YCbCr [...]
Otherwise, 3-channel subsampled images are assumed to be YCbCr, 3-channel non-subsampled images are assumed to be RGB.
Because of this, the landscape image will be treated as already in RGB (and, incorrectly, not converted from YCbCr), resulting in the pinkish tint. Even though everything else in the TIFF container clearly indicates that it's YCbCr.
To fix this issue (and many other issues), I have created my own JPEG plugin that can be used as a drop-in replacement for the JRE plugin. It follows (the much simpler) conventions found in IJG's libJPEG, resulting in better color space consistency with other applications. In combination with the TIFF plugin from the same project, both your inputs are read correctly (white background). I have not tested it with the JRE TIFF plugin, but in theory, it should/could also work. Unfortunately, the TwelveMonkeys TIFF plugin does not (yet)
have the write capabilities you use (tiling) and has some limitations about what meta data it writes.
PS: As you seem to deal mainly with JPEGs that degrade in quality when re-encoding, you might want to look at merging TIFFs without decoding the image data. You can find an example of that in TIFFUtilities, written by Oliver Schmidtmer.
*) It is technically possible to work around the problem in your code, but it's kind of complex to handle all the cases correctly. If you want to implement this yourself, or are just curious I suggest you have a look at the source code for the TwelveMonkeys ImageIO JPEG plugin.
I have an image in the format of byte[] array in my Java code. I want the following information extracted from that array. How can I do it as fast as possible.
Width
Height
Color (black & white, color or transparent? If color, what is the main color?)
Type (Is the image PNG, GIF, JPEG, etc.)
Use ImageIO to read as buffered image and then get relevant things which you want. See java doc at http://docs.oracle.com/javase/6/docs/api/javax/imageio/ImageIO.html.
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
public class Test {
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
// assuming that picture is your byte array
byte[] picture = new byte[30];
InputStream in = new ByteArrayInputStream(picture);
BufferedImage buf = ImageIO.read(in);
ColorModel model = buf.getColorModel();
int height = buf.getHeight();
}
}
To get the image type from the byte array, you can do something like:
byte[] picture = new byte[30];
ImageInputStream iis = ImageIO.createImageInputStream(new ByteArrayInputStream(picture));
Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
while (readers.hasNext()) {
ImageReader read = readers.next();
System.out.println("format name = " + read.getFormatName());
}
Here is the output I have for different files:
format name = png
format name = JPEG
format name = gif
It was inspired from:
Convert Byte Array to image in Java - without knowing the type
I am trying to replace some pixels from my source image(PNG format). But i am end up with some confusing result. Basically i am replacing a particular RGB values with black and white colors. Here is my code,
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ChangePixel
{
public static void main(String args[]) throws IOException
{
File file = new File(System.getProperty("user.dir"), "D4635.png");
FileInputStream fis = new FileInputStream(file);
BufferedImage image = ImageIO.read(fis);
int[] replaceColors = new int[2];
replaceColors[0] = Color.BLACK.getRGB();
replaceColors[1] = Color.WHITE.getRGB();
Color src = new Color(133, 101, 51);
int srcRGBvalue = src.getRGB();
changeAlg2(image, srcRGBvalue, replaceColors);
}
private static void changeAlg2(BufferedImage image, int srcRGBvalue, int[] replaceColors) throws IOException
{
for (int width = 0; width < image.getWidth(); width++)
{
for (int height = 0; height < image.getHeight(); height++)
{
if (image.getRGB(width, height) == srcRGBvalue)
{
image.setRGB(width, height, ((width + height) % 2 == 0 ? replaceColors[0] : replaceColors[1]));
}
}
}
File file = new File(System.getProperty("user.dir"), "107.png");
ImageIO.write(image, "png", file);
}
}
It changes my source pixels to black and some other color, instead of white. Please advice me, what's going wrong here.
Since this is my first post, I can't able to attach my images. Sorry for the inconvenience.
Edit: I have uploaded the source and the output images in a site. Here is the URL,
Source : http://s20.postimage.org/d7zdt7kwt/D4635.png
Output : http://s20.postimage.org/kdr4vntzx/107.png
Expected output : After the black pixel, white pixel has to come.
Edit : Resolved code as per Jan Dvorak advice,
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ChangePixel
{
public static void main(String args[]) throws IOException
{
File file = new File(System.getProperty("user.dir"), "D12014.gif");
FileInputStream fis = new FileInputStream(file);
BufferedImage image = ImageIO.read(fis);
Color src = new Color(223, 170, 66);
int srcRGBvalue = src.getRGB();
int[] replaceColors = new int[2];
replaceColors[0] = Color.MAGENTA.getRGB();
replaceColors[1] = Color.CYAN.getRGB();
changeAlg2(image, srcRGBvalue, replaceColors);
}
private static void changeAlg2(BufferedImage image, int srcRGBvalue, int[] replaceColors) throws IOException
{
BufferedImage image2 = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
for (int width = 0; width < image.getWidth(); width++)
{
for (int height = 0; height < image.getHeight(); height++)
{
if (image.getRGB(width, height) == srcRGBvalue)
{
image2.setRGB(width, height, ((width + height) % 2 == 0 ? replaceColors[0] : replaceColors[1]));
}
else
{
image2.setRGB(width, height, image.getRGB(width, height));
}
}
}
File file = new File(System.getProperty("user.dir"), "110.gif");
ImageIO.write(image2, "gif", file);
}
}
Regards
Raja.
Since you are adding colors that are not present in the original image palette, the pixels you are trying to set are clipped to the nearest color in the palette. You need to set a new color mode. Either convert to 24bpp RGB (true-color) or extend the palette with the new colors.
It doesn't seem to be possible to modify an existing BufferedImage ColorModel or assign a new one, but you can create a new buffer and copy the data there. Creating a new BufferedImage with the same Raster might work as well (only if the bit depth does not change?).
If you don't mind, you can always create a True-color image. try:
{
BufferedImage old = image;
image = new BufferedImage(
old.getWidth(),
old.getHeight(),
BufferedImage.TYPE_INT_RGB
);
image.setData(old.getRaster());
} // old is no longer needed
API reference: http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/image/BufferedImage.html
You could try to detect if the image is already in true-color (image.getColorModel() instanceof ???) to avoid having to copy the buffer when not needed.
You could try to extend the existing palette. If that is not possible (there is no palette to start with or there is not enough space), you have to fallback to RGB.
See:
http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/image/BufferedImage.html (getColorModel and the constructor taking a ColorModel and type)
http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/image/IndexColorModel.html (getMapSize, getRGBs and the corresponding constructor)
From seeing your actual palette, you'll need some sort of deduplication logic because your palette is already 256 bytes - the maximum size of a PNG palette. Note that you should not save the image with larger palette than there are colors in the image (especially when you want to add new colors later). your original file could have been saved with a 2-color palette, saving 762 bytes.
Note that you don't gain much from storing the image as indexed as opposed to true-color with the same number of colors. The reason is that the byte stream (palette = 1 byte per pixel, true-color = 3 or 4 bytes per pixel) is losslessly compressed (with DEFLATE) anyways. Indexed can save you a few bytes (or lose you a few bytes, if the palette is big), but it won't reduce the file size to one third.
How can I modify image from java through ImageMagick? Is there any way of doing it?
Use JMagick (docs). Read the documentation. It provides all the functionality of ImageMagick. You may also look into another ImageMagick Java wrapper, im4java.
There is a good starters document for im4java here
Here is an example, I've worked out.
/** Typical scaling implementation using JMagick **/
ImageInfo origInfo = new ImageInfo(absPath); //load image info
MagickImage image = new MagickImage(origInfo); //load image
image = image.scaleImage(finalWidth, finalHeight); //to Scale image
image.setFileName(absNewFilePath); //give new location
image.writeImage(origInfo); //save
Edit #1:
If you are wondering for the Jar file of JMagick. Download jMagick tarball, untar it.
$ tar xvzf jmagick-linux-6.4.0-Q32.tar.gz
./jmagick-6.4.0.jar
./jmagick.jar
./libJMagick-6.4.0.so
./libJMagick.so
How to Install JMajick on Windows
Go to http://downloads.jmagick.org/6.3.9/ (or any other version of your choice)
Download ImageMagick-6.3.9-0-Q8-windows-dll.exe and jmagick-win-6.3.9-Q8.zip.
Install the exe file. This will install ImageMagick which is a prerequisite for JMagick to work.
Now extract the zip file. This will give jmagick.dll and jmagick.jar.
Copy the jmagick.jar to you lib folder and include it in the classpath.
Copy the jmagick.dll to the root installation directory of ImageMagic and add it as an entry to the PATH environment variable.
JMagick is installed :).
For ImageMagic 1.4.0
// create command
ConvertCmd cmd = new ConvertCmd();
// create the operation, add images and operators/options
IMOperation op = new IMOperation();
op.addImage("source_picture.jpg"); // source file
op.resize(800,600);
// of op.resize(800); // and height calculate automatically
op.addImage("resized_picture.jpg"); // destination file file
// execute the operation
cmd.run(op);
And if you like maven!
<dependency>
<groupId>org.im4java</groupId>
<artifactId>im4java</artifactId>
<version>1.4.0</version>
</dependency>
Resizing an image (using the easiest method) within the J2SE.
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.imageio.ImageIO;
import java.net.URL;
class ResizeImage {
public static void main(String[] args) throws Exception {
URL url = new URL("http://pscode.org/media/citymorn2.jpg");
final BufferedImage bi = ImageIO.read(url);
Runnable r = new Runnable() {
public void run() {
JLabel unresize = new JLabel(new ImageIcon(bi));
int width = (int)(bi.getWidth()*.75);
int height = (int)(bi.getHeight()*.75);
BufferedImage bi1 = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics g1 = bi1.getGraphics();
g1.drawImage( bi, 0, 0, width, height, null );
JLabel easyResize = new JLabel(new ImageIcon(bi1));
JPanel p = new JPanel();
p.add( unresize );
p.add( easyResize );
JOptionPane.showMessageDialog(null, p);
}
};
SwingUtilities.invokeLater(r);
}
}
I tried using imagemagick from Java but found hardware accelerated 100% java library for image operations.
https://github.com/thebuzzmedia/imgscalr
"This library makes uses of efficient Java2D scaling techniques advocated by the Java2D team which provides hardware accelerated operations on most platforms."
I have a need to convert images from CMYK to RGB - not necessarily back again, but hey, if it can be done...
With the release of ColdFusion 8, we got the CFImage tag, but it doesn't support this conversion; and nor does Image.cfc, or Alagad's Image Component.
However, it should be possible in Java; which we can leverage through CF. For example, here's how you might create a Java thread to sleep a process:
<cfset jthread = createObject("java", "java.lang.Thread")/>
<cfset jthread.sleep(5000)/>
I would guess a similar method could be used to leverage java to do this image conversion, but not being a Java developer, I don't have a clue where to start. Can anyone lend a hand here?
A very simple formula for converting from CMYK to RGB ignoring all color profiles is:
R = ( (255-C)*(255-K) ) / 255;
G = ( (255-M)*(255-K) ) / 255;
B = ( (255-Y)*(255-K) ) / 255;
This code requires CMYK values to be in rage of 0-255. If you have 0 to 100 or 0.0 to 1.0 you'll have to convert the values.
Hope this will get you started.
As for the java and ColdFusion interfacing, I'm sorry, but I have no idea how to do that.
I use the Java ImageIO libraries (https://jai-imageio.dev.java.net). They aren't perfect, but can be simple and get the job done. As far as converting from CMYK to RGB, here is the best I have been able to come up with.
Download and install the ImageIO JARs and native libraries for your platform. The native libraries are essential. Without them the ImageIO JAR files will not be able to detect the CMYK images. Originally, I was under the impression that the native libraries would improve performance but was not required for any functionality. I was wrong.
The only other thing that I noticed is that the converted RGB images are sometimes much lighter than the CMYK images. If anyone knows how to solve that problem, I would be appreciative.
Below is some code to convert a CMYK image into an RGB image of any supported format.
Thank you,
Randy Stegbauer
package cmyk;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import org.apache.commons.lang.StringUtils;
public class Main
{
/**
* Creates new RGB images from all the CMYK images passed
* in on the command line.
* The new filename generated is, for example "GIF_original_filename.gif".
*
*/
public static void main(String[] args)
{
for (int ii = 0; ii < args.length; ii++)
{
String filename = args[ii];
boolean cmyk = isCMYK(filename);
System.out.println(cmyk + ": " + filename);
if (cmyk)
{
try
{
String rgbFile = cmyk2rgb(filename);
System.out.println(isCMYK(rgbFile) + ": " + rgbFile);
}
catch (IOException e)
{
System.out.println(e.getMessage());
}
}
}
}
/**
* If 'filename' is a CMYK file, then convert the image into RGB,
* store it into a JPEG file, and return the new filename.
*
* #param filename
*/
private static String cmyk2rgb(String filename) throws IOException
{
// Change this format into any ImageIO supported format.
String format = "gif";
File imageFile = new File(filename);
String rgbFilename = filename;
BufferedImage image = ImageIO.read(imageFile);
if (image != null)
{
int colorSpaceType = image.getColorModel().getColorSpace().getType();
if (colorSpaceType == ColorSpace.TYPE_CMYK)
{
BufferedImage rgbImage =
new BufferedImage(
image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
ColorConvertOp op = new ColorConvertOp(null);
op.filter(image, rgbImage);
rgbFilename = changeExtension(imageFile.getName(), format);
rgbFilename = new File(imageFile.getParent(), format + "_" + rgbFilename).getPath();
ImageIO.write(rgbImage, format, new File(rgbFilename));
}
}
return rgbFilename;
}
/**
* Change the extension of 'filename' to 'newExtension'.
*
* #param filename
* #param newExtension
* #return filename with new extension
*/
private static String changeExtension(String filename, String newExtension)
{
String result = filename;
if (filename != null && newExtension != null && newExtension.length() != 0);
{
int dot = filename.lastIndexOf('.');
if (dot != -1)
{
result = filename.substring(0, dot) + '.' + newExtension;
}
}
return result;
}
private static boolean isCMYK(String filename)
{
boolean result = false;
BufferedImage img = null;
try
{
img = ImageIO.read(new File(filename));
}
catch (IOException e)
{
System.out.println(e.getMessage() + ": " + filename);
}
if (img != null)
{
int colorSpaceType = img.getColorModel().getColorSpace().getType();
result = colorSpaceType == ColorSpace.TYPE_CMYK;
}
return result;
}
}
The tag cfx_image may be of use to you. I haven't used it in a while but I remember it had a ton of features.
Alternatively, you might be able to script a windows app such as Irfanview (via commandline using cfexecute) to process images.
Hope that helps
I know that this question is old, but I still encounter problems with CMYK images & ColdFusion. However, I just read a CMYK JPEG image using ColdFusion 10 and resaved it. The saved image was able to to be read using ColdFusion 9 (which is only capable of reading RGB JPEGs.) I'm not sure if this conversion is intentional or not and I don't currently have any way of identifying whether the source image's color profile is CMYK or not as the saved color profile still appears to be the same.
<cfset imgData = ImageRead(expandPath("./CMYK_image.jpg"))>
<cfset ImageWrite(imgData, expandPath("./Saved_image.jpg"))>