0

I'm trying to make a Mario game clone, and right now, in my constructor, I have a method that is supposed to make a certain color transparent instead of the current pinkish (R: 255, G: 0, B: 254). According to Photoshop, the hex value is ff00fe. My method is:

public Mario(){
    this.state = MarioState.SMALL;
    this.x = 54;
    this.y = 806;
    URL spriteAtLoc = getClass().getResource("sprites/Mario/SmallStandFaceRight.bmp");

    try{
      sprite = ImageIO.read(spriteAtLoc);
      int width = sprite.getWidth();
      int height = sprite.getHeight();
      int[] pixels = new int[width * height];
      sprite.getRGB(0, 0, width, height, pixels, 0, width);

      for (int i = 0; i < pixels.length; i++) {

        if (pixels[i] == 0xFFff00fe) {

          pixels[i] = 0x00ff00fe; //this is supposed to set alpha value to 0 and make the target color transparent
        }

      }
    } catch(IOException e){
      System.out.println("sprite not found");
      e.printStackTrace();
    }
  }

it runs and compiles, but sprite comes out exactly the same when I render it. (edit: perhaps of note I do not have super.paintComponent(g) in my paintComponent(g) method. The sprites are .bmps. this what the sprite looks like

Derry
  • 371
  • 1
  • 13
  • Can you explain what the exact problem with the sprite is in more detail? – SteelToe Aug 02 '17 at 03:34
  • Time to do some debugging, I think. – Hovercraft Full Of Eels Aug 02 '17 at 03:36
  • it's supposed to be a sprite of Super Mario and its to be in bmp format; since its all in a square, the pixels that are not Mario are a color that I want to be turned transparent when painted. – Derry Aug 02 '17 at 03:36
  • What are you doing with the `pixels` array after you modify it? You probably should be creating a new `BufferedImage` from the array, or calling `setRGB` with the updated pixels. – Ted Hopp Aug 02 '17 at 03:37
  • apparently other software clones that use sprites have the sprites as bmps in the src folder with a similar color as I have – Derry Aug 02 '17 at 03:44
  • For better help sooner, post a [MCVE] or [Short, Self Contained, Correct Example](http://www.sscce.org/). Embed the image in the question so the code can hot-link to it. – Andrew Thompson Aug 02 '17 at 03:47
  • I embedded an example of a sprite, tho this site has it in .png, mine is .bmp – Derry Aug 02 '17 at 03:57
  • *"I embedded an example of a sprite"* 1) Tip: Add @HovercraftFullOfEels (or whoever, the `@` is important) to *notify* the person of a new comment. 2) Where is the MCVE that loads that image? – Andrew Thompson Aug 02 '17 at 04:54

3 Answers3

3

You are only retrieving the pixels using BufferedImage.getRGB. That returns a copy of the data in a certain area of the BufferedImage.

Any change you make to the int[] returned is not automatically reflected back into the image.

To update the image, you need to call BufferedImage.setRGB after you change the int[]:

sprite.setRGB(0, 0, width, height, pixels, 0, width);

