I need to fit a huge image (BufferedImage to access colors etc) into a JScrollPane derived class. Nothing very hard until there.
The image is a JPG scan of an A3 sample of material, its size is 13030x20840 pixels, 24bits, and weights 12MB on disk -> about 800MB in RAM.
I embedded the BufferedImage into a Jpanel, which lies as the Scrollpane's view.
When I try to scroll/drag my image, it takes seconds to respond, so it is not very handy.
I need your help in order to know what I should do to render the scrollpane's scrolling and the image dragging as smooth and reactive as possible, but I easily figure out that with such an image it could be impossible.
I tried many options, such as double buffering, etc. but I'm quite new to Swing, then it is greatly possible I missed some simple solution.
If there is a need to change the BufferedImage by something else, or whatever, I'm receptive to any solution.
So, we have a large 13,030 x 20,840 pixel image.
if we break this image into 256 x 256 pixel tiles, we get a tile set that's 51 tiles across and 82 tiles down. The last tiles in the rows and columns will be partial images, since 256 doesn't go evenly into 13,030 and 20,840.
Let's assume our display window is 400 X 400 pixels. Let's also assume were starting in the upper left hand corner of the large image.
We take and make a 3 x 3 tile buffered image. This would be 768 x 768 pixels, which allows enough overlap for smooth scrolling. We take the first 3 tiles from the first row, the first 3 tiles from the second row, and the first 3 tiles from the third row to make our 3 x 3 tile buffered image.
Now, when we set up the horizontal and vertical scroll on the JScrollPane, we have to set the maximum value on the horizontal scroll to 13,030 and the maximum value on the vertical scroll to 20,840. This is so the user is kinetically aware that he is scrolling a large image.
Ok, we display the 3 x 3 tile buffered image. The user scrolls to the right to see more images. The user has scrolled 256 pixels.
The application now has to build a new 3 x 3 tile buffered image. We take the 2nd through 4th tiles from the first row, second row, and third row. We display this new buffered image. To the user, it looks like one huge image. To the application, a series of small 3 x 3 tile buffered images are displayed.
mKorbel has already created some code which builds and displays these smaller buffered images on the fly.
To deal with zooming, you can resize the large image outside of the Java application and create more than one tile set. This makes the Java application code more complicated, but much faster than trying to resize the smaller buffered images in the Java application.
I found what I needed there :
very large image manipulation and tiling
A nice book, the sample shown covers that.
The Java JAI lib has a lot of features to handle these kind of problems, and is supported by Oracle, which means it is (theoretically) stable and sustainable.
Thanks to #BryanD !
Related
I dont understand what happens with pixels in Virtual Display in Android when output dimensions are reduced compared to the input ones ?
When I have for example input = size of my Display = 1920x960 and I set outputs to be 1920/3 and 960/3, what happens in that case with image pixels:
pixel density is increased or
maybe it takes only smaller part of screen that is centered and has dimensions 640x320 or
something else?
Additionally, is there a way that I can only grab center part of screen as in picture below?
By digging in the AOSP, watching, looking at a thread and experimenting~
I have come to my own (might be overly) simplified conclusion.
Android calls the native Java SDK which produces the information that's needed to render a bitmap/pixels on a Java program.
If the results are the same don't need to pass/copy it again to the GPU.
If the results are not the same pass/copy it to the GPU to be "invalidated" then re-rendered.
Now to your question.
By looking at the Bitmap class and looking at this thread It came to my mind that resizing depends on the scaling ratio passed on to the Matrix class.
If resized, it will expensively create a new Bitmap that looks like something either a pretty-bad higher pixel-density or not-so-smooth lower pixel density.
If the pixel-density is increased (smaller dimensions, your case) it will look squashed and if need be, the colors are averaged to the nearest neighbouring pixels. ("kind of" like how JPEG works).
After resizing it will still stay to it's origin (top-left part of the rendered object) which is defined by it's X and Y coordinates.
For your second question, about screen grabbing you can take a look at this and then programatically resize the image by doing something like this:
//...
Bitmap.createBitmap(screenshot_bitmap, left, top, right, bottom);
//...
I am currently designing Agar.io game with Java. Most parts of my game went well. The only problem is when the blob reaches certain size, it become too big for the current screen size to handle. I need to find a way to automatically shrink game canvas (window dimensions stay the same) to make the big blob to appear smaller and smaller food blobs appear even smaller than before.
My original approach was reducing each of blob's width and height to make then smaller, that's when I noticed this approach will not only reduce blob's size but increase distance between blobs. I dropped it.
I need some suggestions on how to take account on blob's x, y positions and width, height to "shrink" game canvas.
I'm facing a performance problem with my mobile game which I write in LibGDX.
Let's assume that there is only one resolution - 1920x1080 - just for testing.
I have a spritesheet combined with images like this below:
I want these particles to fly around my logo, so I need their size to be at least 256px/512px - so it looks good on a given resolution.
If one frame has that size and I need at least 32 frames for it to look good, it's easy to calculate that the whole spritesheet has dimensions:
width: 256 * 8 (columns) = 2048
height: 512 * 4 (rows) = 2048
This is the most optimistic idea, cause the spritesheet should be even bigger.
The weight of the spritesheet is ~50kb so it's really fine, but the dimensions are getting me in trouble.
Yesterday I tested everything on a Desktop version in LibGDX, everything renders fine. I ported the game after finishing the menu to Android and the area where this spritesheet should be drawn is black.
I read on gamedev or here (don't remember) that I should use only graphics with a maximum size od 1024/1024 cause LibGdx has some problems with loading higher textures with Android on many versions.
What I'm trying to accomplish?
I need to find an idea how to make this work and load the texture.
I already tried with resizing the file using a pixmap, but it takes ints as dimensions, it lowers the quality etc...
I know someone would say, why wouldn't you just create a single 'dot' object with an orange graphic like below, spawn these dots randomly and change their alpha sometimes? It's not an option because I need other animations like 'fog' which can't be programmed that easy like dots.
Maybe there is a way to resize a texture, a region or something (using floats of course to keep the aspect ratio)?
If someone has any ideas, how should I use huge spritesheets in my app, I would be very grateful :)
Your sprite sheet should not exceed the length 2048*2048.
If you want to load a spritesheet which is more than 2048*2048,then you have to load per frame separately.
Suppose, if your sprite sheet contains 15 frames then you must have 15 separate png files.
I am writing a 2D lunar lander-style game in Java and using the Slick2D library to handle the graphics. I am having a problem handling the background images.
Here is my problem:
I have 3 layers of details to paint on the background behind the spaceship (stars, mountains and land including landing sites). These are repainted each loop as the ship (centre of the screen) moves around.
The images for these layers are 4500 pixels wide by 1440 high. This is mainly to create some sense of variety (stars) and to be sufficiently wide to hold the generated mountains and land (the land includes the landing sites). Mountains and land are generated per turn and are polygons drawn into holding images.
Slick2d (or opengl) is complaining that it cannot handle images of this size - it says it can only handle textures that are 512 x 512 on my development PC. So... if I have been exploring different methods to work around this including:
a. doing polygon clipping in each loop to reduce my polygons (mountains and land) to the displayable screen size (640 x 480), but this seems mathematically challenging, or
b. splitting my layer images into 512x512 tiles and then updating the screen with the tiles, which is an extension of what I already do (wrapping the layers to create an 'infinite' world) so seems more do-able given my abilities.
My first question (or sense-check, really) is am I missing something? My images, although large, are minimal in terms of content, e.g. black background with a few lines on. Is there a way to compress these in Slick2D/opengl or have I missed something to do with settings that means I can make my card handle bigger images? (I'm assuming not, based on what I have read, but hope springs eternal.)
So, assuming I have not missed anything obvious, on to part 2...
As a quick "I might get away with this" workaround, I have reverted to using BufferedImages to hold the layers and then extracting portions of these into Slick2D images and painting these on the screen in each render loop. Doing it this way I am getting about 3 FPS, which is obviously a tad slow for a real-time game.
To create the BufferedImages I am using:
BufferedImage im_stars = new BufferedImage(bWIDTH, bHEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics2D gr_stars = im_stars.createGraphics();
... and then I draw my content onto them (stars, etc.)
In my render loop a do a bit of maths to work out which chunks of the images I need to display (to cope with wrapping/providing an 'infinite' experience) and then extract the relevant portions of BufferedImage to a Slick2D image(s) as follows:
Image i1_star = Tools.getImage(stars.getStarImg().getSubimage((int) x1, (int) y1, width, height));
g.drawImage(i1_star, 0, 0);
I have written a static helper method to convert my BufferedImage chunk to a Slick2D Image as follows:
protected static Image getImage(BufferedImage bi) {
Image im = null;
try {
im = new Image(BufferedImageUtil.getTexture("", bi));
} catch (IOException ex) {
Logger.getLogger(Tools.class.getName()).log(Level.SEVERE, null, ex);
}
return im;
}
I'm guessing this is a bad way to do things based on the FPS I am getting, although 3 seems very low. I was getting about 25 FPS when I was using code I'd written myself doing the same thing! So, is there an accelerated Slick2D/opengl way to do this that I am missing or am I back to having to either tile my background images or hold them as polygons and develop a polygon clipping routine?
Having done some more research, I have found that my graphics card can support up to 4096 x 4096 pixel images using Slick2D's:
BigImage.getMaxSingleImageSize();
I have reverted to using Slick2D image files with a width no larger than this size in my program and am now getting around 350 FPS so the BufferedImage work-around was definitely a bad idea.
I am new to android, and my group is currently creating a graphing application using a GlSurfaceView using opengl es 2.0.
We have recently displayed the grid and tickmarks on the plot and now I have been assigned the task to implement a numeric scale and labeling the x and y axis as "X" and "Y".
After doing a lot of research I have determined to accomplish this by rendering a string of characters to a bitmap. I have encountered many problems in achieving this. I understand the basic concept. I know I will need the alphanumeric characters "0123456789" and "XY"and"-"(for the -x and -y scale). I have seen many different examples and have tried extensively to follow JVitella's example here here
I am beginning to grasp the concept but as far as the my string goes I know I have 13 characters so how large should my bitmap be?
Also in Jvitelas example I am dumbfounded by the code:
Drawable background = context.getResources().getDrawable(R.drawable.background);
I dont understand what exactly is going on and when I code this I recieve a syntax error on context.
For my application I understand I would need to save the string into a bit map much like this. I would create a bitmap but how big should it be? Then I create a canvas from the bitmap and canvas.drawText into the bitmap.
[ 0 1 2 3 4 ]
| 5 6 7 8 9 |
[ X Y Z ]
Basically I am asking:
How to achieve the following bit map above?
How would I draw single digit numbers from the bit map?
How would I draw numbers with more than one digit?
You're asking a lot of questions, but I'll try to answer a few:
so how large should my bitmap be?
It's really up to you, depending on how crisp you want the text to be. You could allocate a huge bitmap with hundreds of pixels for each character that would zoom very well, or a very small bitmap with limited resolution. I'd say whatever "font size" you want to have, allocate at least that many pixels in height for each character. So if you want to draw something with a font size of "20", then maybe you need a bitmap 5x20 by 3x20 or 100x60.
How would I draw single digit numbers from the bit map?
You'll draw a quad with opengl in the place where you want to draw a letter, and you use the texture coordinates of that quad to pick a letter.
For example if I want to draw an X, then you draw a quad on the screen, and assign it's texcoords from (0,0) to (0.2, 0.33), which selects the left 1/5th of the texture, and the bottom 1/3rd of the texture. You'll see how a box like this lines up with the position of the "X" in your texture.
How would I draw numbers with more than one digit?
You just draw two independent single digits right next to each other.
If your only goal here is to draw text in Android, it might be easier to just use a FrameLayout, and layer TextViews overtop of your GLSurfaceView. OpenGL isn't designed for text which makes it somewhat cumbersome.