blob: a731cd06137b032e15d2a550c50b192ad1ccb910 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.pdfbox.jbig2;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;
import org.apache.pdfbox.jbig2.err.JBIG2Exception;
import org.apache.pdfbox.jbig2.image.Bitmaps;
import org.apache.pdfbox.jbig2.image.FilterType;
import org.apache.pdfbox.jbig2.util.cache.CacheFactory;
/**
* @see ImageReader
*/
public class JBIG2ImageReader extends ImageReader
{
/** JBIG2 document to which we delegate current work. */
private JBIG2Document document;
/** Globals are JBIG2 segments for PDF wide use. */
private JBIG2Globals globals;
/**
* @see ImageReader#ImageReader(ImageReaderSpi)
*
* @param originatingProvider - The {@code ImageReaderSpi} that is invoking this constructor, or {@code null}.
* @throws IOException if something went wrong while reading the provided stream.
*/
public JBIG2ImageReader(ImageReaderSpi originatingProvider) throws IOException
{
super(originatingProvider);
}
/**
* @see ImageReader#getDefaultReadParam()
*/
@Override
public JBIG2ReadParam getDefaultReadParam()
{
return new JBIG2ReadParam();
}
/**
* Returns a default {@linkplain ImageReadParam} object for a specific page.
*
* @param imageIndex - The page number.
* @return
*/
private JBIG2ReadParam getDefaultReadParam(final int imageIndex)
{
int width = 1;
int height = 1;
try
{
final int index = (imageIndex < getDocument().getAmountOfPages()) ? imageIndex : 0;
width = getWidth(index);
height = getHeight(index);
}
catch (IOException e)
{
// Dimensions could not be determined. Returning read params
}
return new JBIG2ReadParam(1, 1, 0, 0, new Rectangle(0, 0, width, height),
new Dimension(width, height));
}
/**
* Calculates the width of the specified page.
*
* @param imageIndex - The image index. In this case it is the page number.
*
* @return The width of the specified page.
*
* @throws IOException if an error occurs reading the width information from the input source.
*/
@Override
public int getWidth(int imageIndex) throws IOException
{
return getDocument().getPage(imageIndex + 1).getWidth();
}
/**
* Calculates the height of the specified page.
*
* @param imageIndex - The image index. In this case it is the page number.
*
* @return The height of the specified page or {@code 0} if an error occurred.
*
* @throws IOException if an error occurs reading the height information from the input source.
*/
@Override
public int getHeight(int imageIndex) throws IOException
{
try
{
return getDocument().getPage(imageIndex + 1).getHeight();
}
catch (JBIG2Exception e)
{
throw new IOException(e.getMessage());
}
}
/**
* Simply returns the {@link JBIG2ImageMetadata}.
*
* @return The associated {@link JBIG2ImageMetadata}.
*
* @throws IOException if an error occurs reading the height information from the input source.
*/
@Override
public IIOMetadata getImageMetadata(int imageIndex) throws IOException
{
return new JBIG2ImageMetadata(getDocument().getPage(imageIndex + 1));
}
/**
* Returns the iterator for available image types.
*
* @param imageIndex - The page number.
*
* @return An {@link Iterator} for available image types.
*
* @throws IOException if an error occurs reading the height information from the input source.
*/
@Override
public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException
{
List<ImageTypeSpecifier> l = new ArrayList<ImageTypeSpecifier>();
l.add(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_BYTE_INDEXED));
return l.iterator();
}
/**
* @see ImageReader#getNumImages(boolean)
*/
@Override
public int getNumImages(boolean allowSearch) throws IOException
{
return allowSearch ? getDocument().getAmountOfPages() : -1;
}
/**
* This ImageIO plugin doesn't record {@link IIOMetadata}.
*
* @return {@code null} at every call.
*/
@Override
public IIOMetadata getStreamMetadata()
{
return null;
}
/**
* Returns decoded segments that has been set as globals. Globals are jbig2 segments that are used in embedded case
* for file wide access. They are not assigned to a specific page.
*
* @return Decoded global segments.
*
* @throws IOException if an error occurs reading the height information from the input source.
*/
public JBIG2Globals getGlobals() throws IOException
{
return getDocument().getGlobalSegments();
}
/**
* Returns the decoded image of specified page considering the given {@link JBIG2ReadParam}s.
*
* @see ImageReader#read(int, ImageReadParam)
*/
@Override
public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException
{
if (param == null)
{
param = getDefaultReadParam(imageIndex);
}
JBIG2Page page = getPage(imageIndex);
Bitmap pageBitmap = (Bitmap) CacheFactory.getCache().get(page);
if (pageBitmap == null)
{
try
{
pageBitmap = page.getBitmap();
CacheFactory.getCache().put(page, pageBitmap, pageBitmap.getMemorySize());
page.clearPageData();
}
catch (JBIG2Exception e)
{
throw new IOException(e.getMessage());
}
}
return Bitmaps.asBufferedImage(pageBitmap, param, FilterType.Gaussian);
}
@Override
public boolean canReadRaster()
{
return true;
}
@Override
public Raster readRaster(int imageIndex, ImageReadParam param) throws IOException
{
if (param == null)
{
param = getDefaultReadParam(imageIndex);
}
JBIG2Page page = getPage(imageIndex);
Bitmap pageBitmap = (Bitmap) CacheFactory.getCache().get(page);
if (pageBitmap == null)
{
try
{
pageBitmap = page.getBitmap();
CacheFactory.getCache().put(page, pageBitmap, pageBitmap.getMemorySize());
page.clearPageData();
}
catch (JBIG2Exception e)
{
throw new IOException(e.getMessage());
}
}
return Bitmaps.asRaster(pageBitmap, param, FilterType.Gaussian);
}
/**
* Decodes and returns the global segments.
*
* @param globalsInputStream - The input stream of globals data.
*
* @return The decoded {@link JBIG2Globals}.
*
* @throws IOException if an error occurs reading the height information from the input source.
*/
public JBIG2Globals processGlobals(ImageInputStream globalsInputStream) throws IOException
{
JBIG2Document doc = new JBIG2Document(globalsInputStream);
return doc.getGlobalSegments();
}
/**
* Simply sets the globals.
*
* @param globals - The globals to set.
* @throws IOException if an error occurs
*/
public void setGlobals(JBIG2Globals globals) throws IOException
{
// TODO remove throws IOException as there isn't any chance to trigger it
this.globals = globals;
this.document = null;
}
/**
* @see ImageReader#setInput(Object, boolean, boolean)
*/
@Override
public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata)
{
super.setInput(input, seekForwardOnly, ignoreMetadata);
document = null;
}
private JBIG2Document getDocument() throws IOException
{
if (this.document == null)
{
if (this.input == null)
{
throw new IOException("Input not set.");
}
this.document = new JBIG2Document((ImageInputStream) this.input, this.globals);
}
return this.document;
}
private JBIG2Page getPage(int imageIndex) throws IOException
{
JBIG2Page page = getDocument().getPage(imageIndex + 1);
if (page == null)
throw new IndexOutOfBoundsException(
"Requested page at index=" + imageIndex + " does not exist.");
return page;
}
}