I am making an application that displays a picture of a room. When the user clicks the picture, an image pops up with the word of the object, and the device says the name. In order to do this, I load a pattern image that has colored blocks in the places of the objects, and a text file that has the different object names mapped to the specific color of the block.
I also made a Java application that can be used to create these two files. The user draws the rectangles over the image, and the application saves the rectangles drawn to a new image file.
Here is the Java code for creating/saving the image:
BufferedImage i = new BufferedImage(img.getWidth(), img.getHeight(),
BufferedImage.TYPE_INT_RGB);
Graphics g = i.getGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, i.getWidth(), i.getHeight());
//draw all the rectangles on the image
for(Rectangle r: rects.keySet()){
g.setColor(rects.get(r));
g.fillRect(r.x, r.y, r.width, r.height);
}
//write the BufferedImage to the file
try {
ImageIO.write(i, "png", saveTo);
} catch (IOException e) {
e.printStackTrace();
}
When I open the picture in Photoshop, Paint, etc, it verifies that the colored blocks are the color they are supposed to be.
When I load them in the Android device, They are not the same color. They differ in a range from 1-3 on each color (so a color that is 25:0:0 is read as 24:0:0 or maybe 22:0:0).
On the device, I load the image as a bitmap, and use a TouchEvent.getX() and getY() to find the position on the image. I then use Bitmap.getPixel(x,y) to get the specific color.
If I use an editor like Photoshop or Paint, I get perfect images that read like normal. My user has asked for their own editor application, so it can create the config file as well.
Sorry for this being so long, and thanks for any help!
Load you colored block as an asset, and not a resource. Android compresses and re-packages bitmaps in the resources folder to minimize their size. I believe the compression is what is causing your colors to shift.
It might be interesting to pull the image from the device using ADB to see if the on-devic e image is actually different. I expect it is.
Bitmaps contained in the assets folder are not processed at all. Use these for images that need to be maintained at their present quality.
Related
I've tried asking this question on LibGDX forums with no luck.
Basically, I've created my own packer that takes multiple spritesheets like these and packs them into something like this. As a result, I can load these packed files as arrays of TextureRegions with their X and Y offset, so that they can be drawn as if they actually had all these unnecessary transparent pixels.
Anyway, here's what I do:
Load chosen images as pixmaps;
Iterate over their "tiles" (for example, 128x128px parts of the image);
Find offsets for each tile (offsets being amount of rows/columns with only transparent pixels);
Draw non-transparent part of the tile into a new, small pixmap (continuing the example, 128-offsetLeft-offsetRight, 128-offsetTop-offsetBottom, format is the same as the loaded image);
Save each pixmap with some drawing data (offsets) in a container.
Repeat for all tiles and images.
Find the most efficient way to pack the tiles from containers into a new, bigger pixmap (again, the same format).
Save custom description file.
Save pixmap as PNG.
Pixmap-related code snippets:
Image loading:
final Pixmap image = new Pixmap(imageData.getFileHandle());
Drawing image into smaller pieces:
final Pixmap tile =
new Pixmap(imageData.getTileWidth() - offsetLeft - offsetRight, imageData.getTileHeight()
- offsetTop - offsetBottom, image.getFormat());
tile.drawPixmap(image, -columnIndex * imageData.getTileWidth() - offsetLeft,
-rowIndex * imageData.getTileHeight() - offsetTop);
Creating new Pixmap for the packed image:
Pixmap packedImage =
new Pixmap(packedImageWidth, packedImageHeight, image.getFormat());
Drawing pieces into pixmap:
packedImage.drawPixmap(frame.getPixmap(), frame.getOriginX(), frame.getOriginY());
Saving packed image:
final PixmapIO.PNG png = new PixmapIO.PNG();
png.setCompression(Deflater.NO_COMPRESSION);
png.setFlipY(false);
try {
png.write(chosenDirectory.child(packedFileName + FILE_FORMAT), packedImage);
} catch (final IOException exception) {
throw new RuntimeException(exception);
}
As a result, colors are somewhat distorted:
(Left: after packing, right: before packing, loaded and rendered as texture.)
Could any step of the packing I do distort the image or is it the saving part? Do I have to look for another solution (pure Java image processing?) or is there a way to preserve colors using LibGDX API?
Since you don't want these sprites to be blended onto the destination Pixmap, but rather replace the pixels there, I think you want to set Pixmap.setBlending(Blending.None); before you start calling drawPixmap on anything.
Sidenote: as Alexander Mironov said, LibGDX's texture packer handles whitespace stripping, and the TextureAtlas class provides you with a Sprite subclass called AtlasSprite that invisibly handles positioning the image as if the whitespace were still part of it. The various createSprite methods actually return an AtlasSprite if whitespace was stripped from the original source.
I have two RenderedImages. I want to do an Overlay Operation with these two images and therefore they need to match in data type and the number of bands.
The problem I have is that one image has 3 bands (RGB) and the second image has 4 bands (ARGB).
My question is how can I add an Alpha Channel to the first image so I can do the Overlay Operation?
EDIT
Ok, I found a method of adding an Alpha Channel to the first image. Below is the code. I simply created a single banded constant image and merged it with my first image.
ParameterBlock pb = new ParameterBlock();
pb.add(new Float(finalImage.getWidth())).add(new Float(finalImage.getHeight()));
pb.add(new Byte[] {new Byte((byte)0xFF)});
RenderedImage alpha = JAI.create("constant", pb);
finalImage = BandMergeDescriptor.create(finalImage, alpha, null);
The problem I have now is that everytime I add an overlay the image changes colors. All the colors become nuances of red or pink. When I add a second overlay, the image becomes normal again, but the first overlay changes colors. All black areas become white.
Also the background of the overlay is not transparent. It is grey.
Below are examples of the images, so you see how the change colors:
As you can see, the picture and overlays change colors and the background of the overlay isn't transparent.
Can you help me solve this problem, so that the image is always displayed correctly? Thanks!
You can try to create a new BufferedImage with ARGB-model, and just paint the non-transparent background picture into this new BufferedImage. Then you have a BufferedImage with alpha-channel (although all of the pixels are opaque), so the Composition should hopefully work.
im not sure about TYPE_4BYTE_ARGB as I usually work with BufferedImages of TYPE_INT_ARGB but I have often used the method of drawing a RGB BufferedImage to a new ARGB BufferedImage and then drawing that onto other things without problem. the change in color would suggest an unwanted change is being made to the other channels in the overlay process as it doesn't seem to be specific to a specific image. If your overlay operation is similar to drawing one image onto another with alpha I would probably suggest using the Graphics.drawImage()/drawRenderedImage() method for the overlay itself not to mention the background should not even need alpha in this case.
the code:
public RenderedImage overlay(RenderedImage back, RenderedImage front, AffineTransform overlayTransformation)
{
BufferedImage newBack = new BufferedImage(back.getWidth(), back.getHeight(), TYPE_3BYTE_RGB);
newBack.setData(back.getData());
Graphics2D graphics = (Graphics2D)(newBack.getGraphics());
graphics.drawRenderedImage(front, overlayTransformation);
return newBack;
}
you may want to ensure the original back Raster is not modified though.
I'm making a simple side scroller game in Java but am having trouble making the camera move with the person. My plan was to create a buffered image that could adjust the region of the image that is displaying and simply have it follow my character. However, I couldn't find any functions in the API to change the region of the buffered image that's displayed, so how could I do this? Thanks for any help provided.
//The level is created in an 800x400 pixel size, is there any way I can change
//the region myImage displays?
myImage = new BufferedImage(400, 400, BufferedImage.TYPE_INT_RGB);
Well while you will be drawing your image you have a lot of options for example this function can draw any rectangle from your original image on any rectangle of the surface you get Graphics object from.
I want to inset a image into a background and save it, both are png files with transparency, below code work fine but new image become black & white only.
BufferedImage BUFFEREDIMAGE1=ImageIO.read(new File(strPATH+"/IMAGE.png"));
BufferedImage BUFFEREDIMAGE2=ImageIO.read(new File(strPATH+"/WATERMARK.png"));
Graphics2D GRAPHICS1=BUFFEREDIMAGE1.createGraphics();
GRAPHICS1.drawImage(BUFFEREDIMAGE2,intLeft,intTop,intWidth,intHeight,null);
GRAPHICS1.dispose();
ImageIO.write(BUFFEREDIMAGE2,"png",new File(strPATH,"SAVED.png"));
The most likely cause is that at some point the colour space of the image is becoming changed. You may be better off explicitly creating a new destination BufferedImage with the RGB or RGBA format and writing both source Images into it. This removes any possible variation in that area.
In my program,I am producing a png from a panel,but I want to get rid of the bounding box of
this panel and to be more focused to the object in the panel.To do so, I want to get rid of the peripheral parts of png, and produce only the center of it.How can i do that ?
Assuming that you already have your image loaded into a BufferedImage (which seems to be the case), this code will crop the image from (x,y) to (width,height).
image = image.getSubimage(x, y, width, height);
Then save as normal.