Skip to main content

Some characters get clipped while writing text on tiff Image

8 replies [Last post]
prashanth_kayampady
Offline
Joined: 2007-07-22
Points: 0

Hi All,

I have an application that writes some text on tiff images. This is developed using JAI ImageIO. The application works fine on my solaris box. But when I run it on my customer's solaris box some of the letters are not copied to the image properly. The following characters getting clipped. A, G, M, O, Q, V, W, X, Y, m, and w. All other letters are copied properly. Plese let me know if you have any idea on this.

Thanks in advance,
Prashanth Kayampady.

Message was edited by: prashanth_kayampady

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Brian Burkhalter

None, unless you can provide more detail. A test case would be optimal.

On Fri, 14 Sep 2007, jai-imageio@javadesktop.org wrote:

> Hi All,
>
> I have an application that writes some text on tiff images. This is developed using JAI ImageIO. The application works fine on my solaris box. But when I run it on my customer's solaris box some of the letters are not copied to the image properly. The following characters getting clipped. A, G, M, O, Q, V, W, X, Y, m, and w. All other letters are copied properly. Plese let me know if you have any idea on this.
>
> Thanks in advance,
> Prashanth.
> [Message sent by forum member 'prashanth_kayampady' (prashanth_kayampady)]
>
> http://forums.java.net/jive/thread.jspa?messageID=235498
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
> For additional commands, e-mail: interest-help@jai-imageio.dev.java.net
>
>

>^..^< >^..^<

Brian Burkhalter
Java Media, Imaging, and Graphics
Sun Microsystems, Inc.

This email message is for the sole use of the intended recipient(s)
and may contain confidential and privileged information. Any
unauthorized review, use, disclosure or distribution is prohibited.
If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

prashanth_kayampady
Offline
Joined: 2007-07-22
Points: 0

Hi Brian,

Here is a sample code that has this issue. This code writes letters A - Z, a - z and 0 - 9 on the given input image. The character 'W' is getting clipped in the resulting image. This happens only in solaris. In windows it works fine. Could you please run the following code and let me know if this occurs at your end?

The format for executing the code is
java TextClipTestCase1
Example: java TextClipTestCase1 C:/Test/image1.tif C:/Test/newimage.tif

This code requires only jai_imageio.jar in the classpath.

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.stream.MemoryCacheImageInputStream;

public class TextClipTestCase1 {

public static void main(String args[]) throws Exception {

//String inputImage = "C:/Temp/multipage1.tif";
//String outputFile = "C:/Temp/output.tif";

String inputImage = args[0];
String outputFile = args[1];

InputStream in = new FileInputStream(inputImage);

//Get ByteArrayInputStream of the input image. The method that applies annotations
//accepts only ByteArrayInputStream. This is my requirement as my application will be getting only
//byteArrayInputStream from some other application.
int dataLength = in.available();
byte imageDataBytes[] = new byte[dataLength];
int byteRead = 0;
int totalBytesRead = 0;
while (totalBytesRead < dataLength) {
byteRead = in.read(imageDataBytes, totalBytesRead, dataLength);
totalBytesRead += byteRead;
}

ByteArrayInputStream inputByteStream = new ByteArrayInputStream(imageDataBytes);
TextClipTestCase1 textClipTestCase = new TextClipTestCase1();
textClipTestCase.applyAnnotationsAndSave(inputByteStream, outputFile);

}

private void applyAnnotationsAndSave (ByteArrayInputStream inputByteStream,
String outputFile) throws Exception {

System.out.println("Image resolution is hardcoded as 200*200 for now.");
int xResolution = 200;
int yResolution = 200;

System.out.println("Getting the tif readers and reading the image.");
Iterator imageReaderItr = ImageIO.getImageReadersByFormatName("tif");
ImageReader imageReader = (ImageReader) imageReaderItr.next();
MemoryCacheImageInputStream imageInStream = new MemoryCacheImageInputStream(inputByteStream);
imageReader.setInput(imageInStream);
int numberOfPages = imageReader.getNumImages(true);
IIOMetadata iioMetaData = imageReader.getImageMetadata(0);

System.out.println("Applying annotations to each page of tif image.");
BufferedImage bufferedImage = null;
Graphics2D graphics2D = null;
ArrayList imageList = new ArrayList();
for (int pages = 0; pages < numberOfPages; pages++) {

IIOImage iio = (IIOImage) imageReader.readAll(pages, new ImageReadParam());
bufferedImage = (BufferedImage) iio.getRenderedImage();
graphics2D = bufferedImage.createGraphics();
graphics2D.setColor(Color.BLACK);

HashMap map = new HashMap();
map.put(TextAttribute.FONT, new Font("Arial", 0, 35));
AttributedString attributeString = new AttributedString("ABCD EFG HIJ KLM NOP QRS TUVWXYZ. " +
"abcdefg hijklmn opqrstuvwxyz. 01234 56789", map);
AttributedCharacterIterator textParagraph = attributeString.getIterator();
int paragraphStart = textParagraph.getBeginIndex();
int paragraphEnd = textParagraph.getEndIndex();
LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(textParagraph,
new FontRenderContext(null, false, false));

float drawPosY = 1 * yResolution;
float drawPosX = 2 * xResolution;
float textWidth = 2 * xResolution;

lineMeasurer.setPosition(paragraphStart);
while (lineMeasurer.getPosition() < paragraphEnd) {
TextLayout layout = lineMeasurer.nextLayout(textWidth);
drawPosY += layout.getAscent();
layout.draw(graphics2D, drawPosX, drawPosY);
drawPosY += layout.getDescent() + layout.getLeading();
}
imageList.add(bufferedImage);
}

System.out.println("Saving the annotated Image.");
Iterator writers = ImageIO.getImageWritersBySuffix("tif");
ImageWriter writer = (ImageWriter) writers.next();
OutputStream out = new FileOutputStream(outputFile);
ImageOutputStream ios = ImageIO.createImageOutputStream(out);
writer.setOutput(ios);
ImageWriteParam parm = writer.getDefaultWriteParam();
parm.setCompressionMode(ImageWriteParam.MODE_DEFAULT);

IIOImage iioImage =null;
if(writer.canWriteSequence()) {
writer.prepareWriteSequence(null);
for (int i = 0; i < numberOfPages; i++) {
bufferedImage = (BufferedImage) imageList.get(i);
iioImage = new IIOImage(bufferedImage, null, iioMetaData);
writer.writeToSequence(iioImage, null);
}
}

((ImageOutputStream)writer.getOutput()).flush();
((ImageOutputStream) writer.getOutput()).close();

System.out.println("Done!!");

}

}

