collected image in one unique image java - java

I need an information: I have to do a project for my university's stage. My program allow me to discover an image with circular movement. I have a lot of images that should be collect in a unique "long" image, with black edges. Is it possible?
I searched in the other topic but they are only for iOs or html. My application is an application in java that will be use on the pc.
Sorry for the bad english
Thank's, Elia.

Using the dogbane's answer,
You could adapt the code easily to do what you want.
Using Graphics.fillRect to create a rectangle. Just need to set the color to black but you will need to manage the height and width in code.
g.setColor(Color.BLACK);
//Black rectangle on the left edge
g.fillRect(x, y, rectWidth, rectHeight);
x += rectSize;
for(String image : images){
BufferedImage bi = ImageIO.read(new File(image));
g.drawImage(bi, x, y, null);
x += bi.getWidth();
//Black rectangle on the right
g.fillRect(x, y, rectWidth, rectHeight);
x += rectSize;
}
You will see an rectWidth, rectHeight to generate the black square. You have two solutions here,
set it yourself (a parameter that you give from the batch)
iterate on the image first to get the biggest height of this batch (carefull on the perfs)
Note :
to improve this, you might want to center the image if those have some different sizes ... this will requires somt update to add a black square up above and below. But it's a nice exercice ;)
The default background is black, so you don't need to create the filled rectangle for a black one (default byte are 0 so black #000000)
Stangely, a Windows XP tell me the PNG is not valid but on a Seven it works fine, might need to investigate this.
UPDATE :
Since we need the result image height and width on the beginning (didn't though about it), we answer some question
It is easy to update the background color to don't bother with it later (paint the full image at the beginning
We are force to iterate the image first to do the sum of there width
We can get the maximum height in the same time

Related

JAVA - swing - draw/fill with invert/negated colors of destination canvas

I cannot find any info on how to draw shapes on a graphic canvas, making sure what I draw is not the same color as the background
there are some solutions out there but they all use images drawing only with per pixel operations/loops or filters; I also tried different Composite operations, but none suit what I want
so lets say I do
g.setColor(color.white) // relevant in this case ? not sure
g.fillRect(...)
I want the rectangle to be in inverted colors of the background so it is always visible
sorry I cant provide more code, I really dont know how to achieve this
thanks
Your paint method could retrieve the current color, and search for its complementary color:
Color originalColor = g.getColor();
g.setColor(complementaryColor(originalColor));
g.fillRect(0, 0, 50, 50);
The complementaryColor method is inspired from this topic : Reverse opposing colors
Color complementaryColor(final Color bgColor) {
Color complement = new Color(255 - bgColor.getRed(),
255 - bgColor.getGreen(),
255 - bgColor.getBlue());
return complement;
}

Drawing subset of a gradient in libgdx

I know this question has been accessed before (like here), but I was wondering how to do the following. In my game, I have a scrolling background. There is for example a blue sky that is light blue at the bottom and gets darker the higher you go. This is not really possible with the suggested solution:
shapeRenderer.filledRect(x, y, width, height,
lightBlue, lightBlue, darkBlue, darkBlue);
since you can only give the colors that really will be shown. I would like to have a gradientPaint with at the top darkblue and the bottom lightblue that stretches out over for example 500 pixels. This, while I only draw only 200 pixels of it. With this, the color would still get darker when the background scrolls. Does anybody know how to do this with libgdx?
What you want is to see a smaller (say 200 pixel) window onto a larger (say 500 pixel) gradient. To do that you just need to compute the colors of four corners colors based on the location of your window in the overall gradient, and then draw just that. (So don't think about drawing the entire background, but about figuring out how to draw just the part that you need.)
Since you're just moving smoothly between the two colors (between 0 and 500), you're doing a "linear interpolation" (that is a straight-line estimation) between the colors based on where the Window is. Libgdx supports this via the lerp() methods on Color.
Assuming the window is travelling along the Y axis, something like this should give what you want:
Color baseColor = lightBlue;
Color topColor = darkBlue;
int skyHeight = 500;
int windowHeight = 200;
int windowLocation = ...; // something betweeen 0 and skyHeight - windowHeight;
Color windowBottomColor = baseColor.copy().lerp(topColor, windowLocation / skyHeight);
Color windowTopColor = baseColor.copy().lerp(topColor, (windowLocation + windowHeight) / skyHeight);
Now windowBottomColor and windowTopColor should be suitable for calling filledRect:
shapeRenderer.filledRect(x, y, width, height,
windowBottomColor, windowBottomColor, windowTopColor, windowTopColor);
Note that the "copy()" calls create a new Color object for each invocation, so you might want to optimize that to avoid the allocation.
Disclaimer: I haven't tried this code, so it probably has some stupid bugs in it, but hopefully it gives you the right idea.

Apply Bitmask to BufferedImage

I'm developing a Worms-like game (with destructible terrain and everything) in Java.
All did fine until i tried to update the terrain image using a bitmask.
Let me explain the process in detail :
Whenever a projectile collision occurs i draw a black circle into my
terrain mask (which has black for transparent and white for opaque pixels).
public void drawExplosion(Vector2 position,BufferedImage explosionImage){
Graphics2D gMask = (Graphics2D) terrainMask.getGraphics();
gMask.drawImage(explosionImage,(int) position.x, (int) position.y, null);
gMask.dispose();
}
After the black circle was drawn into my terrainMask BufferedImage whose type is
BufferedImage.TYPE_BYTE_INDEXED, i update my visible terrain BufferedImage by setting
every pixel to 0 if the terrainMask's pixel is black at the same position.
public void mapUpdate(){
for(int x = 0 ; x < terrainMask.getWidth(); x++){
for(int y = 0 ; y < terrainMask.getHeight(); y++){
if(terrainMask.getRGB(x, y) == -16777216){
terrain.setRGB(x, y, 0);
}
}
}
}
After these steps the terrain BufferedImage is updated and every looks fine, showing the
explosion hole in the terrain.
Here comes my problem :
Whenever I call mapUpdate() the Game stops for 300-500 ms checking 2400*600 pixels and setting transparent pixels in the terrain if a check returns true.
Without setRGB() the lag does not occur. So my Question is how can I apply a bitmask to
a BufferedImage more efficiently.
Important : All BufferedImages are converted to compatible ones using
GraphicsConfiguration.createCompatibleImage() method.
When I call getData() on the BufferedImage to get the pixel array, the fps drops to
~23 fps making the game unplayable, so this is not an option here.
I also setSystem.setProperty("sun.java2d.opengl","True");
to enabled OpenGL Pipeline. Another weird thing is whenever i don't set the openGL property my Game reaches more than 700 fps (with openGL enabled 140 - 250 fps) and my laptop freezes completely. My game loop is the same as described here : http://www.koonsolo.com/news/dewitters-gameloop/ (Constant Game Speed independent of Variable FPS , the last one).
The fastest way you can do this in Java (i.e. no OpenGL) that I know of, would be to:
a) Change your mask (terrainMask) image's colors to white and transparent (instead of white and black). Just changing the color table (IndexColorModel) will do, I guess.
b) Replace the double getRGB/setRGB loop with painting the mask over the terrain, using the proper alpha composite rule. Both setRGB and getRGB are potentially slow operations, due to lookups, color conversion and possible data type conversion (all depending on your images), so they should generally be avoided in performance critical code. The updated code could look something like the following:
public void mapUpdate() {
Graphics2D g = terrain.createGraphics();
try {
g.setComposite(AlphaComposite.DstIn); // Porter-Duff "destination-in" rule
g.drawImage(terrainMask); // Clear out transparent parts from terrainMask
}
finally {
g.dispose();
}
}
Doing it this way should also keep your images managed (i.e. no fps drop).
For more information on AlphaComposite, see Compositing Graphics from the Java2D Advanced Topics tutorial.
PS: Another optimization you could do, is to only update the part of terrain that are covered by the explosion (i.e. the rectangle covered by position.x, position.y, explosionImage.getWidth(), explosionImage.getHeight()). No need to update the pixels you know isn't covered...

