问题
I want to change the height of multi page TIFF image so I am using below code snippet to scale it. But It returns just first page from the tiff file , I guess it converts it to JPEG image. How to retain all pages of the file??
public static byte[] scale(byte[] fileData, int width, int height) {
System.out.println("width:::"+width+"::::height:::"+height);
ByteArrayInputStream in = new ByteArrayInputStream(fileData);
ByteArrayOutputStream buffer=null;
BufferedImage img=null;
BufferedImage imageBuff=null;
try {
ImageInputStream imageStream = ImageIO.createImageInputStream(new ByteArrayInputStream(fileData));
java.util.Iterator<ImageReader> readers = ImageIO.getImageReaders(imageStream);
while(readers.hasNext()) {
ImageReader nextImageReader = readers.next();
nextImageReader.reset();
}
img = ImageIO.read(in);
if(height == 0) {
height = (width * img.getHeight())/ img.getWidth();
}
if(width == 0) {
width = (height * img.getWidth())/ img.getHeight();
}
Image scaledImage = img.getScaledInstance(width, height, Image.SCALE_SMOOTH);
imageBuff = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
imageBuff.getGraphics().drawImage(scaledImage, 0, 0, new Color(0,0,0), null);
buffer = new ByteArrayOutputStream();
ImageIO.write(imageBuff, "TIF", buffer);
} catch (IOException e) {
e.printStackTrace();
} finally{
if(img!=null){
img.flush();
img=null;
}
if(imageBuff!=null){
imageBuff.flush();
imageBuff=null;
}
if(buffer!=null){
try {
buffer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(in!=null){
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return buffer.toByteArray();
}
UPDATED CODE:
public static byte[] resize(byte[] img,int height,int width) throws IOException {
byte[] outimage = null;
ImageReader reader=null;
ImageWriter writer=null;
ByteArrayOutputStream baos=null;
ImageOutputStream ios=null;
ImageInputStream imageStream=null;
try {
baos = new ByteArrayOutputStream(30000);
ios = ImageIO.createImageOutputStream(baos);
reader = getTiffImageReader();
imageStream= ImageIO.createImageInputStream(new ByteArrayInputStream(img));
reader.setInput(imageStream);
int pages = reader.getNumImages(true);
Iterator<ImageWriter> imageWriters = ImageIO.getImageWritersByFormatName("TIFF");
writer = imageWriters.next();
writer.setOutput(ios);
ImageWriteParam writeParam = writer.getDefaultWriteParam();
writeParam.setTilingMode(ImageWriteParam.MODE_DEFAULT);
writer.prepareWriteSequence(reader.getStreamMetadata());
for (int i = 0; i < pages; i++) {
//IIOImage iioImage = reader.readAll(i, null);
BufferedImage bufimage=null;
BufferedImage imageBuff=null;
bufimage=reader.read(i);
imageBuff=Thumbnails.of(bufimage).size(1200, 1200).asBufferedImage();
IIOImage scalediioImage = new IIOImage(imageBuff, null, null);
writer.writeToSequence(scalediioImage, writeParam);
bufimage.flush();
imageBuff.flush();
}
writer.endWriteSequence();
outimage = baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
finally{
if(imageStream!=null){
imageStream.close();
}
if(ios!=null){
ios.flush();
ios.close();
}
if(baos!=null){
baos.close();
}
if(reader!=null){
reader.dispose();
}
if(writer!=null){
writer.dispose();
}
}
return outimage;
}
回答1:
ImageIO.write(...)
will only ever write single stand-alone images. Writing multiple images to the same output stream does not remedy this. However the ImageIO package comes with full support for what you want, it just requires more code.
Obtain the proper ImageWriter
for TIFF format, using :
ImageWriter writer = ImageIO.getImageWritersByFormatName("TIFF").next(); // Assumes TIFF plugin installled
See the API docs for ImageIO.getImageWritersByFormatName(String) for more information.
Then use writer.canWriteSequence() to tell if your writer
instance supports writing sequences. It should return true
for TIFF. If not, you need to find a different plugin.
Next, use writer.prepareWriteSequence(...) to prepare your image sequence.
For each image (page) you want to append, use writer.writeToSequence(new IIOImage(..., bufferedImage, null), ...) in a for
loop.
Then finally, outside the for
loop use writer.endWriteSequence() to end the image sequence.
Hope these pointers should get you going in the right direction.
Update: Here's a cleaned up and modified version of your code that I think should work (I don't have and can't install JAI on my work laptop).
The important changes are removing the writer.setOutput(ios)
from the loop (you should only set it once), and moving writer.endWriteSequence()
oustide the loop. I also removed the BufferedImage
array, to avoid keeping all the images in memory, you might want to keep it for convenience.
Let me know if you still have trouble, and I'll see what I can do.
public static byte[] resize(byte[] img) throws IOException {
byte[] outimage = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(30000);
ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
ImageReader reader = getTiffImageReader();
ImageInputStream imageStream = ImageIO.createImageInputStream(new ByteArrayInputStream(img));
reader.setInput(imageStream);
int pages = reader.getNumImages(true);
Iterator<ImageWriter> imageWriters = ImageIO.getImageWritersByFormatName("TIFF");
ImageWriter writer = imageWriters.next();
writer.setOutput(ios);
ImageWriteParam writeParam = writer.getDefaultWriteParam();
writeParam.setTilingMode(ImageWriteParam.MODE_DEFAULT);
writer.prepareWriteSequence(reader.getStreamMetadata()); // You want the stream metadata here
for (int i = 0; i < pages; i++) {
IIOImage iioImage = reader.readAll(i, null); // Save some lines by using readAll
BufferedImage image = (BufferedImage) iioImage.getRenderedImage();
// Modify image here...
iioImage.setRenderedImage(image);
writer.writeToSequence(iioImage, writeParam);
}
writer.endWriteSequence(); // Crucial, must be done outside loop
ios.flush();
ios.close();
outimage = baos.toByteArray();
baos.close();
writer.dispose();
reader.dispose();
} catch (Exception e) {
e.printStackTrace();
}
return outimage;
}
来源:https://stackoverflow.com/questions/22856461/scale-multi-page-tiff-image-in-java