Thanks,
Prashanth

Brian Burkhalter

Which versions are we talking about here (Windows, Solaris, Java SE, JAI Image
I/O Tools)?

Brian

On Wed, 26 Sep 2007, jai-imageio@javadesktop.org wrote:

> Hi Brian,
>
> Here is a sample code that has this issue. This code writes letters A - Z, a - z and 0 - 9 on the given input image. The character 'W' is getting clipped in the resulting image. This happens only in solaris. In windows it works fine. Could you please run the following code and let me know if this occurs at your end?
>
> The format for executing the code is
> java TextClipTestCase1
> Example: java TextClipTestCase1 C:/Test/image1.tif C:/Test/newimage.tif
>
> This code requires only jai_imageio.jar in the classpath.
>
>
> import java.awt.Color;
> import java.awt.Font;
> import java.awt.Graphics2D;
> import java.awt.font.FontRenderContext;
> import java.awt.font.LineBreakMeasurer;
> import java.awt.font.TextAttribute;
> import java.awt.font.TextLayout;
> import java.awt.image.BufferedImage;
> import java.io.ByteArrayInputStream;
> import java.io.FileInputStream;
> import java.io.FileOutputStream;
> import java.io.InputStream;
> import java.io.OutputStream;
> import java.text.AttributedCharacterIterator;
> import java.text.AttributedString;
> import java.util.ArrayList;
> import java.util.HashMap;
> import java.util.Iterator;
>
> import javax.imageio.IIOImage;
> import javax.imageio.ImageIO;
> import javax.imageio.ImageReadParam;
> import javax.imageio.ImageReader;
> import javax.imageio.ImageWriteParam;
> import javax.imageio.ImageWriter;
> import javax.imageio.metadata.IIOMetadata;
> import javax.imageio.stream.ImageOutputStream;
> import javax.imageio.stream.MemoryCacheImageInputStream;
>
>
> public class TextClipTestCase1 {
>
>
> public static void main(String args[]) throws Exception {
>
> //String inputImage = "C:/Temp/multipage1.tif";
> //String outputFile = "C:/Temp/output.tif";
>
> String inputImage = args[0];
> String outputFile = args[1];
>
>
> InputStream in = new FileInputStream(inputImage);
>
> //Get ByteArrayInputStream of the input image. The method that applies annotations
> //accepts only ByteArrayInputStream. This is my requirement as my application will be getting only
> //byteArrayInputStream from some other application.
> int dataLength = in.available();
> byte imageDataBytes[] = new byte[dataLength];
> int byteRead = 0;
> int totalBytesRead = 0;
> while (totalBytesRead < dataLength) {
> byteRead = in.read(imageDataBytes, totalBytesRead, dataLength);
> totalBytesRead += byteRead;
> }
>
> ByteArrayInputStream inputByteStream = new ByteArrayInputStream(imageDataBytes);
> TextClipTestCase1 textClipTestCase = new TextClipTestCase1();
> textClipTestCase.applyAnnotationsAndSave(inputByteStream, outputFile);
>
>
>
> }
>
> private void applyAnnotationsAndSave (ByteArrayInputStream inputByteStream,
> String outputFile) throws Exception {
>
> System.out.println("Image resolution is hardcoded as 200*200 for now.");
> int xResolution = 200;
> int yResolution = 200;
>
> System.out.println("Getting the tif readers and reading the image.");
> Iterator imageReaderItr = ImageIO.getImageReadersByFormatName("tif");
> ImageReader imageReader = (ImageReader) imageReaderItr.next();
> MemoryCacheImageInputStream imageInStream = new MemoryCacheImageInputStream(inputByteStream);
> imageReader.setInput(imageInStream);
> int numberOfPages = imageReader.getNumImages(true);
> IIOMetadata iioMetaData = imageReader.getImageMetadata(0);
>
> System.out.println("Applying annotations to each page of tif image.");
> BufferedImage bufferedImage = null;
> Graphics2D graphics2D = null;
> ArrayList imageList = new ArrayList();
> for (int pages = 0; pages < numberOfPages; pages++) {
>
> IIOImage iio = (IIOImage) imageReader.readAll(pages, new ImageReadParam());
> bufferedImage = (BufferedImage) iio.getRenderedImage();
> graphics2D = bufferedImage.createGraphics();
> graphics2D.setColor(Color.BLACK);
>
> HashMap map = new HashMap();
> map.put(TextAttribute.FONT, new Font("Arial", 0, 35));
> AttributedString attributeString = new AttributedString("ABCD EFG HIJ KLM NOP QRS TUVWXYZ. " +
> "abcdefg hijklmn opqrstuvwxyz. 01234 56789", map);
> AttributedCharacterIterator textParagraph = attributeString.getIterator();
> int paragraphStart = textParagraph.getBeginIndex();
> int paragraphEnd = textParagraph.getEndIndex();
> LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(textParagraph,
> new FontRenderContext(null, false, false));
>
>
> float drawPosY = 1 * yResolution;
> float drawPosX = 2 * xResolution;
> float textWidth = 2 * xResolution;
>
>
> lineMeasurer.setPosition(paragraphStart);
> while (lineMeasurer.getPosition() < paragraphEnd) {
> TextLayout layout = lineMeasurer.nextLayout(textWidth);
> drawPosY += layout.getAscent();
> layout.draw(graphics2D, drawPosX, drawPosY);
> drawPosY += layout.getDescent() + layout.getLeading();
> }
> imageList.add(bufferedImage);
> }
>
> System.out.println("Saving the annotated Image.");
> Iterator writers = ImageIO.getImageWritersBySuffix("tif");
> ImageWriter writer = (ImageWriter) writers.next();
> OutputStream out = new FileOutputStream(outputFile);
> ImageOutputStream ios = ImageIO.createImageOutputStream(out);
> writer.setOutput(ios);
> ImageWriteParam parm = writer.getDefaultWriteParam();
> parm.setCompressionMode(ImageWriteParam.MODE_DEFAULT);
>
>
> IIOImage iioImage =null;
> if(writer.canWriteSequence()) {
> writer.prepareWriteSequence(null);
> for (int i = 0; i < numberOfPages; i++) {
> bufferedImage = (BufferedImage) imageList.get(i);
> iioImage = new IIOImage(bufferedImage, null, iioMetaData);
> writer.writeToSequence(iioImage, null);
> }
> }
>
> ((ImageOutputStream)writer.getOutput()).flush();
> ((ImageOutputStream) writer.getOutput()).close();
>
> System.out.println("Done!!");
>
> }
>
> }
>
> Thanks,
> Prashanth
> [Message sent by forum member 'prashanth_kayampady' (prashanth_kayampady)]
>
> http://forums.java.net/jive/thread.jspa?messageID=237257
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
> For additional commands, e-mail: interest-help@jai-imageio.dev.java.net
>
>

