Copying all chars from AWT font to an OpenGL texture array - java

I'm trying to copy all the chars from an AWT font into a OpenGL array for LWJGL to use. Currently my code isn't working (blank textures). What I tried was to draw each char into a BufferedImage along with a transparent background, then copy it pixel-by-pixel onto a ByteBuffer for an OpenGL image. My question is, what is a better way around copying these chars? BufferedImage doesn't seem to be working. Is there another canvas type I can use for this?
So far this is the layout, but it doesn't work, I need a new way to draw onto the textures:
for (int i = 0; i <= 255; i++)
{
String letter = Character.toString((char)i);
BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics();
g.setColor(new Color(255, 255, 255, 0));
g.drawRect(0, 0, size, size);
g.setColor(new Color(255, 255, 255));
g.setFont(font);
g.drawString(letter, 0, 0);
int id = i;
glTextures[id] = glGenTextures();
glBindTexture(GL_TEXTURE_2D, glTextures[id]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
ByteBuffer buf = ByteBuffer.allocateDirect(4 * 4 * size * size);
for (int x = 1; x <= size; x++)
{
for (int y = 1; y <= size; y++)
{
Color color = new Color(image.getRGB(x - 1, y - 1));
buf.putFloat((float)(1 / 255 * color.getRed()));
buf.putFloat((float)(1 / 255 * color.getGreen()));
buf.putFloat((float)(1 / 255 * color.getBlue()));
buf.putFloat((float)(1 / 255 * color.getAlpha()));
}
}
buf.flip();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_FLOAT, buf);
}

Related

setPixel leaving a black border around bitmap, how to avoid?

I am trying to alter the colour of certain pixels in a bitmap image. When I alter the colour of pixels in an array of a bitmap image from my drawable folder, it leaves a black border around the different colours which is not desired. How can I do this without the black border?
INITIAL BITMAP:
I have tried the method below and it leaves the black border:
bitmap = bitmap_.copy(bitmap_.getConfig(), true);
int[] pixels = new int[bitmap.getHeight() * bitmap.getWidth()];
bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
for(int i = 0; i < pixels.length; i++) {
if(pixels[i] == Color.rgb(120, 120, 120)) {
pixels[i] = Color.RED;
} else
if(pixels[i] == Color.rgb(90, 90, 90)) {
pixels[i] = Color.GREEN;
} else
if(pixels[i] == Color.rgb(60, 60, 60)) {
pixels[i] = Color.RED;
} else
if(pixels[i] == Color.rgb(30, 30, 30)) {
pixels[i] = Color.GREEN;
} else
if(pixels[i] == Color.rgb(0, 0, 0)) {
pixels[i] = Color.RED;
} else {
pixels[i] = Color.YELLOW; // Should never fire
}
}
bitmap.setPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
There should be no yellow pixels in the output as the image only consists of pixels with 0,0,0 or multiples of 30 up to 120. It shouldn't be anti-aliasing when I save it. However as you can see there is yellow pixels. Or if I don't recolour them, they go black.
With no recolour:
Recolouring the black as yellow:
Placing the bitmaps into drawable-nodpi folder prevents Android from scaling them up at runtime, which was causing anti-aliasing.

BufferedImage fill rectangle with transparent pixels

I have a BufferedImage and I am trying to fill a rectangle with transparent pixels. The problem is, instead of replacing the original pixels, the transparent pixels just go on top and do nothing. How can I get rid of the original pixel completely? The code works fine for any other opaque colors.
public static BufferedImage[] slice(BufferedImage img, int slices) {
BufferedImage[] ret = new BufferedImage[slices];
for (int i = 0; i < slices; i++) {
ret[i] = copyImage(img);
Graphics2D g2d = ret[i].createGraphics();
g2d.setColor(new Color(255, 255, 255, 0));
for(int j = i; j < img.getHeight(); j += slices)
g2d.fill(new Rectangle(0, j, img.getWidth(), slices - 1));
g2d.dispose();
}
return ret;
}
public static BufferedImage copyImage(BufferedImage source){
BufferedImage b = new BufferedImage(source.getWidth(), source.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = b.getGraphics();
g.drawImage(source, 0, 0, null);
g.dispose();
return b;
}
Using AlphaComposite, you have at least two options:
Either, use AlphaComposite.CLEAR as suggested, and just fill a rectangle in any color, and the result will be a completely transparent rectangle:
Graphics2D g = ...;
g.setComposite(AlphaComposite.Clear);
g.fillRect(x, y, w, h);
Or, you can use AlphaComposite.SRC, and paint in a transparent (or semi-transparent if you like) color. This will replace whatever color/transparency that is at the destination, and the result will be a rectangle with exactly the color specified:
Graphics2D g = ...;
g.setComposite(AlphaComposite.Src);
g.setColor(new Color(0x00000000, true);
g.fillRect(x, y, w, h);
The first approach is probably faster and easier if you want to just erase what is at the destination. The second is more flexible, as it allows replacing areas with semi-transparency or even gradients or other images.
PS: (As Josh says in the linked answer) Don't forget to reset the composite after you're done, to the default AlphaComposite.SrcOver, if you plan to do more painting using the same Graphics2D object.

JAVA Android: Darkening black letters/texts on a bitmap

I want to darken all the black text on a bitmap to filter the the bitmap and after research I found this:
private static void setContrast(ColorMatrix cm, float contrast) {
float scale = contrast + 1.f;
float translate = (-.5f * scale + .5f) * 255.f;
cm.set(new float[] {
scale, 0, 0, 0, translate,
0, scale, 0, 0, translate,
0, 0, scale, 0, translate,
0, 0, 0, 1, 0 });
}
My present challenge is applying it on the bitmap to darken the black texts.
Kindly assist me.
I was able to find an answer to my question using
https://stackoverflow.com/a/17887577/5220210
and
http://android.okhelp.cz/bitmap-set-contrast-and-brightness-android/
public static Bitmap darkenText(Bitmap bmp, float contrast)
{
ColorMatrix cm = new ColorMatrix();
float scale = contrast + 1.f;
float translate = (-.5f * scale + .5f) * 255.f;
cm.set(new float[] {
scale, 0, 0, 0, translate,
0, scale, 0, 0, translate,
0, 0, scale, 0, translate,
0, 0, 0, 1, 0 });
Bitmap ret = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), bmp.getConfig());
Canvas canvas = new Canvas(ret);
Paint paint = new Paint();
paint.setColorFilter(new ColorMatrixColorFilter(cm));
canvas.drawBitmap(bmp, 0, 0, paint);
return ret;
}
Hope it helps someone.

