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.
Related
I have a location icon in red color with a white circle in it.
I want to change the color of it programmatically to yellow color retaining the white colored circle.
I am using this code -
Drawable drawable = getActivity().getResources().getDrawable(R.drawable.location_icon);
Canvas canvas = new Canvas();
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
canvas.setBitmap(bitmap);
drawable.setColorFilter(new PorterDuffColorFilter(context.getResources().getColor(R.color.yellow_color), PorterDuff.Mode.MULTIPLY));
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
drawable.draw(canvas);
return BitmapDescriptorFactory.fromBitmap(bitmap);
How do I theme it to yellow color by retaining the white circle inside it?
Get All the pixels and change one by one to the color you need.
Exemple:
Bitmap bitmap= BitmapFactory.decodeResource(getApplicationContext().getResources(),R.drawable.yourRes);
myBitmap=immutableBmp.copy(Bitmap.Config.ARGB_8888, true);
int [] pixels = new int [myBitmap.getHeight() * myBitmap.getWidth()];
myBitmap.getPixels(pixels, 0, myBitmap.getWidth(), 0, 0, myBitmap.getWidth(), myBitmap.getHeight());
for(int i = 0; i < pixels.length; i++)
{
if(pixels[i] == Color.RED)
{
pixels[i] = Color.YELLOW;
}
}
myBitmap.setPixels(pixels,0,myBitmap.getWidth(),0, 0, myBitmap.getWidth(),myBitmap.getHeight());
I think that for this specific icon you could use vector asset from google and change the tint color for it. Check the link below:
https://developer.android.com/studio/write/vector-asset-studio.html#running
How can I remove the white pixels of an image before loading it in the Panel
the method for loading image in panel is:
public void ajouterImage(File fichierImage) {
// desiiner une image à l'ecran
try {
monImage = ImageIO.read(fichierImage);
} catch (IOException e) {
e.printStackTrace();
}
repaint();
}
You can't remove a pixel for say from an image, but you sure can change the color of it, or even make it transparent.
Let's say you have a pixel array as a variable somewhere, and you can give it the RGB value of your BufferedImage. The pixel array will be called pixels:
try {
monImage = ImageIO.read(fichierImage);
int width = monImage.getWidth();
int height = monImage.getHeight();
pixels = new int[width * height];
image.getRGB(0, 0, width, height, pixels, 0, width);
for (int i = 0; i < pixels.length; i++) {
// I used capital F's to indicate that it's the alpha value.
if (pixels[i] == 0xFFffffff) {
// We'll set the alpha value to 0 for to make it fully transparent.
pixels[i] = 0x00ffffff;
}
}
} catch (IOException e) {
e.printStackTrace();
}
Assuming that by removing pixels you mean setting them to transparent, you need to set the alpha value of the image to zero. Here is a function colorToAlpha(BufferedImage, Color) which takes a BufferedImage and a Color as input and returns another BufferedImage with the Color set to transparent.
public static BufferedImage colorToAlpha(BufferedImage raw, Color remove)
{
int WIDTH = raw.getWidth();
int HEIGHT = raw.getHeight();
BufferedImage image = new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_ARGB);
int pixels[]=new int[WIDTH*HEIGHT];
raw.getRGB(0, 0, WIDTH, HEIGHT, pixels, 0, WIDTH);
for(int i=0; i<pixels.length;i++)
{
if (pixels[i] == remove.getRGB())
{
pixels[i] = 0x00ffffff;
}
}
image.setRGB(0, 0, WIDTH, HEIGHT, pixels, 0, WIDTH);
return image;
}
Example usage:
BufferedImage processed = colorToAlpha(rawImage, Color.WHITE)
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);
}
How do I create an in-memory fully transparent SWT image and draw a black line on it with antialias enabled?
I expect the result to include only black color and alpha values ranging from 0 to 255 due to antialias...
I googled and tried everything that I could... is this possible at all?
This is how I did and it works:
Image src = new Image(null, 16, 16);
ImageData imageData = src.getImageData();
imageData.transparentPixel = imageData.getPixel(0, 0);
src.dispose();
Image icon = new Image(null, imageData);
//draw on the icon with gc
I was able to make this work, although it feels a bit hacky:
Display display = Display.getDefault();
int width = 10;
int height = 10;
Image canvas = new Image(display, width, height);
GC gc = new GC(canvas);
gc.setAntialias(SWT.ON);
// This sets the alpha on the entire canvas to transparent
gc.setAlpha(0);
gc.fillRectangle(0, 0, width, height);
// Reset our alpha and draw a line
gc.setAlpha(255);
gc.setForeground(display.getSystemColor(SWT.COLOR_BLACK));
gc.drawLine(0, 0, width, height);
// We're done with the GC, so dispose of it
gc.dispose();
ImageData canvasData = canvas.getImageData();
canvasData.alphaData = new byte[width * height];
// This is the hacky bit that is making assumptions about
// the underlying ImageData. In my case it is 32 bit data
// so every 4th byte in the data array is the alpha for that
// pixel...
for (int idx = 0; idx < (width * height); idx++) {
int coord = (idx * 4) + 3;
canvasData.alphaData[idx] = canvasData.data[coord];
}
// Now that we've set the alphaData, we can create our
// final image
Image finalImage = new Image(canvasData);
// And get rid of the canvas
canvas.dispose();
After this, finalImage can be drawn into a GC with drawImage and the transparent parts will be respected.
I made it by allocating an ImageData, making it transparent then creating the Image from the data :
static Image createTransparentImage(Display display, int width, int height) {
// allocate an image data
ImageData imData = new ImageData(width, height, 24, new PaletteData(0xff0000,0x00ff00, 0x0000ff));
imData.setAlpha(0, 0, 0); // just to force alpha array allocation with the right size
Arrays.fill(imData.alphaData, (byte) 0); // set whole image as transparent
// Initialize image from transparent image data
return new Image(display, imData);
}
To scale with transparency, I've found that I have to manually set the alpha byte array as shown below. So the alpha ends up with nearest-neighbor anti aliasing.
public static Image scaleImage(Device device, Image orig, int scaledWidth, int scaledHeight) {
Rectangle origBounds = orig.getBounds();
if (origBounds.width == scaledWidth && origBounds.height == scaledHeight) {
return orig;
}
ImageData origData = orig.getImageData();
ImageData imData = new ImageData(scaledWidth, scaledHeight, origData.depth, origData.palette);
if (origData.alphaData != null) {
imData.alphaData = new byte[imData.width * imData.height];
for (int row = 0; row < imData.height; row++) {
for (int col = 0; col < imData.width; col++) {
int origRow = row * origData.height / imData.height;
int origCol = col * origData.width / imData.width;
byte origAlpha = origData.alphaData[origRow * origData.width + origCol];
imData.alphaData[row * imData.width + col] = origAlpha;
}
}
}
final Image scaled = new Image(device, imData);
GC gc = new GC(scaled);
gc.setAntialias(SWT.ON);
gc.setInterpolation(SWT.HIGH);
gc.setBackground(device.getSystemColor(SWT.COLOR_WHITE));
gc.fillRectangle(0, 0, scaledWidth, scaledHeight);
gc.drawImage(orig, 0, 0, origBounds.width, origBounds.height, 0, 0, scaledWidth, scaledHeight);
gc.dispose();
return scaled;
}
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...