>^..^< >^..^<

Brian Burkhalter
Java Media, Imaging, and Graphics
Sun Microsystems, Inc.

This email message is for the sole use of the intended recipient(s)
and may contain confidential and privileged information. Any
unauthorized review, use, disclosure or distribution is prohibited.
If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

prashanth_kayampady
Offline
Joined: 2007-07-22
Points: 0

Solaris 9i
Windows XP (it works fine on this)
JAI Imageio 1.1
J2SE 1.4.2

Thanks,
Prashanth

Phil Race

jai-imageio@javadesktop.org wrote:
> Solaris 9i
> Windows XP (it works fine on this)
> JAI Imageio 1.1
> J2SE 1.4.2
>
> Thanks,
> Prashanth
> [Message sent by forum member 'prashanth_kayampady' (prashanth_kayampady)]
>
> http://forums.java.net/jive/thread.jspa?messageID=237260
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
> For additional commands, e-mail: interest-help@jai-imageio.dev.java.net
>

Whilst I can't think what difference drawing on an image would make,
and once its in memory as a BufferedImage its no longer TIF or PNG or
anything except a BufferedImage.
Nor can I think of how the image format or color space etc would
cause such a specific problem.

So it sounds more like just a pure text rendering issue which should
be discussed on a different alias or forum (java2d)