Another change you should probably make (and this involves a little guesswork as I don't have your bmp to test with) - the BufferedImage returned by ImageIO.read may have type BufferedImage.TYPE_INT_RGB - meaning that it doesn't have an alpha channel. You can verify by printing sprite.getType(), if that prints 1 it's TYPE_INT_RGB without an alpha channel.

To get an alpha channel, create a new BufferedImage of the right size and then set the converted int[] on that image, then use the new image from then on:

BufferedImage newSprite = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
newSprite.setRGB(0, 0, width, height, pixels, 0, width);
sprite = newSprite; // Swap the old sprite for the new one with an alpha channel
Erwin Bolwidt
  • 30,799
  • 15
  • 56
  • 79
  • so after the for-loop, place the code you have? I tried that, it didn't do – Derry Aug 02 '17 at 03:45
  • Yes, after the for-loop. – Erwin Bolwidt Aug 02 '17 at 03:52
  • There may be more problems with your process - above is a necessary step but perhaps not the only one. Have you used a debugger or a print statement to see whether any pixel was equal to `0xFFff00fe`? – Erwin Bolwidt Aug 02 '17 at 03:52
  • I put a System.out.println(pixels[i]) and it gives me 16711934. I googled it an it indeed looks like that's equivalent to the color I'm trying to get rid of – Derry Aug 02 '17 at 03:59
  • 1
    @Derry 16711934 is `0xFF00FE`, not `0xFFff00fe`. Why not change the line to `if (pixels[i] == 0xFF00FE)` or even `if (pixels[i] == 16711934)` ? – Erwin Bolwidt Aug 02 '17 at 04:02
  • I've done that; I have if (pixels[i] == 0xFF00FE) { pixels[i] = 0x0000FE; } } sprite.setRGB(0, 0, width, height, pixels, 0, width); but its not changing anything – Derry Aug 02 '17 at 04:09
  • OK I am able to replace it if I put: if (pixels[i] == -65282) { pixels[i] = 0xFFFFFF; } that -65282 I got using printstream; why was it a negative number? – Derry Aug 02 '17 at 04:36
  • -65282 is the same as `0xffff00fe` (Java ints are always signed and use twos-complement encoding of negative numbers) - so what is the value before you change it? -65282 or 16711934? – Erwin Bolwidt Aug 02 '17 at 05:47
  • -65282 was the value before I changed it. but since the hex numbers don't work, what should I put as the value to make them transparent? – Derry Aug 02 '17 at 05:55
  • 1
    I extended the answer - probably reading the BMP resulted in a `BufferedImage` without an alpha channel, so you need to create one with an alpha channel. – Erwin Bolwidt Aug 02 '17 at 06:08
1

BMP images don't provide an alpha channel, you have to set it manually (as you do in your code)...

when you check your pixel to have a certain color you have to check without alpha (BMP has no alpha it's always 0x0).

if (pixels[i] == 0x00ff00fe) { //THIS is the color WITHOUT alpha
    pixels[i] = 0xFFff00fe; //set alpha to 0xFF to make this pixel transparent
}

so in short: you did all right but mixed it up a bit ^^

Martin Frank
  • 3,445
  • 1
  • 27
  • 47
  • for me, I can change pixel colors when I use (pixels[i] == -65282) but using your code, nothing changes – Derry Aug 02 '17 at 04:49
  • as of now, this: if (pixels[i] == -65282) { pixels[i] = 0xFF000000; } changes the pinkish pixels to black; when I try to put 0x00ff00fe in my if state, it doesn't do anything – Derry Aug 02 '17 at 05:16
1

This works:

enter image description here

private BufferedImage switchColors(BufferedImage img) {
    int w = img.getWidth();
    int h = img.getHeight();
    BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
    // top left pixel is presumed to be BG color
    int rgb = img.getRGB(0, 0); 
    for (int xx=0; xx<w; xx++) {
        for (int yy=0; yy<h; yy++) {
            int rgb2 = img.getRGB(xx, yy);
            if (rgb2!=rgb) {
                bi.setRGB(xx, yy, rgb2);
            }
        }
    }

    return bi;
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • is that on a JFrame? Because right now, on my version, which I took from above, I can get the pink to change, but can't get transparent when shown on the JFrame, only white. If yours is the only way to do it, then I'll try. – Derry Aug 02 '17 at 05:48
  • 1
    *"is that on a JFrame?"* It's **irrelevant** what it's on. The method would work no matter what the top level container was. If you doubt that, *try it* on different backgrounds! As it happens, I never add things directly to a frame. Those labels are added to a `JPanel` (that is then displayed in a `JFrame`). *"If yours is the only way to do it"* Probably not the only way, but markedly different to the approach seen in the question in that it works as expected. I suspect the problem with that approach is getting the hex representation of the color wrong, but I won't be checking that - no MCVE! – Andrew Thompson Aug 02 '17 at 05:55