Graphics2D: How to create consistent padding around an irregular shape?

I'm using Java Graphics2D to generate this map with some sort of tinted red overlay over it. As you can see, the overlay gets cut off along the image boundary on the left side:-
After demo'ing this to my project stakeholders, what they want is for this overlay to clip along the map boundary with some consistent padding around it. The simple reason for this is to give users the idea that the overlay extends outside the map.
So, my initial thought was to perform a "zoom and shift", by creating another larger map that serves as a "cookie cutter", here's my simplified code:-
// polygon of the map
Polygon minnesotaPolygon = ...;
// convert polygon to area
Area minnesotaArea = new Area();
minnesotaArea.add(new Area(minnesotaPolygon));
// this represents the whole image
Area wholeImageArea = new Area(new Rectangle(mapWidth, mapHeight));
// zoom in by 8%
double zoom = 1.08;
// performing "zoom and shift"
Rectangle bound = minnesotaArea.getBounds();
AffineTransform affineTransform = new AffineTransform(g.getTransform());
affineTransform.translate(-((bound.getWidth() * zoom) - bound.getWidth()) / 2,
-((bound.getHeight() * zoom) - bound.getHeight()) / 2);
affineTransform.scale(zoom, zoom);
minnesotaArea.transform(affineTransform);
// using it as a cookie cutter
wholeImageArea.subtract(minnesotaArea);
g.setColor(Color.GREEN);
g.fill(wholeImageArea);
The reason I'm filling the outside part with green is to allow me to see if the cookie cutter is implemented properly. Here's the result:-
As you can see, "zoom and shift" doesn't work in this case. There is absolutely no padding at the bottom right. Then, I realized that this technique will not work for irregular shape, like the map... and it only works on simpler shapes like square, circle, etc.
What I want is to create consistent padding/margin around the map before clipping the rest off. To make sure you understand what I'm saying here, I photoshopped this image below (albeit, poorly done) to explain what I'm trying to accomplish here:-
I'm not sure how to proceed from here, and I hope you guys can give me some guidance on this.
Thanks.
I'll just explain the logic, as I don't have time to write the code myself. The short answer is that you should step through each pixel of the map image and if any pixels in the surrounding area (i.e. a certain distance away) are considered "land" then you register the current pixel as part of the padding area.
For the long answer, here are 9 steps to achieve your goal.
1. Decide on the size of the padding. Let's say 6 pixels.
2. Create an image of the map in monochrome (black is "water", white is "land"). Leave a margin of at least 6 pixels around the edge. This is the input image: (it isn't to scale)
3. Create an image of a circle which is 11 pixels in diameter (11 = 6*2-1). Again, black is empty/transparent, white is solid. This is the hit-area image:
4. Create a third picture which is all black (to start with). Make it the same size as the input image. It will be used as the output image.
5. Iterate each pixel of the input image.
6. At that pixel overlay the hit-area image (only do this virtually, via calculation), so that the center of the hit-area (the white circle) is over the current input image pixel.
7. Now iterate each pixel of the hit-area image.
8. If the any white pixel of the hit-area image intersects a white pixel of the input image then draw a white pixel (where the center of the circle is) into the output image.
9. Go to step 5.
Admittedly, from step 6 onward it isn't so simple, but it should be fairly easy to implement. Hopefully you understand the logic. If my explanation is too confusing (sorry) then I could spend some time and write the full solution (in Javascript, C# or Haskell).

How to -accurately- measure size in pixels of text being drawn on a canvas by drawTextOnPath()

I'm using drawTextOnPath() to display some text on a Canvas and I need to know the dimensions of the text being drawn. I know this is not feasible for paths composed of multiple segments, curves, etc. but my path is a single segment which is perfectly horizontal. I am using Paint.getTextBounds() to get a Rect with the dimensions of the text I want to draw.
I use this rect to draw a bounding box around the text when I draw it at an arbitrary location.
Here's some simplified code that reflects what I am currently doing:
// to keep this example simple, always at origin (0,0)
public drawBoundedText(Canvas canvas, String text, Paint paint) {
Rect textDims = new Rect();
paint.getTextBounds(text,0, text.length(), textDims);
float hOffset = 0;
float vOffset = paint.getFontMetrics().descent; // vertically centers text
float startX = textDims.left; / 0
float startY = textDims.bottom;
float endX = textDims.right;
float endY = textDims.bottom;
path.moveTo(startX, startY);
path.lineTo(endX, endY);
path.close();
// draw the text
canvas.drawTextOnPath(text, path, 0, vOffset, paint);
// draw bounding box
canvas.drawRect(textDims, paint);
}
The results are -close- but not perfect. If I replace the second to last line with:
canvas.drawText(text, startX, startY - vOffset, paint);
Then it works perfectly. Usually there is a gap of 1-3 pixels on the right and bottom edges. The error seems to vary with font size as well. Any ideas? It's possible I'm doing everything right and the problem is with drawTextOnPath(); the text quality very visibly degrades when drawing along paths, even if the path is horizontal, likely because of the interpolation algorithm or whatever its using behind the scenes. I wouldnt be surprised to find out that the size jitter is also coming from there.
I've found a solution that works for my particular situation, although it doesn't really resolve the original question.
Since my particular use case only draws text along single segment straight paths, I was able to get rid of the paths all together and use Canvas.drawText() along with Canvas.translate() and canvas.rotate(). This got rid of the text size randomness and ugliness I was seeing when drawing along paths as well.

Categories