Android Open GL ES non POT texture - android

I am very new to OpenGL ES.
To my understanding openGL ES only allows power of two sized images for textures (eg 512*512 or 256*256 etc...). I am looking for a way to display images of different sizes as textures but they are not power of 2 sized and their size varies.
The pictures will be downloaded from the internet. Resizing them before downloading is out of the question.
Is there a way to use non POT sized images for textures? Do I have to create a method to resize them? Is there a library out there somewhere that does that?
The textures will be applied to rectangles using the library min3d:
http://code.google.com/p/min3d/
thks!
EDIT:
example of texture loading from resources:
InputStream is =getResources().openRawResource(R.drawble.drawable1);
Bitmap bitmap;
bitmap = BitmapFactory.decodeStream(is);

When you load in an image, you could create a larger Bitmap container for it that is of a POT size. Then copy the non-POT image into it. When you load the new Bitmap as a texture you can then crop it to the size you want (third parameter of glTexParameteriv()).
To create the container Bitmap:
// work out the pot size you need from the source Bitmap's size
// ...
Bitmap bigger = Bitmap.createBitmap(potWidth, potHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bigger);
canvas.drawBitmap(nonPOTBmp, 0, 0, null);
// free up memory
nonPOTBmp.recycle();

Related

Cropping and scaling bitmap efficiently 2018?

We are having difficulty with bitmaps in our product. Our goal is to take picture fast and display it/crop immediately. The problem is - image has to be in a good quality, has to be cropped well and fast. I personally tried the code below and it does reduce memory usage by ~ 2-3 times. Still, we would like to know more efficient way. Should we always transfer imageArray[] instead of actual bitmaps between our custom frames processing(using Fotoapparat library, because of its ability to efficiently display full screen camera View) and ImageViews? We are open to use Glide or any other tool to crop, or load bitmap if that would be more efficient. Our current code for image retrieving from cameraView frames(this reduces usage ~ 2-3 times):
ByteArrayOutputStream out = new ByteArrayOutputStream();
YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, width, height, null);
yuvImage.compressToJpeg(new Rect(0, 0, width, height), 50, out);
byte[] imageBytes = out.toByteArray();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, options);
options.inSampleSize = calculateInSampleSize(options, (int)(width/1.5),(int)(height/1.5));
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, options);
Then we crop this Bitmap with method below (this seems inefficient in 2018):
resizedbitmap = Bitmap.createBitmap(original, 0,0,width, height);
Also, what about threads? Should we use AsyncTask, Executors or any other ways for cropping/showing bitmap? I personally always use RxJava, however our core product must be as lightweight as possible :)
Alternatives
If you're on API level 10+ you can alternatively use BitmapRegionDecoder which does the cropping and downsampling in one step, probably in native.
As a totally different approach you can also try converting the data directly to a Bitmap and then using a Canvas to draw some part of the original Bitmap onto a new cropped version, doing scaling via the Canvas' transformation matrix.
Quality
image has to be in a good quality, has to be cropped well and fast.
Your first step where you compress to quality=50, you're losing a lot of information. Then later when you create the new Bitmap, you do an up-scaling which also affects the quality; in my opinion cropping only makes sense if the resulting image is actually smaller.
Efficiency
Then we crop this Bitmap with method below (this seems inefficient in 2018)
Consider this: do you really need the Bitmap to be the exact size? It's probably much better to leave the Bitmap as the cropped size, have the smaller Bitmap in memory, upload the smaller Bitmap to the GPU and let the GPU rendering do the scaling. It's possible the View won't match the Bitmap size, so this will happen anyway.
Glide
Glide pretty much does the same thing at its core as your code (except the YUV bit). See Downsampler, the difference is that it works with many input sources, formats and API levels, hence the size difference.
our core product must be as lightweight as possible :)
Including an image loading library and forcing the user to include that as well goes against this. But at the same time do you really want to re-invent the wheel and write your own image loading library? For example Glide has a lot of pieces that can be replaced for custom behavior.
In my app I have a camera -> user crop selection -> cropped smaller Bitmap flow. I did something similar to yours, except using the disk instead of ByteArrayOutputStream, because the input can be huge and it would need to fit kind-of twice into memory for which there's no guarantee.

Is this conceptually how Android resizes images within an ImageView?