How to draw a transparent line?

I am drawing a solid blue line on a JPanel via
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
super.paint(g2);
if (path.size() >= 2) {
BasisStroke stroke = new BasicStroke(Config.TILE_SIZE_IN_PIXEL / 3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL);
g2.setStroke(stroke);
g2.setPaint(Color.BLUE);
g2.setPaintMode();
for (int i = 0; i < path.size() - 1; i++) {
g2.drawLine(path.get(i).x, path.get(i).y, path.get(i + 1).x, path.get(i + 1).y);
}
}
}
Yet I want this line to be semi-transparent. How do I achieve that?
The short answer is to set the alpha for the color of your graphic context:
float alpha = 0.5;
Color color = new Color(1, 0, 0, alpha); //Red
g2.setPaint(color);
Alpha ranges between 0.0f (invisible) to 1.0f (opaque)
For the long answer with examples, see this article.

Cursor with Semi-Transparency / Anti-Aliasing

I'm trying to create a custom cursor with the following code:
BufferedImage cursor = new BufferedImage(30, 30, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = (Graphics2D) cursor.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.BLACK);
g.drawOval(0, 0, 26, 26);
jframe.getContentPane().setCursor(Toolkit.getDefaultToolkit().createCustomCursor(
cursor, new Point(13, 13), "cursor"));
Without Anti-Aliasing this looks really bad, but once I try to activate Anti-Aliasing, the pixels that are supposed to be semi transparent seem to become completely solid - as if the JFrame cursor cannot handle semi-transparency.
I've tried loading the BufferedImage from a .png file, but the results are the same.
I do not want to draw the cursor manually on my canvas because it has a slight input lag compared to this method.
All I want to do is have a Cursor that can support semi-transparency.
Any idea on how I can achieve this?
Thanks in advance.
This one is subtle (I've been stuck for a couple of years :) but I've cracked it today.
The cursor appears to only support on/off for transparency, so drawing first to a TYPE_INT_RGB image then copying that to a TYPE_INT_ARGB (then fixing the transparency) works.
Not sure if it's optimal, but it doesn't matter too much for small images like this.
int size = 32;
/*
* we need two buffered images as the cursor only supports on/off for alpha
*
* so we need to draw to an image without alpha support
* then draw that to one with alpha support
* then make "white" transparent
*/
BufferedImage image = new BufferedImage(size, size,
BufferedImage.TYPE_INT_RGB);
BufferedImage image2 = new BufferedImage(size, size,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics();
Graphics2D g2 = image2.createGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, size, size);
// turn on anti-aliasing.
g.setStroke(new BasicStroke(4.0f)); // 4-pixel lines
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(new Color(0.5f, 0f, 0f));
g.drawOval(3, 3, size-7, size-7);
g2.drawImage(image, 0, 0, null, null);
for (int y = 0 ; y < size ; y++) {
for (int x = 0 ; x < size ; x++) {
int rgb = image.getRGB(x, y);
int blue = rgb & 0xff;
int green = (rgb & 0xff00) >> 8;
int red = (rgb & 0xff0000) >> 16;
//int alpha = (rgb & 0xff000000) >> 24;
if (red == 255 && green == 255 && blue == 255) {
// make white transparent
image2.setRGB(x, y, 0);
}
}
}
eraserCursor = Toolkit.getDefaultToolkit().createCustomCursor(
image2, new Point(size / 2, size / 2), "eraserCursor");
In my code, to achieve translucent image, I use this snippet:
g.setComposite(AlphaComposite.SrcOver.derive(0.8f));
g.drawImage(image, 0, 0, null);
g.setComposite(AlphaComposite.SrcOver);
See whether it works for you...

Categories