Rasterizing Java Fonts - java

Exposition:
I'm writting an OpenGL app in Java via JOGL. The built in fonts with GLUT are very basic. I want to be able to take a Java Font, render all the characters in it to a 2D array of bytes (a greyscale image representing the characters), which I can then load as a texture in OpenGL.
Problem:
I can load the textures in OpenGL; I can use JOGL. My only problem is going from the "Font java cn read" --> "2D greyscale image of all the characters step". What functions / libraries should I be using?

I'm not sure I quite understand what you're looking for. I think what you want is some code that will generate grayscale bitmap images of a given size for every glyph in a font.
There isn't a way (that I am aware of anyway) to get all the glyphs a font supports (oddly, you can get the number of glyphs... so yeah, I may just be missing something, bah). However, you can get glyph metrics for given characters quite easily.
Something along these lines should work for you.
HashMap<int[], Rectangle2D> generateGlyphs(int fontSize, String characters, Font font){
HashMap<int[], Rectangle2D> ret = new HashMap<int[], Rectangle>();
FontRenderContext rendCont = new FontRenderContext(null, true, true);
for(int i = 0; i < characters.length; i++){
Rectangle2D bounds = font.getStringBounds(characters.substring(i, 1), rendCont);
BufferedImage bi = new BufferedImage((int)bounds.getWidth(), (int)bounds.getHeight(), BufferedImage.TYPE_INT_GRAY);
Graphics g = bi.getGraphcs();
g.setFont(font);
g.drawString(characters.substring(i, 1), 0, (int)bounds.getHeight());
ret.put(bi.getData().getPixels(0, 0, (int)bounds.getWidth(), (int)bounds.getHeight()), bounds);
}
return ret;
}
Note that I'm clipping rather than rounding in some places, which could potentially be an issue.

Possible I'm missing something, but can java.awt not do most of this for you?
create a new BufferedImage
get its Graphics2D (image.getGraphics)
paint the text to the image
get the Raster (getData) from the buffered image.
dispose of the Graphics2D context when done.

Processing can render fonts in OpenGL, and it uses it's own in house open source class PFont to "generate grayscale bitmap images of a given size for every glyph in a font," as Kevin put it. I recommend you look at the source, which is here.

Related

BufferedImage disable dithering when reducing color using custom ColorModel?

I'm creating an image with a custom palette (in other words a custom colormodel):
BufferedImage img = new BufferedImage(orgImg.getWidth(), orgImg.getHeight(),
BufferedImage.TYPE_BYTE_INDEXED,
cm);
Graphics2D g2 = img.createGraphics();
g2.drawImage(orgImg, 0, 0, null);
g2.dispose();
Note that the "cm" variable is a my custom colormodel with a palette of 256 colors.
The "orgImg" variable is a full colored (24 big argb) image.
The above code results in a copy of "orgImg" with 256 colors using the palette defined in the colormodel.
This works nicely.
But java uses dithering to reduce colors. Is it possible to disable this dithering?
Note that i need to use my own palette so that the final images matches a specific color palette.
When drawing an image into a Graphics2D object, various aspects of the rendering can be controlled using RenderingHints. You should be able to disable the dithering using the Graphics2D.setRenderingHint or setRenderingHints methods, passing the KEY_DITHERING and VALUE_DITHER_DISABLE value as parameters:
Graphics2D g2 = img.createGraphics();
// Disable dithering
g2.setRenderingHint(RenderingHint.KEY_DITHERING, RenderingHint.VALUE_DITHER_DISABLE);
g2.drawImage(orgImg, 0, 0, null);
g2.dispose();
See the Java2D tutorial for more info.
PS: Note that the methods/class are named "hint".
This may not be a problem any more, but in the past I've experienced that disabling the dither using the hint like above did not work. It's also not possible to specify the dithering algorithm to use, typically only a "ordered" or "diamond" pattern dithering is used.
I therefore implemented my own versions of various dithering algorithms for this use. See the CopyDither (which does a closest match lookup for each pixel, probably what you want here) and DiffusionDither (which implements a "Floyd-Steinberg" error diffusion dither). Both of the mentioned implementations rely on a fast reverse lookup of color values. Unfortunately, the default IndexColorModel doesn't do fast reverse lookups. So I implemented a special class for this case too, see the InverseColorMapIndexColorModel class.
Usage:
BufferedImage img = new BufferedImage(orgImg.getWidth(), orgImg.getHeight(), BufferedImage.TYPE_BYTE_INDEXED, cm);
CopyDither noDither = new CopyDither(new InverseColorMapIndexColorModel(cm)); // cm must be IndexColorModel
noDither.filter(orgImg, img);

