org.jpedal.jbig2.examples.viewer.JBIG2Viewer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of OpenViewerFX Show documentation
Show all versions of OpenViewerFX Show documentation
An Open Source JavaFX PDF Viewer
/**
* ===========================================
* Java Pdf Extraction Decoding Access Library
* ===========================================
*
* Project Info: http://www.jpedal.org
* (C) Copyright 1997-2008, IDRsolutions and Contributors.
* Main Developer: Simon Barnett
*
* This file is part of JPedal
*
* Copyright (c) 2008, IDRsolutions
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the IDRsolutions nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Other JBIG2 image decoding implementations include
* jbig2dec (http://jbig2dec.sourceforge.net/)
* xpdf (http://www.foolabs.com/xpdf/)
*
* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf
*
* All three of the above resources were used in the writing of this software, with methodologies,
* processes and inspiration taken from all three.
*
* ---------------
* JBIG2Viewer.java
* ---------------
*/
package org.jpedal.jbig2.examples.viewer;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Transparency;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.PixelGrabber;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;
import javax.swing.ScrollPaneConstants;
import javax.swing.UIManager;
import org.jpedal.jbig2.JBIG2Decoder;
import org.jpedal.jbig2.JBIG2Exception;
import org.jpedal.jbig2.image.JBIG2Bitmap;
public class JBIG2Viewer extends JFrame {
private JFrame mainFrame = this;
private JScrollPane jsp;
private BufferedImage image;
private JLabel imageLabel = new JLabel();
private JComboBox scalingBox;
private String scalingItem = "";
private double scaling;
private JComboBox rotationBox;
private String rotationItem = "";
private int rotation;
private NavigationToolbar navToolbar;
private JBIG2Decoder decoder;
private int currentPage;
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
new JBIG2Viewer();
} catch (Exception e) {
e.printStackTrace();
}
}
public JBIG2Viewer() {
setSize(500, 500);
getContentPane().setLayout(new BorderLayout());
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new BorderLayout());
setUpToolbar();
imageLabel.setHorizontalAlignment(JLabel.CENTER);
imageLabel.setVerticalAlignment(JLabel.TOP);
jsp = new JScrollPane(imageLabel);
getContentPane().add(jsp, BorderLayout.CENTER);
navToolbar = new NavigationToolbar(this);
navToolbar.setFloatable(false);
getContentPane().add(navToolbar, BorderLayout.SOUTH);
setTitle("JPedal JBIG2 Image Decoder");
setVisible(true);
}
private void setUpToolbar() {
// Create a horizontal toolbar
JToolBar toolbar = new JToolBar();
toolbar.setFloatable(false);
toolbar.setBorder(BorderFactory.createEtchedBorder());
JButton openButton = new JButton(new AbstractAction("Open", new ImageIcon(getClass().getResource("/org/jpedal/jbig2/examples/viewer/res/open.png"))) {
public void actionPerformed(ActionEvent evt) {
openFile();
}
});
openButton.setText(null);
openButton.setToolTipText("Open New File");
toolbar.add(openButton);
toolbar.add(Box.createRigidArea(new Dimension(7, 0)));
JButton saveButton = new JButton(new AbstractAction("Save", new ImageIcon(getClass().getResource("/org/jpedal/jbig2/examples/viewer/res/save.png"))) {
public void actionPerformed(ActionEvent evt) {
if (image == null) {
JOptionPane.showMessageDialog(mainFrame, "No image is open");
} else {
saveFile();
}
}
});
saveButton.setText(null);
saveButton.setToolTipText("Save File As");
toolbar.add(saveButton);
toolbar.add(Box.createRigidArea(new Dimension(7, 0)));
JButton propertiesButton = new JButton(new AbstractAction("Properties", new ImageIcon(getClass().getResource("/org/jpedal/jbig2/examples/viewer/res/properties.png"))) {
public void actionPerformed(ActionEvent evt) {
// Perform action
}
});
propertiesButton.setText(null);
propertiesButton.setToolTipText("File Properties");
// toolbar.add(propertiesButton);
toolbar.add(Box.createRigidArea(new Dimension(7, 0)));
toolbar.add(new JLabel("Zoom:"));
toolbar.add(Box.createRigidArea(new Dimension(3, 0)));
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
setScalingAndRotation();
}
};
scalingBox = new JComboBox(new String[] { "Window", "Height", "Width", "25", "50", "75", "100", "125", "150", "200", "250", "500", "750", "1000" });
scalingBox.setEditable(true);
scalingBox.setPreferredSize(new Dimension(scalingBox.getPreferredSize().width, toolbar.getHeight()));
scalingBox.setPrototypeDisplayValue("XXXXXXXX"); // Set a desired
// width
scalingBox.setMaximumSize(new Dimension(100, 100));
toolbar.add(scalingBox);
toolbar.add(Box.createRigidArea(new Dimension(7, 0)));
toolbar.add(new JLabel("Rotation:"));
toolbar.add(Box.createRigidArea(new Dimension(3, 0)));
rotationBox = new JComboBox(new String[] { "0", "90", "180", "270" });
rotationBox.setEditable(true);
rotationBox.setPreferredSize(new Dimension(rotationBox.getPreferredSize().width, toolbar.getHeight()));
rotationBox.setMaximumSize(new Dimension(100, 100));
toolbar.add(rotationBox);
getContentPane().add(toolbar, BorderLayout.NORTH);
rotationBox.addActionListener(actionListener);
scalingBox.addActionListener(actionListener);
}
private void saveFile() {
JFileChooser chooser = new JFileChooser();
chooser.addChoosableFileFilter(new FileFilterer(new String[] { "png" }, "PNG (*.png)"));
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
int approved = chooser.showSaveDialog(null);
if (approved == JFileChooser.APPROVE_OPTION) {
File file = chooser.getSelectedFile();
String fileToSave = file.getAbsolutePath();
if (!fileToSave.toLowerCase().endsWith(".png")) {
file = new File(fileToSave + ".png");
}
try {
ImageIO.write(image, "png", file);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void openFile() {
JFileChooser open = new JFileChooser(".");
open.setFileSelectionMode(JFileChooser.FILES_ONLY);
String[] png = new String[] { "jb2", "jbig2" };
open.addChoosableFileFilter(new FileFilterer(png, "JBIG2 (jb2, jbig2)"));
int resultOfFileSelect = open.showOpenDialog(mainFrame);
if (resultOfFileSelect == JFileChooser.APPROVE_OPTION) {
/** reset rotation */
rotation = 0;
rotationItem = "0";
rotationBox.setSelectedItem(rotationItem);
/** reset scaling */
scaling = 1;
scalingItem = "Window";
scalingBox.setSelectedItem(scalingItem);
decoder = new JBIG2Decoder();
try {
decoder.decodeJBIG2(open.getSelectedFile());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JBIG2Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// navToolbar.open();
navToolbar.setCurrentPage(1);
navToolbar.setTotalNoOfPages(decoder.getNumberOfPages());
currentPage = 1;
image = decoder.getPageAsBufferedImage(currentPage - 1);
setScalingAndRotation();
}
}
private void setScalingAndRotation() {
if (image == null)
return;
String selectedScaling = (String) scalingBox.getSelectedItem();
if (selectedScaling.equals("Window")) {
int windowWidth = jsp.getWidth();
int windowHeight = jsp.getHeight();
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
if (windowWidth / (double) imageWidth < windowHeight / (double) imageHeight) { // scale by width
scaleToWidth();
} else { // scale by height
scaleToHeight();
}
jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
} else {
jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
if (selectedScaling.equals("Height")) {
scaleToHeight();
} else if (selectedScaling.equals("Width")) {
scaleToWidth();
} else { // this might be an int
try {
int scale = Integer.parseInt(selectedScaling);
this.scaling = scale / (double) 100;
} catch (NumberFormatException e) { // not a number
e.printStackTrace();
scalingBox.setSelectedItem(scalingItem);
return;
}
}
}
String selectedRotation = (String) rotationBox.getSelectedItem();
try {
this.rotation = Integer.parseInt(selectedRotation);
} catch (NumberFormatException e) { // not a number
e.printStackTrace();
rotationBox.setSelectedItem(rotationItem);
return;
}
Image scaledImage = image.getScaledInstance((int) (image.getWidth() * scaling), -1, Image.SCALE_DEFAULT);
BufferedImage rotatedImage = rotate(toBufferedImage(scaledImage), rotation * Math.PI / 180);
imageLabel.setIcon(new ImageIcon(rotatedImage));
scalingItem = (String) scalingBox.getSelectedItem();
}
private void setRotation() {
String selectedRotation = (String) rotationBox.getSelectedItem();
try {
this.rotation = Integer.parseInt(selectedRotation);
} catch (NumberFormatException e) { // not a number
e.printStackTrace();
rotationBox.setSelectedItem(rotationItem);
return;
}
Image rotatedImage = rotate(image, rotation * Math.PI / 180);
imageLabel.setIcon(new ImageIcon(rotatedImage));
rotationItem = (String) rotationBox.getSelectedItem();
}
private void scaleToWidth() {
if (image == null)
return;
scaling = (jsp.getWidth()) / (double) image.getWidth();
}
private void scaleToHeight() {
if (image == null)
return;
scaling = (jsp.getHeight()) / (double) image.getHeight();
}
private static BufferedImage rotate(BufferedImage src, double angle) {
if (src == null)
return null;
int w = src.getWidth();
int h = src.getHeight();
int newW = (int) (Math.round(h * Math.abs(Math.sin(angle)) + w * Math.abs(Math.cos(angle))));
int newH = (int) (Math.round(h * Math.abs(Math.cos(angle)) + w * Math.abs(Math.sin(angle))));
AffineTransform at = AffineTransform.getTranslateInstance((newW - w) / 2, (newH - h) / 2);
at.rotate(angle, w / 2, h / 2);
BufferedImage dst = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = dst.createGraphics();
g.drawRenderedImage(src, at);
g.dispose();
return dst;
}
private static boolean hasAlpha(Image image) {
// If buffered image, the color model is readily available
if (image instanceof BufferedImage) {
BufferedImage bimage = (BufferedImage) image;
return bimage.getColorModel().hasAlpha();
}
// Use a pixel grabber to retrieve the image's color model;
// grabbing a single pixel is usually sufficient
PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
try {
pg.grabPixels();
} catch (InterruptedException e) {
e.printStackTrace();
}
// Get the image's color model
ColorModel cm = pg.getColorModel();
return cm.hasAlpha();
}
private BufferedImage toBufferedImage(Image image) {
if (image instanceof BufferedImage) {
return (BufferedImage) image;
}
// This code ensures that all the pixels in the image are loaded
image = new ImageIcon(image).getImage();
// Determine if the image has transparent pixels; for this method's
// implementation, see e661 Determining If an Image Has Transparent
// Pixels
boolean hasAlpha = hasAlpha(image);
// Create a buffered image with a format that's compatible with the
// screen
BufferedImage bimage = null;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
try {
// Determine the type of transparency of the new buffered image
int transparency = Transparency.OPAQUE;
if (hasAlpha) {
transparency = Transparency.BITMASK;
}
// Create the buffered image
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
bimage = gc.createCompatibleImage(image.getWidth(null), image.getHeight(null), transparency);
} catch (HeadlessException e) {
// The system does not have a screen
}
if (bimage == null) {
// Create a buffered image using the default color model
int type = BufferedImage.TYPE_INT_RGB;
if (hasAlpha) {
type = BufferedImage.TYPE_INT_ARGB;
}
bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
}
// Copy image to buffered image
Graphics g = bimage.createGraphics();
// Paint the image onto the buffered image
g.drawImage(image, 0, 0, null);
g.dispose();
return bimage;
}
public static void displayJBIG2AsImage(JBIG2Bitmap bitmap) {
byte[] bytes = bitmap.getData(true);
if (bytes == null)
return;
// make a a DEEP copy so we cant alter
int len = bytes.length;
byte[] copy = new byte[len];
System.arraycopy(bytes, 0, copy, 0, len);
int width = bitmap.getWidth();
int height = bitmap.getHeight();
/** create an image from the raw data */
DataBuffer db = new DataBufferByte(copy, copy.length);
WritableRaster raster = Raster.createPackedRaster(db, width, height, 1, null);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);
image.setData(raster);
Image scaledImage = image.getScaledInstance(500, -1, Image.SCALE_AREA_AVERAGING);
BufferedImage result = new BufferedImage(scaledImage.getWidth(null), scaledImage.getHeight(null), BufferedImage.TYPE_INT_BGR);
Graphics2D g = result.createGraphics();
g.drawImage(scaledImage, 0, 0, null);
g.dispose();
JLabel label = new JLabel(new ImageIcon(result));
JOptionPane.showConfirmDialog(null, label, "JBIG2 Display", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE);
}
public JBIG2Decoder getDecoder() {
return decoder;
}
public void displayPage(int page) {
if (image != null && page > 0 && page <= decoder.getNumberOfPages()) {
image = decoder.getPageAsBufferedImage(page - 1);
currentPage = page;
setScalingAndRotation();
navToolbar.setCurrentPage(currentPage);
}
}
public int getCurrentPage() {
return currentPage;
}
}