I tried following some ImageView and BitmapDrawable source code to gain a better understanding of how the two classes operate on BitMaps. Is this generically how the process works?
I have an image which is a JPEG of size 500x500
I have ImageView A which is size 250x250, and ImageView B which is size 500x500.
Both have a BitmapDrawable which contains the JPEG
When its time to draw the Bitmap, A and B will both apply a matrix that will scale the bitmap appropriately to their respective canvas.
The JPEG itself will remain unscaled

Drawing scaled bitmaps on a SurfaceView -- no antialiasing

I'm sorry if this topic has been brought before, but all my searches on the web and google groups did not help me.
I'm currently developing a little game with the Android SDK, and use hi-res bitmaps that I resize accordingly to match the device's resolution (letting the system do it for me is
not "crisp" enough).
I use a SurfaceView, on which I paint in one pass a canvas filling the whole surface. The paint uses setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)) to allow masking.
Beforehand, I retrieve various bitmaps -- which are resized at initialization with createScaledBitmap() and put in a cache -- and I apply the bitmaps with a paint on this canvas, before drawing this canvas on the SurfaceView.
My problem is, whatever I try, whatever paint settings I use (dithering, antialias, etc..), the resized bitmaps are not antialiased and the drawing present jagged edges. I tried everything.
The only little success I had was using inSampleSize to approach the desired scaled size and force a first pass of antialiasing, before invoking createScaledBitmap on the retrieved
hi-res bitmap, but it is not beautiful enough. I just can't allow to create multitudes of pre-sized bitmaps for every combination of resolution. What did I miss ?
Thanks a lot in advance
First when you load your bitmap you make sure that you don't lose any image quality by settings options to argb_8888:
Options options = new Options();
options.inScaled = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap pic = BitmapFactory.decodeResource(getResources(), R.id.pic, options);
When you scale the bitmap turn on the filter:
pic = Bitmap.createScaledBitmap(pic, screenW, screenH, true);
However if one streaches the image too much inevitably it degrades in quality.
When you use paint you can improve quality but lose on speed with turning on ditherig and filtering:
Paint paint = new Paint();
paint.setFlags(Paint.DITHER_FLAG);
paint.setFilterBitmap(true);
Finally the entire activity window could be set on argb_4444 instead on argb_8888 (OS < 2.3). You can chage this if you instert this line before setContentView:
getWindow().setFormat(PixelFormat.RGBA_8888);
If it comes down to it, you can manually antialias without too much trouble. Just apply a simple lowpass filter (something like an NxN average) to the pixel data before asking the bitmap object to rescale itself.
you may clear canvas buffer by youself! such as follows:
canvas.drawColor(Color.TRANSPARENT, android.graphics.PorterDuff.Mode.CLEAR);

drawBitmap where one pixel equals one pixel

If I draw a bitmap on a view canvas using drawBitmap(), the images will be resampled so that 1 pixel in the image will be 1 dip on the screen. On a device I have with high pixel density, that means each image pixel is spread across 1.5 screen pixels, degrading the image. Handy in general, but in some cases I want to carefully select the images I want to draw, then draw them explicitly at their native size, so they won't degrade. How do I do this?
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inScaled = false;
Bitmap mBitmap = BitmapFactory.decodeResource(mResource, R.drawable.resource, opts);
alternatively you could store your resources inside a res/drawable-nodpi folder

Write contents of custom View to large Image file on SD card

I have a class that extends View. I override the onDraw method and allow the user to draw on the screen. I am at the point where I want to save this view as an image. I Can use buildDrawingCache and getDrawingCache to create a bitmap that I can write to the SD card. However, the image is not good quality at a large size, it has jagged edges. Since I have a View and I use Paths I can transform all by drawing to a bigger size. I just don't know how to make the Canvas bigger so when I call getDrawingCache it doesn't crop all the paths I am just transformed. What is happening is I transform all my paths but when I write the Bitmap to file I am only getting the "viewport" of the actual screen size. I want something much bigger. Any help in the right direction would be greatly appreciated. I have been reading the docs and books and am at a loss.
Thanks
Jon
You can create another Canvas backed by a Bitmap that you create and draw all the paths to that. Then the Bitmap will hold the larger, higher resolution image. It would look something like this:
Bitmap largeBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas largeCanvas = new Canvas(largeBitmap);
// Draw the paths to this canvas and then use largeBitmap to save to a file.

Categories

Resources