import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import common.ResourcesToAccess;
public class RecordingStartingThread extends Thread{
#Override
public void run(){
JFrame f = new JFrame();
ImageIcon reel = new ImageIcon("src/images/reel.GIF");
JLabel label = new JLabel(reel);
reel.setImageObserver(label);
f.getContentPane().add(label);
f.setUndecorated(true);
f.setSize(300, 300);
f.setVisible(true);
}
public static void main(String[] args) {
new RecordingStartingThread().start();
}
}
Issue: GIF plays extremely fast.
Question: How do I make sure that GIF plays at a normal speed?
As for GIF speed playback - I've encountered this problem too. If I remember correctly this was caused by the "default" (or not provided?) value for frame rate in GIF file. Some web browsers "overrided" that frame rate so that GIF played correctly.
As a result I created a class that converts GIF (read GIF -> write GIF) and give frame rate provided by the user. com.madgag.gif.fmsware.AnimatedGifEncoder class is an external library that I link to the project via Maven: animated-gif-lib-1.0.jar
public final class GIFUtils {
private GIFUtils() {
}
public static List<BufferedImage> extractFrames(String filePath) throws IOException {
return extractFrames(new File(filePath));
}
public static List<BufferedImage> extractFrames(File file) throws IOException {
List<BufferedImage> imgs = new LinkedList<BufferedImage>();
ImageReader reader = ImageIO.getImageReadersBySuffix("GIF").next();
ImageInputStream in = null;
try {
in = ImageIO.createImageInputStream(new FileInputStream(file));
reader.setInput(in);
BufferedImage img = null;
int count = reader.getNumImages(true);
for(int i = 0; i < count; i++) {
Node tree = reader.getImageMetadata(i).getAsTree("javax_imageio_gif_image_1.0");
int x = Integer.valueOf(tree.getChildNodes().item(0).getAttributes()
.getNamedItem("imageLeftPosition").getNodeValue());
int y = Integer.valueOf(tree.getChildNodes().item(0).getAttributes()
.getNamedItem("imageTopPosition").getNodeValue());
BufferedImage image = reader.read(i);
if(img == null) {
img = new BufferedImage(image.getWidth() + x, image.getHeight() + y,
BufferedImage.TYPE_4BYTE_ABGR);
}
Graphics2D g = img.createGraphics();
ImageUtils.setBestRenderHints(g);
g.drawImage(image, x, y, null);
imgs.add(ImageUtils.copy(img));
}
}
finally {
if(in != null) {
in.close();
}
}
return imgs;
}
public static void writeGif(List<BufferedImage> images, File gifFile, int millisForFrame)
throws FileNotFoundException, IOException {
BufferedImage firstImage = images.get(0);
int type = firstImage.getType();
ImageOutputStream output = new FileImageOutputStream(gifFile);
// create a gif sequence with the type of the first image, 1 second
// between frames, which loops continuously
GifSequenceWriter writer = new GifSequenceWriter(output, type, 100, false);
// write out the first image to our sequence...
writer.writeToSequence(firstImage);
for(int i = 1; i < images.size(); i++) {
BufferedImage nextImage = images.get(i);
writer.writeToSequence(nextImage);
}
writer.close();
output.close();
}
public static Image createGif(List<BufferedImage> images, int millisForFrame) {
AnimatedGifEncoder g = new AnimatedGifEncoder();
ByteArrayOutputStream out = new ByteArrayOutputStream(5 * 1024 * 1024);
g.start(out);
g.setDelay(millisForFrame);
g.setRepeat(1);
for(BufferedImage i : images) {
g.addFrame(i);
}
g.finish();
byte[] bytes = out.toByteArray();
return Toolkit.getDefaultToolkit().createImage(bytes);
}
And GifSequenceWriter looks like this:
public class GifSequenceWriter {
protected ImageWriter gifWriter;
protected ImageWriteParam imageWriteParam;
protected IIOMetadata imageMetaData;
public GifSequenceWriter(ImageOutputStream outputStream, int imageType, int timeBetweenFramesMS,
boolean loopContinuously) throws IIOException, IOException {
gifWriter = getWriter();
imageWriteParam = gifWriter.getDefaultWriteParam();
ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(imageType);
imageMetaData = gifWriter.getDefaultImageMetadata(imageTypeSpecifier, imageWriteParam);
String metaFormatName = imageMetaData.getNativeMetadataFormatName();
IIOMetadataNode root = (IIOMetadataNode) imageMetaData.getAsTree(metaFormatName);
IIOMetadataNode graphicsControlExtensionNode = getNode(root, "GraphicControlExtension");
graphicsControlExtensionNode.setAttribute("disposalMethod", "none");
graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE");
graphicsControlExtensionNode.setAttribute("transparentColorFlag", "FALSE");
graphicsControlExtensionNode.setAttribute("delayTime", Integer.toString(timeBetweenFramesMS / 10));
graphicsControlExtensionNode.setAttribute("transparentColorIndex", "0");
IIOMetadataNode commentsNode = getNode(root, "CommentExtensions");
commentsNode.setAttribute("CommentExtension", "Created by MAH");
IIOMetadataNode appEntensionsNode = getNode(root, "ApplicationExtensions");
IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension");
child.setAttribute("applicationID", "NETSCAPE");
child.setAttribute("authenticationCode", "2.0");
int loop = loopContinuously ? 0 : 1;
child.setUserObject(new byte[] { 0x1, (byte) (loop & 0xFF), (byte) (loop >> 8 & 0xFF) });
appEntensionsNode.appendChild(child);
imageMetaData.setFromTree(metaFormatName, root);
gifWriter.setOutput(outputStream);
gifWriter.prepareWriteSequence(null);
}
public void writeToSequence(RenderedImage img) throws IOException {
gifWriter.writeToSequence(new IIOImage(img, null, imageMetaData), imageWriteParam);
}
public void close() throws IOException {
gifWriter.endWriteSequence();
}
private static ImageWriter getWriter() throws IIOException {
Iterator<ImageWriter> iter = ImageIO.getImageWritersBySuffix("gif");
if(!iter.hasNext()) {
throw new IIOException("No GIF Image Writers Exist");
}
return iter.next();
}
private static IIOMetadataNode getNode(IIOMetadataNode rootNode, String nodeName) {
int nNodes = rootNode.getLength();
for(int i = 0; i < nNodes; i++) {
if(rootNode.item(i).getNodeName().compareToIgnoreCase(nodeName) == 0) {
return (IIOMetadataNode) rootNode.item(i);
}
}
IIOMetadataNode node = new IIOMetadataNode(nodeName);
rootNode.appendChild(node);
return node;
}
}
The easiest fix for this problem is to just create a .gif file which is "well-formed", i.e. contains the appropriate frame rate. This can be achieved with the help of various online converters, just google "gif speed changer".
Related
I am trying to read image objects from a PDF document. The image comes out as black background and white text. How can I reverse that. the image in the pdf, is white foreground and black background.
Here is the code, main piece for loading the image component
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.PRStream;
import com.itextpdf.text.pdf.PdfDictionary;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.parser.ImageRenderInfo;
import com.itextpdf.text.pdf.parser.PdfImageObject;
import com.itextpdf.text.pdf.parser.RenderListener;
import com.itextpdf.text.pdf.parser.TextRenderInfo;
public class MyImageRenderListener implements RenderListener {
/**
* The new document to which we've added a border rectangle.
*/
protected String path = "";
/**
* Creates a RenderListener that will look for images.
*/
public MyImageRenderListener(String path) {
this.path = path;
}
/**
* #see com.itextpdf.text.pdf.parser.RenderListener#beginTextBlock()
*/
public void beginTextBlock() {
}
/**
* #see com.itextpdf.text.pdf.parser.RenderListener#endTextBlock()
*/
public void endTextBlock() {
}
/**
* #see com.itextpdf.text.pdf.parser.RenderListener#renderImage(
*com.itextpdf.text.pdf.parser.ImageRenderInfo)
*/
public void renderImage(final ImageRenderInfo renderInfo) {
try {
String filename;
FileOutputStream os;
PdfImageObject image = renderInfo.getImage();
PdfImageObject tmp = null;
PdfName filter = (PdfName) image.get(PdfName.FILTER);
///
PdfDictionary imageDictionary = image.getDictionary();
// Try SMASK, SMASKINDATA
PRStream maskStream = (PRStream) imageDictionary.getAsStream(PdfName.SMASK);
// todo - required - black white - fix
PdfImageObject maskImage = new PdfImageObject(maskStream);
image = maskImage;
if (PdfName.DCTDECODE.equals(filter)) {
filename = String.format(path, renderInfo.getRef().getNumber(), "jpg");
os = new FileOutputStream(filename);
os.write(image.getImageAsBytes());
os.flush();
os.close();
} else if (PdfName.JPXDECODE.equals(filter)) {
filename = String.format(path, renderInfo.getRef().getNumber(), "jp2");
os = new FileOutputStream(filename);
os.write(image.getImageAsBytes());
os.flush();
os.close();
} else if (PdfName.JBIG2DECODE.equals(filter)) {
// ignore: filter not supported.
} else {
BufferedImage awtimage = renderInfo.getImage().getBufferedImage();
if (awtimage != null) {
filename = String.format(path, renderInfo.getRef().getNumber(), "png");
ImageIO.write(awtimage, "png", new FileOutputStream(filename));
}
}
try {
final String newfile = String.format(path, renderInfo.getRef().getNumber(), ".x.", "png");
BufferedImage bi = image.getBufferedImage();
BufferedImage newBi = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_USHORT_GRAY);
newBi.getGraphics().drawImage(bi, 0, 0, null);
ImageIO.write(newBi, "png", new FileOutputStream(newfile));
} catch(final Exception e) {
e.printStackTrace();;
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static Image makeBlackAndWhitePng(PdfImageObject image) throws IOException, DocumentException {
BufferedImage bi = image.getBufferedImage();
BufferedImage newBi = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_USHORT_GRAY);
newBi.getGraphics().drawImage(bi, 0, 0, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(newBi, "png", baos);
return Image.getInstance(baos.toByteArray());
}
/**
* #see com.itextpdf.text.pdf.parser.RenderListener#renderText(
*com.itextpdf.text.pdf.parser.TextRenderInfo)
*/
public void renderText(TextRenderInfo renderInfo) {
}
}
And code around loading the pages
public static void readImages(final PdfReader reader, final File filex) throws IOException {
for (int i = 0; i < reader.getXrefSize(); i++) {
PdfObject pdfobj = reader.getPdfObject(i);
if (pdfobj == null || !pdfobj.isStream()) {
continue;
}
PdfStream stream = (PdfStream) pdfobj;
PdfObject pdfsubtype = stream.get(PdfName.SUBTYPE);
if (pdfsubtype != null && pdfsubtype.toString().equals(PdfName.IMAGE.toString())) {
byte[] img = PdfReader.getStreamBytesRaw((PRStream) stream);
FileOutputStream out = new FileOutputStream(new File(filex.getParentFile(), String.format("%1$05d", i) + ".jpg"));
out.write(img);
out.flush();
out.close();
}
}
}
To combine my comments:
What you see, merely is the soft mask of the image which contains transparency information, white = opaque, black = transparent. The base image actually is all black but only where the mask indicates opaque, that image black is drawn. Thus it looks like reversed.
You can use image manipulation libraries to invert a bitmap. Simply googl'ing for "imageio invert image" returns this, this, and numerous other interesting matches.
In trying to make an animated GIF from an image with transparency this code is producing a ghosting effect from the earlier image frames.
Image of 3rd frame, which shows the first two frames beneath the final frame
How can the code be altered to produce a 'clean' animated image for all frames?
Note: The code uses two methods, written by GeoffTitmus & Maxideon, that were formerly on the Oracle forums site. The links I first saw referenced in the code (in the JavaDocs section) have long since disappeared, so were removed. Other than that, only a few JavaDoc warnings were corrected, otherwise they are exactly as found from around the internet or as used in my older code projects.
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.io.*;
import javax.imageio.*;
import javax.imageio.metadata.IIOInvalidTreeException;
import javax.imageio.stream.*;
import javax.imageio.metadata.*;
import org.w3c.dom.Node;
import java.net.URL;
public class AnimatedGifWithTransparency {
private JComponent ui = null;
public final String PATH = "https://i.stack.imgur.com/P59NF.png";
private BufferedImage image;
AnimatedGifWithTransparency() {
try {
initUI();
} catch (IOException ex) {
ex.printStackTrace();
}
}
/**
* #author GeoffTitmus
* #param out OutputStream A stream in which to store the animation.
* #param frames BufferedImage[] Array of BufferedImages, the frames of the
* animation.
* #param delayTimes String[] Array of Strings, representing the frame delay
* times.
* #throws Exception
*/
public static void saveAnimate(OutputStream out, BufferedImage[] frames, String[] delayTimes) throws Exception {
ImageWriter iw = ImageIO.getImageWritersByFormatName("gif").next();
ImageOutputStream ios = ImageIO.createImageOutputStream(out);
iw.setOutput(ios);
iw.prepareWriteSequence(null);
for (int i = 0; i < frames.length; i++) {
BufferedImage src = frames[i];
ImageWriteParam iwp = iw.getDefaultWriteParam();
IIOMetadata metadata = iw.getDefaultImageMetadata(new ImageTypeSpecifier(src), iwp);
configure(metadata, delayTimes[i], i);
IIOImage ii = new IIOImage(src, null, metadata);
iw.writeToSequence(ii, null);
}
iw.endWriteSequence();
ios.close();
}
/**
* #author Maxideon
* #param meta
* #param delayTime String Frame delay for this frame.
* #param imageIndex
*/
public static void configure(IIOMetadata meta,
String delayTime,
int imageIndex) {
String metaFormat = meta.getNativeMetadataFormatName();
if (!"javax_imageio_gif_image_1.0".equals(metaFormat)) {
throw new IllegalArgumentException(
"Unfamiliar gif metadata format: " + metaFormat);
}
Node root = meta.getAsTree(metaFormat);
//find the GraphicControlExtension node
Node child = root.getFirstChild();
while (child != null) {
if ("GraphicControlExtension".equals(child.getNodeName())) {
break;
}
child = child.getNextSibling();
}
IIOMetadataNode gce = (IIOMetadataNode) child;
gce.setAttribute("userDelay", "FALSE");
gce.setAttribute("delayTime", delayTime);
//only the first node needs the ApplicationExtensions node
if (imageIndex == 0) {
IIOMetadataNode aes
= new IIOMetadataNode("ApplicationExtensions");
IIOMetadataNode ae
= new IIOMetadataNode("ApplicationExtension");
ae.setAttribute("applicationID", "NETSCAPE");
ae.setAttribute("authenticationCode", "2.0");
byte[] uo = new byte[]{
//last two bytes is an unsigned short (little endian) that
//indicates the the number of times to loop.
//0 means loop forever.
0x1, 0x0, 0x0
};
ae.setUserObject(uo);
aes.appendChild(ae);
root.appendChild(aes);
}
try {
meta.setFromTree(metaFormat, root);
} catch (IIOInvalidTreeException e) {
//shouldn't happen
throw new Error(e);
}
}
private BufferedImage getShiftedImage(int frame) {
int w = image.getWidth();
int h = image.getHeight();
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.getGraphics();
int xOffPos = frame*w/3;
int xOffNeg = xOffPos-w;
g.drawImage(image, xOffNeg, 0, ui);
g.drawImage(image, xOffPos, 0, ui);
g.dispose();
return bi;
}
public final void initUI() throws IOException {
if (ui != null) {
return;
}
image = ImageIO.read(new URL(PATH));
ui = new JPanel(new BorderLayout(4, 4));
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
BufferedImage[] frames = {
getShiftedImage(0),
getShiftedImage(1),
getShiftedImage(2)
};
String[] delayTimes = {
"50","50","50"
};
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
saveAnimate(baos, frames, delayTimes);
} catch (Exception ex) {
ex.printStackTrace();
return;
}
byte[] bytes = baos.toByteArray();
ui.add(new JLabel(new ImageIcon(bytes)));
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
AnimatedGifWithTransparency o = new AnimatedGifWithTransparency();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
};
SwingUtilities.invokeLater(r);
}
}
I want to get the text which I have marked in my pdf file. I iterate over the PdfAnnotation of the PdfPage. The annoation has a method getRectangle() which return a PdfArray. I can't create from the PdfArray an Rectangle runtime-class (object/instance) which has the position and overlays over the marked text of the annotation.
With the Rectangle from annotation I wanto to filter via LocationtextExtratctionStrategy the marked content.
I written the following code to get it with iText:
package biz.hochguertel;
import com.itextpdf.kernel.color.DeviceCmyk;
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.*;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
import com.itextpdf.kernel.pdf.annot.PdfTextMarkupAnnotation;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.canvas.parser.EventType;
import com.itextpdf.kernel.pdf.canvas.parser.PdfCanvasProcessor;
import com.itextpdf.kernel.pdf.canvas.parser.data.IEventData;
import com.itextpdf.kernel.pdf.canvas.parser.data.TextRenderInfo;
import com.itextpdf.kernel.pdf.canvas.parser.filter.TextRegionEventFilter;
import com.itextpdf.kernel.pdf.canvas.parser.listener.FilteredEventListener;
import com.itextpdf.kernel.pdf.canvas.parser.listener.LocationTextExtractionStrategy;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class AppIText {
private String filePath = getClass().getClassLoader().getResource("itext/OCA/549_OCA_Java_SE_7_Programmer_I_Certification.pdf").getFile();
private static String DEST = "demo-output/549_OCA_Java_SE_7_Programmer_I_Certification.pdf";
private PdfDocument pdfDocument;
private PdfDocument pdfWriteDoc;
public void before() throws IOException {
File file = new File(DEST);
file.getParentFile().mkdir();
if (file.exists()) {
file.delete();
}
pdfDocument = new PdfDocument(new PdfReader(filePath));
pdfWriteDoc = new PdfDocument(new PdfWriter(DEST));
}
public static void main(String[] args) throws IOException {
AppIText appIText = new AppIText();
appIText.before();
appIText.process();
appIText.close();
}
private void close() {
pdfDocument.close();
pdfWriteDoc.close();
}
private void process() {
for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++) {
PdfPage page = pdfDocument.getPage(i);
List<PdfPage> newPdfPages = pdfDocument.copyPagesTo(i, i, pdfWriteDoc);
PdfPage newPage = null;
if (newPdfPages.size() > 0) {
newPage = newPdfPages.get(0);
}
List<PdfAnnotation> annotations = page.getAnnotations();
for (PdfAnnotation annotation : annotations) {
if (annotation.getContents() != null) {
System.out.println(annotation.getContents());
if (annotation instanceof PdfTextMarkupAnnotation) {
PdfArray rectangleArray = annotation.getRectangle();
double x = ((PdfNumber) rectangleArray.get(0)).getValue();
double y = ((PdfNumber) rectangleArray.get(1)).getValue();
double xWidth = ((PdfNumber) rectangleArray.get(2)).getValue();
double yWidth = ((PdfNumber) rectangleArray.get(3)).getValue();
System.out.println(String.format("x=%s,y=%s,w=%s,h=%s", x, y, xWidth, yWidth));
Rectangle rectangle = new Rectangle((float) x, (float) y, (float) xWidth, (float) yWidth);
PdfCanvas canvas = new PdfCanvas(newPage);
canvas.setFillColor(new DeviceCmyk(1, 0, 0, 0))
.rectangle(rectangle)
.fillStroke()
;
FontFilter fontFilter = new FontFilter(rectangle);
FilteredEventListener listener = new FilteredEventListener();
LocationTextExtractionStrategy extractionStrategy = listener.attachEventListener(new LocationTextExtractionStrategy(), fontFilter);
new PdfCanvasProcessor(listener).processPageContent(page);
String actualText = extractionStrategy.getResultantText();
}
}
}
}
}
}
class RectangleEventHandler implements IEventHandler {
#Override
public void handleEvent(Event event) {
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfDocument pdfDoc = docEvent.getDocument();
PdfPage page = docEvent.getPage();
PdfCanvas canvas = new PdfCanvas(page.getLastContentStream(), page.getResources(), pdfDoc);
canvas.setFillColor(new DeviceCmyk(1, 0, 0, 0))
.rectangle(new Rectangle(20, 10, 10, 820))
.fillStroke();
}
}
class FontFilter extends TextRegionEventFilter {
public FontFilter(Rectangle filterRect) {
super(filterRect);
}
#Override
public boolean accept(IEventData data, EventType type) {
if (type.equals(EventType.RENDER_TEXT)) {
TextRenderInfo renderInfo = (TextRenderInfo) data;
PdfFont font = renderInfo.getFont();
if (null != font) {
String fontName = font.getFontProgram().getFontNames().getFontName();
return fontName.endsWith("Bold") || fontName.endsWith("Oblique");
}
}
return false;
}
}
How to create an rectangle which matches the marked area to extract only the marked (highlighted) text from the pdf?
Or is there an different way to get the marked text ov an annotation from an pdf?
The following main part of the code above is to apply:
Rectangle rectangle = new Rectangle((float) x, (float) y, (float) xWidth, (float) yWidth);
I found the solution.
The Rectancle calculation:
x: annotation.x
y: annotation.y
width: annotation.width - annotation.x
height: annotation.height - annotation.y
What I get now:
Visual Debug (if LOG_LEVEL >= 100):
Extracted Content:
13:50:01.323 [main] INFO b.h.AppIText - Annotation contents: q(7.1).explain(1)
13:50:01.323 [main] INFO b.h.AppIText - rectangleArray: x=90.0338, y=438.245, w=468.33, h=489.749
13:50:01.323 [main] INFO b.h.AppIText - pageSizeWithRotation: x=0.0, y=0.0, w=531.0, h=666.0, top=666.0, bottom=0.0, left=0.0, right=531.0
13:50:01.337 [main] INFO b.h.AppIText - str: Purpose: A finally block can’t be placed before the catch blocks. <cut here because the book is not free, but I get the complete marked text..>
My fixed code looks now:
package biz.hochguertel;
import com.itextpdf.kernel.color.DeviceCmyk;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.*;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
import com.itextpdf.kernel.pdf.annot.PdfTextMarkupAnnotation;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.canvas.parser.PdfTextExtractor;
import com.itextpdf.kernel.pdf.canvas.parser.filter.TextRegionEventFilter;
import com.itextpdf.kernel.pdf.canvas.parser.listener.FilteredTextEventListener;
import com.itextpdf.kernel.pdf.canvas.parser.listener.ITextExtractionStrategy;
import com.itextpdf.kernel.pdf.canvas.parser.listener.LocationTextExtractionStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
* With the help of the following documentations:
* - http://developers.itextpdf.com/content/best-itext-questions-stackoverview/content-parsing-extraction-and-redaction-text/itext7-how-read-text-specific-position
*/
public class AppIText {
private static final Logger LOGGER = LoggerFactory.getLogger(AppIText.class);
private static int LOG_LEVEL = 0;
private final static int VISUAL_DEBUG = 100;
private String filePath = getClass().getClassLoader().getResource("itext/OCA/393-394,549-550_OCA_Java_SE_7_Programmer_I_Certification.pdf").getFile();
private static String DEST = "demo-output/393-394,549-550_OCA_Java_SE_7_Programmer_I_Certification.pdf";
private PdfDocument pdfDocument;
private PdfDocument pdfWriteDoc;
public void before() throws IOException {
File file = new File(DEST);
file.getParentFile().mkdir();
if (file.exists()) {
file.delete();
}
pdfDocument = new PdfDocument(new PdfReader(filePath));
pdfWriteDoc = new PdfDocument(new PdfWriter(DEST));
}
public static void main(String[] args) throws IOException {
AppIText appIText = new AppIText();
appIText.before();
appIText.process();
}
private void process() {
for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++) {
PdfPage page = pdfDocument.getPage(i);
List<PdfPage> newPdfPages = pdfDocument.copyPagesTo(i, i, pdfWriteDoc);
PdfPage newPage = null;
if (newPdfPages.size() > 0) {
newPage = newPdfPages.get(0);
}
List<PdfAnnotation> annotations = page.getAnnotations();
for (PdfAnnotation annotation : annotations) {
if (annotation.getContents() != null) {
System.out.println();
LOGGER.info("Annotation contents: {}", annotation.getContents());
if (annotation instanceof PdfTextMarkupAnnotation) {
PdfArray rectangleArray = annotation.getRectangle();
LOGGER.info("rectangleArray: x={}, y={}, w={}, h={}",
rectangleArray.get(0),
rectangleArray.get(1),
rectangleArray.get(2),
rectangleArray.get(3)
);
Rectangle pageSizeWithRotation = page.getCropBox();
LOGGER.info("pageSizeWithRotation: x={}, y={}, w={}, h={}, top={}, bottom={}, left={}, right={}",
pageSizeWithRotation.getX(),
pageSizeWithRotation.getY(),
pageSizeWithRotation.getWidth(),
pageSizeWithRotation.getHeight(),
pageSizeWithRotation.getTop(),
pageSizeWithRotation.getBottom(),
pageSizeWithRotation.getLeft(),
pageSizeWithRotation.getRight()
);
float x = ((PdfNumber) rectangleArray.get(0)).floatValue();
float y = ((PdfNumber) rectangleArray.get(1)).floatValue();
float width = ((PdfNumber) rectangleArray.get(2)).floatValue() - x;
float height = ((PdfNumber) rectangleArray.get(3)).floatValue() - y;
Rectangle rectangle = new Rectangle(
x,
y,
width,
height
);
//13:10:33.097 [main] INFO b.h.AppIText - Annotation contents: q(7.1).explain(1)
//13:10:33.107 [main] INFO b.h.AppIText - rectangleArray: x=90.0338, y=438.245, w=468.33, h=489.749
//13:10:33.107 [main] INFO b.h.AppIText - pageSizeWithRotation: x=0.0, y=0.0, w=531.0, h=666.0, top=666.0, bottom=0.0, left=0.0, right=531.0
//width: 468.33f - 90.0388f,
//height: 489.749f - 438.245f
if (LOG_LEVEL >= VISUAL_DEBUG) {
PdfCanvas canvas = new PdfCanvas(newPage);
canvas.setFillColor(new DeviceCmyk(1, 0, 0, 0))
.rectangle(rectangle)
.fillStroke();
}
TextRegionEventFilter regionFilter = new TextRegionEventFilter(rectangle);
ITextExtractionStrategy strategy = new FilteredTextEventListener(new LocationTextExtractionStrategy(), regionFilter);
String str = PdfTextExtractor.getTextFromPage(page, strategy) + "\n";
LOGGER.info("str: {}", str);
}
}
}
}
pdfDocument.close();
pdfWriteDoc.close();
}
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
The code is being modified a bit . I added a button to the Jpanel whose action event save the image on the disk .
Source Code
package ImageResize;
import java.awt.image.BufferedImage;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.RenderedImage;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.event.*;
import javax.imageio.*;
import java.io.*;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import java.util.Locale;
import javax.swing.filechooser.FileNameExtensionFilter;
class ImageCompressionDemo {
private BufferedImage originalImage;
private BufferedImage textImage;
private JPanel gui;
private JCheckBox antialiasing;
private
JCheckBox rendering;
private JCheckBox fractionalMetrics;
private JCheckBox strokeControl;
private JCheckBox colorRendering;
private JCheckBox dithering;
private JComboBox textAntialiasing;
private JComboBox textLcdContrast;
private JLabel jpegLabel;
private JLabel pngLabel;
private JTextArea output;
private JSlider quality;
private JButton saveButton;
private int pngSize;
private int jpgSize;
final static Object[] VALUES_TEXT_ANTIALIASING = {
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON,
RenderingHints.VALUE_TEXT_ANTIALIAS_GASP,
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR,
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB,
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VBGR,
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB
};
final static Object[] VALUES_TEXT_LCD_CONTRAST = {
new Integer(100),
new Integer(150),
new Integer(200),
new Integer(250)
};
ImageCompressionDemo(BufferedImage inputImage) {
int width = 280;
int height = 100;
gui = new JPanel(new BorderLayout(3,4));
gui.setPreferredSize(new Dimension(400, 600));
quality = new JSlider(JSlider.VERTICAL, 0, 100, 50);
quality.setSnapToTicks(true);
quality.setPaintTicks(true);
quality.setPaintLabels(true);
quality.setMajorTickSpacing(10);
quality.setMinorTickSpacing(1);
quality.addChangeListener( new ChangeListener(){
public void stateChanged(ChangeEvent ce) {
updateImages();
}
} );
gui.add(quality, BorderLayout.WEST);
originalImage = inputImage;
textImage =inputImage;
JPanel controls = new JPanel(new GridLayout(0,1,0,0));
antialiasing = new JCheckBox("Anti-aliasing", false);
rendering = new JCheckBox("Rendering - Quality", true);
fractionalMetrics = new JCheckBox("Fractional Metrics", true);
strokeControl = new JCheckBox("Stroke Control - Pure", false);
colorRendering = new JCheckBox("Color Rendering - Quality", true);
dithering = new JCheckBox("Dithering", false);
saveButton =new JButton("Save Image");
saveButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
BufferedImage img = (BufferedImage)getJpegCompressedImage(originalImage);
File outputfile = new File("C:/Users/uday/Desktop/newImage.jpg");
ImageIO.write(img, "jpg", outputfile);
} catch (IOException ex) {
Logger.getLogger(ImageCompressionDemo.class.getName()).log(Level.SEVERE, null, ex);
}
} });
controls.add(antialiasing);
controls.add(fractionalMetrics);
textLcdContrast = new JComboBox(VALUES_TEXT_LCD_CONTRAST);
JPanel lcdContrastPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
lcdContrastPanel.add(textLcdContrast);
lcdContrastPanel.add(new JLabel("Text LCD Contrast"));
controls.add(lcdContrastPanel);
textAntialiasing = new JComboBox(VALUES_TEXT_ANTIALIASING);
controls.add(textAntialiasing);
controls.add(dithering);
controls.add(rendering);
controls.add(colorRendering);
controls.add(strokeControl);
ItemListener itemListener = new ItemListener(){
public void itemStateChanged(ItemEvent e) {
updateImages();
}
};
antialiasing.addItemListener(itemListener);
rendering.addItemListener(itemListener);
fractionalMetrics.addItemListener(itemListener);
strokeControl.addItemListener(itemListener);
colorRendering.addItemListener(itemListener);
dithering.addItemListener(itemListener);
textAntialiasing.addItemListener(itemListener);
textLcdContrast.addItemListener(itemListener);
Graphics2D g2d = originalImage.createGraphics();
gui.add(controls, BorderLayout.EAST);
gui.add(saveButton,BorderLayout.BEFORE_FIRST_LINE);
JPanel images = new JPanel(new GridLayout(0,1,2,2));
images.add(new JLabel(new ImageIcon(textImage)));
try {
pngLabel = new JLabel(new ImageIcon(getPngCompressedImage(textImage)));
images.add(pngLabel);
jpegLabel = new JLabel(new ImageIcon(getJpegCompressedImage(textImage)));
images.add(jpegLabel);
} catch(IOException ioe) {
}
gui.add(images, BorderLayout.CENTER);
output = new JTextArea(4,40);
output.setEditable(false);
gui.add(new JScrollPane(output), BorderLayout.SOUTH);
updateImages();
JOptionPane.showMessageDialog(null, gui);
}
private Image getPngCompressedImage(BufferedImage image) throws IOException {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
ImageIO.write( image, "png", outStream );
pngSize = outStream.toByteArray().length;
BufferedImage compressedImage =
ImageIO.read(new ByteArrayInputStream(outStream.toByteArray()));
return compressedImage;
}
private Image getJpegCompressedImage(BufferedImage image) throws IOException {
float qualityFloat = (float)quality.getValue()/100f;
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
ImageWriter imgWriter = ImageIO.getImageWritersByFormatName( "jpg" ).next();
ImageOutputStream ioStream = ImageIO.createImageOutputStream( outStream );
imgWriter.setOutput( ioStream );
JPEGImageWriteParam jpegParams = new JPEGImageWriteParam( Locale.getDefault() );
jpegParams.setCompressionMode( ImageWriteParam.MODE_EXPLICIT );
jpegParams.setCompressionQuality( qualityFloat );
imgWriter.write( null, new IIOImage( image, null, null ), jpegParams );
ioStream.flush();
ioStream.close();
imgWriter.dispose();
jpgSize = outStream.toByteArray().length;
BufferedImage compressedImage = ImageIO.read(new ByteArrayInputStream(outStream.toByteArray()));
return compressedImage;
}
private void updateText() {
StringBuilder builder = new StringBuilder();
builder.append("Fractional Metrics: \t");
builder.append( fractionalMetrics.isSelected() );
builder.append("\n");
builder.append( textAntialiasing.getSelectedItem() );
builder.append("\nPNG size: \t");
builder.append(pngSize);
builder.append(" bytes\n");
builder.append("JPG size: \t");
builder.append(jpgSize);
builder.append(" bytes \tquality: ");
builder.append(quality.getValue());
output.setText(builder.toString());
}
private void updateImages() {
int width = originalImage.getWidth();
int height = originalImage.getHeight();
Graphics2D g2dText = textImage.createGraphics();
if (antialiasing.isSelected()) {
g2dText.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
} else {
g2dText.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_OFF);
}
if (rendering.isSelected()) {
g2dText.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
} else {
g2dText.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_SPEED);
}
if (fractionalMetrics.isSelected()) {
g2dText.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
} else {
g2dText.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
}
if (strokeControl.isSelected()) {
g2dText.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_NORMALIZE);
} else {
g2dText.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE);
}
if (dithering.isSelected()) {
g2dText.setRenderingHint(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_ENABLE);
} else {
g2dText.setRenderingHint(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_DISABLE);
}
if (colorRendering.isSelected()) {
g2dText.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
} else {
g2dText.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_SPEED);
}
g2dText.setRenderingHint(RenderingHints.KEY_TEXT_LCD_CONTRAST,
textLcdContrast.getSelectedItem());
g2dText.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
textAntialiasing.getSelectedItem());
g2dText.drawImage(originalImage, 0,0, null);
try {
jpegLabel.setIcon(new ImageIcon(getJpegCompressedImage(textImage)));
pngLabel.setIcon(new ImageIcon(getPngCompressedImage(textImage)));
} catch(IOException ioe) {
}
gui.repaint();
updateText();
}
public static void main(String[] args) {
SwingUtilities.invokeLater( new Runnable() {
public void run() {
try {
FileNameExtensionFilter filter = new FileNameExtensionFilter("Pictures","jpg","png");
JFileChooser fc = new JFileChooser();
fc.setFileFilter(filter);
int returnVal = fc.showOpenDialog(null);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
String Path = file.getPath();
BufferedImage originalImage = ImageIO.read(new File(Path));
ImageCompressionDemo iwt = new ImageCompressionDemo(originalImage);
}
} catch (IOException ex) {
Logger.getLogger(ImageCompressionDemo.class.getName()).log(Level.SEVERE, null, ex);
}
}
} );
}
}
Here the Image size displayed in jpegLabel label variable is different from what is being saved on the disk . I want the size of the image saved on the disk to be of same size which is being displayed .
Reference to the Question : Need Java function that takes image and imagesize(in Kb) as input and return an image
The problem is here:
BufferedImage img = (BufferedImage)getJpegCompressedImage(originalImage);
File outputfile = new File("C:/Users/uday/Desktop/newImage.jpg");
ImageIO.write(img, "jpg", outputfile);
..when using the ImageIO class that way, it ignores whatever compression has been applied to the image and saves it using standard compression! The trick to saving the compressed image is to change the getJpegCompressedImage method to saveJpegCompressedImage, and instead of returning an Image it should declare void and save the byte[] directly to disk (using standard I/O).
E.G. as seen in this example:
Original image (unknown compression)
As seen in Example images for code and mark-up Q&As.
Saved as quality .2 (6,327 bytes)
Saved as quality .8 (18,702 bytes)
Code
import java.awt.Desktop;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.util.Locale;
import javax.imageio.*;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;
public class CompressImage {
/** TODO: This method has terrible handling of I/O.
Rewrite for production use. BNI. */
static public void saveJpegCompressedImage(
BufferedImage image,
float quality,
File file) throws Exception {
OutputStream outStream = new FileOutputStream(
new File(file, "Image-" + quality + ".jpg"));
ImageWriter imgWriter = ImageIO.
getImageWritersByFormatName("jpg").next();
ImageOutputStream ioStream =
ImageIO.createImageOutputStream(outStream);
imgWriter.setOutput(ioStream);
JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(
Locale.getDefault());
jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpegParams.setCompressionQuality(quality);
imgWriter.write(null, new IIOImage(image, null, null), jpegParams);
ioStream.flush();
ioStream.close();
imgWriter.dispose();
}
public static void main(String[] args) throws Exception {
URL url = new URL("http://i.stack.imgur.com/7bI1Y.jpg");
File f = new File(System.getProperty("user.home"));
BufferedImage bi = ImageIO.read(url);
for (float q = 0.2f; q < .9f; q += .2f) {
saveJpegCompressedImage(bi, q, f);
}
Desktop.getDesktop().open(f);
}
}
How do you read the animated GIF's control block between each frame? I'm interested in the delay between each frame. I've looked at the Javadoc for ImageReader and I'm not seeing anything.
Here's my code for reading all the frames from the animated GIF, how would I enhance it to read the metadata about each frame embedded in the animated GIF?
List<BufferedImage> list = new ArrayList<BufferedImage>();
try {
ImageReader reader = ImageIO.getImageReadersBySuffix("gif").next();
reader.setInput(ImageIO.createImageInputStream(urlImage.openStream()));
int i = reader.getMinIndex();
int numImages = reader.getNumImages(true);
while (i < numImages)
{
list.add(reader.read(i++));
}
// do stuff with frames of image...
} catch (Exception e) {
e.printStackTrace();
}
You will have to seek out "delayTime" attribute from metadata node. Use the following working example to understand:
public class GiffTest {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException {
ImageReader reader = ImageIO.getImageReadersBySuffix("gif").next();
reader.setInput(ImageIO.createImageInputStream(new FileInputStream("H:\\toonGif.gif")));
int i = reader.getMinIndex();
int numImages = reader.getNumImages(true);
IIOMetadata imageMetaData = reader.getImageMetadata(0);
String metaFormatName = imageMetaData.getNativeMetadataFormatName();
IIOMetadataNode root = (IIOMetadataNode)imageMetaData.getAsTree(metaFormatName);
IIOMetadataNode graphicsControlExtensionNode = getNode(root, "GraphicControlExtension");
System.out.println(graphicsControlExtensionNode.getAttribute("delayTime"));
}
private static IIOMetadataNode getNode(IIOMetadataNode rootNode, String nodeName) {
int nNodes = rootNode.getLength();
for (int i = 0; i < nNodes; i++) {
if (rootNode.item(i).getNodeName().compareToIgnoreCase(nodeName)== 0) {
return((IIOMetadataNode) rootNode.item(i));
}
}
IIOMetadataNode node = new IIOMetadataNode(nodeName);
rootNode.appendChild(node);
return(node);
}
}