Get an Area containing the non-transparent pixels in a BufferedImage in Java

In Java SE 7, I create a BufferedImage object:
BufferedImage i = new BufferedImage(300, 300, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = i.createGraphics();
And then I fill parts of the image with color, using several call to fillPolygon, drawImage, etc. (Note that some of my colors have an alpha less than 255.)
My question is, how can I construct an Area object which contains only the area which was painted to in the BufferedImage? From reading the API docs, I believe it could be done by inspecting the Raster returned by the getAlphaRaster method, but I'm hoping there's an easier (and faster?) way of doing this.
..how can I construct an Area object which contains only the area which was painted to in the BufferedImage?
The getOutline(..) method seen in this source could be used to distinguish between the opaque and translucent parts of the image. Having said that, the method only checks for an 'exact match' between target color and image color for that pixel. You'd need to adjust it to instead check for alpha <255.
The ShapeContainment class would be used to determine if a point falls into any of a number of Area instances.
Other code deailing with Java-2D and images can be seen in OneRing & ShapeCollision.

Merging Pictures in sequence

I am trying to make some kind of map maker, using the old 2D style of games such as Final Fantasy 4. Basically they had everything set up in a grid where each square on the grid might have taken 16x16 or 32x32 pixels.
I would like to start out small, and get the main things down first. Such as generating a map which could be, say, 128x128. This means, that I should be able to feed the program an array of numbers representing the different tiles available, and then the program should make a new picture by placing the tiles as the array specifies (So the one in Index 0 will be placed at 0,0 etc).
I plan to show the picture when I am done, but that should be easy as pie.
I've been looking around for a solution and all I could find was merging pictures on top of each other (as in layers on top of each other), rather than side by side, so can any one point me in the right direction? I'd like it if I didn't have to rely on 3rd party libraries, as this is more of a learning experience than practical application :)
First, create the output BufferedImage to be the size you need.
BufferedImage image = new BufferedImage(width, height, imageType);
Then, get the Graphics2D object from the image and start drawing the smaller image in the places they need to be in the resulting image:
Graphics2D g2 = image.createGraphics();
for (BufferedImage img : images) {
g2.drawImage(img, x, y, null);
}
Then, you can save the image to the desired format: jpg, png or gif.
ImageIO.write(image, "jpg", file);

Differences between Swing and iText font rendering

I'm building an app which among other things allows the user to insert a text into a PDF, using a layer.
The position of the text in the PDF page can be set using the app, which renders the PDF using ICEPdf inside a JPanel. After selecting the position and the size of the layer, the app renders it to the PDF using iText (v. 5.3.2).
The problem I'm facing is that the font rendering from Swing is sightly different from the final result in the PDF.
Here are some screen-shots, both using the Helvetica plain font inside the same bounding box:
Rendering a text with Swing:
protected void paintComponent(Graphics g){
//for each line...
g.drawString(text, b0, b1);
//b0 and b1 are computed from the selected bounding box for the text
}
I have this:
Rendering a text with iText:
PdfTemplate t; //PdfTemplate is created elsewhere
ColumnText ct = new ColumnText(t);
ct.setRunDirection(PdfWriter.RUN_DIRECTION_NO_BIDI);
ct.setSpaceCharRatio(1);
ct.setSimpleColumn(new Phrase(text, font), b0, b1, b3, b4, font.getSize(), Element.ALIGN_BOTTOM);
//b0, b1, b2 and b3 are the bounding box of the text
ct.go();
I have this:
So the question is: what can be done to make Swing and iText render fonts exactly the same way? I can tweak Swing or iText, so no matter what code is modified, I need a truly WYSIWYG experience for the user.
I tried with other fonts and types, but still there are some differences between them. I think I'm missing some configuration.
Thanks.
Edit:
Font in Java is measured in Pixels, but iText measures in Points, and we know there are 72 points per inch, and for a standard windows machine there are 96 pixels per inch / dpi.
First we need to find the difference between a point and a pixel:
difference = 72 / dpi
0.75 = 72 / 96
Next we can multiply the Java font size with the difference to get the iText font size, if the java font size is 16, then the iText font size should be 12 when used with 96dpi.
iTextFontSize = difference x javaFontSize
12 = 0.75 x 16
On a windows machine 96dpi is often the norm, but remember that is not always the case, you should work it out for each different machine.
Original Post
I believe the difference is caused by rendering hints.
Solution 1:
The best way to do it would be to draw everything on a buffered image. Then the buffered image is drawn to the swing component and the exact same buffered image is drawn to the PDF as well, that way there should be no difference between them.
Alternate Idea:
Another idea that may not work as well, but will work better with your existing code is to draw the contents of the swing component directly to a buffered image then draw the buffered image to the PDF.
The following is a quick example that will draw the contents of a JPanel to a buffered image with a few different rendering hints. (Change the hints to suit your swing component)
public BufferedImage createImage(JPanel panel)
{
BufferedImage swingComponent = new BufferedImage(
panel.getHeight(), panel.getWidth(),
BufferedImage.TYPE_INT_RGB);
Graphics2D g = swingComponent.createGraphics();
g.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.dispose();
return swingComponent; //print this to your PDF
}
So the question is: what can be done to make Swing and iText render fonts exactly the same way?
Exactly the same? Very little. Presuming that you supply the same font characteristics to both, there may still be differences introduced in rendering.
PDF files (or really, the text phrases) hold font information—family, size, style, etc.—but it is your PDF reader that renders the text to your device. Depending on what program you use, it can use the platform's renderer or it can choose one of its own.
AFAIK, Java Swing uses its own font rendering engine, as distinct from the underlying platform's renderer. This makes it look more consistent across platforms, but also makes it very unlikely that text will be rendered the same way any other program would.
Knowing that, your options are limited:
Use a PDF reader that also uses Swing font rendering. That's a fairly limiting solution.
Use your platform's rendering engine to draw into Swing. That sounds like iffy work, and also like something SWT would have solved. Maybe you could embed an SWT component?

Is it possible to add transparency to jpg in Java and Android

I want to load some images to the cloud, but I want to add some protections when someone views the photos and saves the images; they will not see anything because of the transparency.
would the code be common for Java and Android? I would like to prototype it in Java first.
I have found some code that combines two files. One file is my main file the other is a transparent file. The combined file does not have a transparent overlay.
Do I need to use an image drawing order?
http://www.developer.nokia.com/document/Java_Developers_Library_v2/GUID-D3E35E6F-0C45-48ED-B09D-F716E14C1C02/javax/microedition/amms/control/imageeffect/OverlayControl.html
BufferedImage image = ImageIO.read(new File("rose.jpg"));
BufferedImage overlay = ImageIO.read(new File("myimg1.gif"));
// create the new image, canvas size is the max. of both image sizes
int w = Math.max(image.getWidth(), overlay.getWidth());
int h = Math.max(image.getHeight(), overlay.getHeight());
BufferedImage combined = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
// paint both images, preserving the alpha channels
Graphics g = combined.getGraphics();
g.drawImage(image, 0, 0, null);
g.drawImage(overlay, 0, 0, null);
// Save as new image
ImageIO.write(combined, "PNG", new File("combined.png"));
This won't work. If they can see the image, they can copy it, one way or another. A solution to consider is providing watermarked thumbnails at no charge, then only offering the full resolution image for a fee. However, they can still copy the full resolution image once they pay.
You can actually put a trans image as an overlay to the orginial image, that will
Protect from download, I think this is usually done by the server side aka your cloud
I know from some websites that they use some kind of an overlay such as yours
And the browser can't see the image below so you can't download.
I actually didn't understand how you implementing this - the image is opened in the browser?
Just a wild though, you can also cut the image into pieces like a jigsaw puzzle
The device won't have problems connecting it togther but when you download you'll
Download only "one piece of the puzzle" :-P

Categories

Resources