However extracting just the text rendering part of your app and running it
as below I see no such clipping on Solaris with 1.4.2 or JDK6.
I'm running on Solaris 10 but the fonts and the code would be the same.

-phil.

import java.io.*;
import java.text.*;
import java.util.*;
import java.awt.*;
import java.awt.font.*;
import java.awt.event.*;

public class Draw extends Component {

public static void main(String[] args) throws Exception {

Frame f = new Frame("Clipped");
f.add(new Draw());
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.pack();
f.setVisible(true);
}

public Dimension getPreferredSize() {
return new Dimension(800,800);
}

public void paint(Graphics g) {
g.setColor(Color.white);
g.fillRect(0,0,getSize().width, getSize().height);
g.setColor(Color.black);

int xResolution = 200;
int yResolution = 200;

HashMap map = new HashMap();
map.put(TextAttribute.FONT, new Font("Arial", 0, 35));
AttributedString attributeString =
new AttributedString("ABCD EFG HIJ KLM NOP QRS TUVWXYZ. " +
"abcdefg hijklmn opqrstuvwxyz. 01234 56789", map);
AttributedCharacterIterator textParagraph = attributeString.getIterator();
int paragraphStart = textParagraph.getBeginIndex();
int paragraphEnd = textParagraph.getEndIndex();
LineBreakMeasurer lineMeasurer
= new LineBreakMeasurer(textParagraph,
new FontRenderContext(null, false, false));

float drawPosY = 1 * yResolution;
float drawPosX = 2 * xResolution;
float textWidth = 2 * xResolution;

lineMeasurer.setPosition(paragraphStart);
while (lineMeasurer.getPosition() < paragraphEnd) {
TextLayout layout = lineMeasurer.nextLayout(textWidth);
drawPosY += layout.getAscent();
System.out.println(drawPosX+" "+drawPosY);
layout.draw((Graphics2D)g, drawPosX, drawPosY);
drawPosY += layout.getDescent() + layout.getLeading();
}
}

}

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

prashanth_kayampady
Offline
Joined: 2007-07-22
Points: 0

Thanks Philip.
When I use FileImageInputStream, instead of ByteArrayInputStream, the code that I sent works fine in my customer's environment. The issue occurs when I use ByteArrayInputStream.

Thanks,
Prashanth.

prashanth_kayampady
Offline
Joined: 2007-07-22
Points: 0

The issue is resolved by turning on "antialiasing" and "fractional metrics" in FontRenderContext.
Used 'new FontRenderContext(null, true, true)' instead of 'new FontRenderContext(null, false, false)'.

Thanks,
Prashanth.

Phil Race

Applying fractional metrics is a workaround that helps
mainly because it makes the text advances scale linearly,
which is what you'd expect on a device of a sufficiently
high resolution (eg a 600 dpi printer), but it isn't
necessarily placing them in the ideal places for
whatever scale you have.

So it sounds to me as if you weren't measuring your text properly.

Text doesn't scale linearly so you need to measure it at the scale
you will render it. Clipping is the most common problem that people
notice when they fail to do this properly.
But the test case you sent doesn't do any scaling so that doesn't
add up to me.

-phil.

jai-imageio@javadesktop.org wrote:
> The issue is resolved by turning on "antialiasing" and "fractional metrics" in FontRenderContext.
> Used 'new FontRenderContext(null, true, true)' instead of 'new FontRenderContext(null, false, false)'.
>
> Thanks,
> Prashanth.
> [Message sent by forum member 'prashanth_kayampady' (prashanth_kayampady)]
>
> http://forums.java.net/jive/thread.jspa?messageID=241975
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
> For additional commands, e-mail: interest-help@jai-imageio.dev.java.net
>

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net