The ByteArray solution sounds good, it could easily wrapped into a Buffer 
an handed
over to glTexImage2d(). A disadvantage of the ByteArray would be that you 
have to
build an Image out of it again, if you want to rescale (often needed to 
ensure textures
are power of two). Flipping is also often needed for OpenGL (horizontal and 
vertcial)
but shouldn't be a problem with either a byte array nor an Image.
 
Another big issue similar to alpha-premultiply is that 32Bit ARGB Images 
are changed
to 16Bit after scaling (especially if all alpha values are 255), without 
some dirty tricks.
This is a big issue to, it's far away from the precission needed for good 
normal mapping.
 
By the way combining greyscale-images into RGBA8888 images, including the 
alpha channel
isn't such a good solution, when it comes to texture compression with etc1, 
which doesn't
support alpha. But in some cases like a normalmap in rgb and height in the 
alpha-component,
it makes absolutly sence, because compression couldn't be done (precision 
loss) and a parallax
shader needs 2 texture-lookups instead of one per iteration if the height 
isn't combined into
normals.
And parallax mapping on todays android-hardware isn't a problem, it would 
be disappointing
if the SDK is the handicap for doing such things.

Am Mittwoch, 20. Juni 2012 22:42:06 UTC+2 schrieb Romain Guy (Google):

> Bitmap and BitmapFactory work only with premultiplied alpha values. We 
> know it is annoying in some cases for GL developers and we've started 
> thinking of various solutions. I don't think we want to add support 
> for non-premultiplied bitmaps, which means we would either have a new 
> method in BitmapFactory that returns images as non-premultiplied byte 
> arrays or offer new APIs in GLUtils to let you upload resources 
> directly into non-premultiplied textures. 
>
> I'd be happy to hear your suggestions on the topic of course. 
>
> On Wed, Jun 20, 2012 at 1:25 PM, arberg <[email protected]> wrote: 
> > On Behalf of Marcus Mengs (mame8282): 
> > 
> > I'm using textures of combined grayscale images, for example a normal 
> > map 
> > with normal in RGB-components and height in A-component. So the 
> > described 
> > issue is a big problem for me. I've treid several fixes including 
> > yours or rewriting 
> > the createScaledBitmap() Method (to prevent premultiplying while 
> > scaling) etc. 
> > 
> > I coulld finally solve the problem. I no more rely on BitmapFactory- 
> > methods, instead 
> > I'm decoding the PNG myself. A good example how to do this, is the 
> > PNGDecoder.java 
> > from the LWJGL-backend of libgdx. It runs on Android with nearly no 
> > change needed. 
> > 
> > 
> http://code.google.com/p/libgdx/source/browse/trunk/backends/gdx-backend-lwjgl/src/com/badlogic/gdx/backends/lwjgl/PNGDecoder.java?r=845
>  
> > 
> > With BitmapFactory it's nearly impossible to do this, because if you 
> > follow the source 
> > of decodeStream(), you'll get to a native method and thus to SKIA, 
> > which hard-coded 
> > the alpha-premultiply in the correspondending method. 
> > 
> > Marcus 
> > 
> > On Thursday, 12 August 2010 14:09:54 UTC+2, arberg wrote: 
> >> 
> >> I just realized the Bitmap-class behaviour is screwed. If I use the 
> >> following method for decoding the bitmap then I get alpha- 
> >> premultiplied pixels when calling Bitmap.getPixels: 
> >> 
> >>   InputStream is = 
> >> context.getResources().openRawResource(texture.resource); 
> >>   try { 
> >>     bitmap = BitmapFactory.decodeStream(is, null, sBitmapOptions); 
> >>   } finally { 
> >>     is.close(); 
> >>   } 
> >> 
> >> If I use 
> >> 
> >>   bitmap = BitmapFactory.decodeResource(context.getResources(), 
> >> texture.resource, sBitmapOptions); 
> >> 
> >> then as mentioned Bitmap.getPixels returns non alpha-premultiplied 
> >> pixel values. Another difference between these two decode-methods is 
> >> that the latter (in my experience) throws out-of-memory exceptions 
> >> more frequently than the former, so either the 
> >> BitmapFactory.decodeResource-method uses more memory, or it uses more 
> >> memory when used in conjunction with my manual texImage2D loading 
> >> algorithm. 
> >> 
> >> Of cause nothing is mentioned in the Android javadoc for Bitmap. 
> >> 
> >> Alex 
> >> 
> >> On Aug 12, 10:50 am, arberg <[email protected]> wrote: 
> >> > Regarding the big-endian comment in the code, I meant little-endian. 
> >> > If we use IntBuffer to write ABGR ints to ByteBuffer on a little- 
> >> > endian-phone we get byte order we RGBA. However the same code running 
> >> > on a big-endian phone should produce ABGR byte order, which is not 
> >> > whatopenglexpects. So don't use intbuffer. 
> >> > 
> >> > The following should also work, and allocates less memory, but I 
> don't 
> >> > quite trust it since I don't have a big-endian phone, and since I 
> >> > cannot test it on a big-endian emulator: 
> >> > 
> >> >         private static final boolean IS_LITTLE_ENDIAN = 
> >> > (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN); 
> >> >         private void myTexImage2D(GL10 gl, Bitmap bitmap) { 
> >> >                 // Don't loading using GLUtils, load using gl-method 
> >> > directly 
> >> >                 // GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 
> 0); 
> >> >                 int[] pixels = extractPixels(bitmap); 
> >> >                 for (int i = pixels.length - 1; i >= 0; i--) { 
> >> >                         int p = pixels[i]; 
> >> >                         int r = ((p >> 16) & 0xFF); 
> >> >                         int g = ((p >> 8) & 0xFF); // green 
> >> >                         int b = ((p) & 0xFF); // blue 
> >> >                         int a = (p >> 24); //alpha 
> >> >                         if (IS_LITTLE_ENDIAN) { 
> >> >                                 pixels[i] = a << 24 | b << 16 | g << 
> 8 | 
> >> > r; 
> >> >                         } else { 
> >> >                                 pixels[i] = r << 24 | g << 16 | b << 
> 8 | 
> >> > a; 
> >> >                         } 
> >> >                 } 
> >> >                 IntBuffer pixelBuffer = IntBuffer.wrap(pixels); 
> >> > 
> >> >                 gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, 
> >> > bitmap.getWidth(), bitmap.getHeight(), 0, GL10.GL_RGBA, 
> >> > GL10.GL_UNSIGNED_BYTE, pixelBuffer); 
> >> >         } 
> >> > 
> >> > Alex 
> >> > 
> >> > On Aug 12, 10:17 am, arberg <[email protected]> wrote: 
> >> > 
> >> > 
> >> > 
> >> > > Apparently the cause of thepremultipliedalphalies in GLUtils, or 
> >> > > perhaps the way GLUtils works with the Bitmap class. We can get the 
> >> > > correct non-premultipliedalphabehaviour by replacing 
> >> > > GLUtils.texImage2D with theopenglmethod gl.glTexImage2D which takes 
> >> > > a pixel component array as a parameter. Thus we can avoid 
> >> > > thepremultipliedalphabehaviour, which means we can use the blend 
> >> > > function gl.glBlendFunc(GL10.GL_SRC_ALPHA, 
> >> > > GL10.GL_ONE_MINUS_SRC_ALPHA); 
> >> > 
> >> > > Note for uninitiated confusedopenglandroid developers: I posted a 
> >> > > question onopengl.org discussion forum, where I described the 
> >> > > symptoms of the 
> >> > > problem:
> http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&N... 
> >> > 
> >> > > Here's how I loaded the image in Android: 
> >> > 
> >> > >     private int loadTexture(GL10 gl, int resourceId) { 
> >> > >         int[] textureNameWorkspace = new int[1]; 
> >> > >                 gl.glGenTextures(1, textureNameWorkspace, 0); 
> >> > >                 int textureName = textureNameWorkspace[0]; 
> >> > >                 gl.glBindTexture(GL10.GL_TEXTURE_2D, textureName); 
> >> > >                 gl.glTexParameterf(GL10.GL_TEXTURE_2D, 
> >> > > GL10.GL_TEXTURE_MIN_FILTER, 
> >> > > GL10.GL_LINEAR); 
> >> > >                 gl.glTexParameterf(GL10.GL_TEXTURE_2D, 
> >> > > GL10.GL_TEXTURE_MAG_FILTER, 
> >> > > GL10.GL_LINEAR); 
> >> > >                 gl.glTexParameterf(GL10.GL_TEXTURE_2D, 
> >> > > GL10.GL_TEXTURE_WRAP_S, 
> >> > > GL10.GL_REPEAT); 
> >> > >                 gl.glTexParameterf(GL10.GL_TEXTURE_2D, 
> >> > > GL10.GL_TEXTURE_WRAP_T, 
> >> > > GL10.GL_REPEAT); 
> >> > 
> >> > >                 gl.glTexEnvf(GL10.GL_TEXTURE_ENV, 
> >> > > GL10.GL_TEXTURE_ENV_MODE, 
> >> > > GL10.GL_MODULATE); 
> >> > 
> >> > >         Bitmap bitmap = BitmapFactory.decodeResource(resources, 
> >> > > resourceId); 
> >> > >         myTexImage2D(gl, bitmap); 
> >> > >         // Set the crop parameter because I use drawtexture 
> extension 
> >> > >                 ((GL11) gl).glTexParameteriv(GL10.GL_TEXTURE_2D, 
> >> > > GL11Ext.GL_TEXTURE_CROP_RECT_OES, 
> >> > >                                 new int[] { 0, bitmap.getHeight(), 
> >> > > bitmap.getWidth(), - 
> >> > > bitmap.getHeight() }, 0); 
> >> > >                 return textureName; 
> >> > >         } 
> >> > 
> >> > >         private void myTexImage2D(GL10 gl, Bitmap bitmap) { 
> >> > >                 // Don't loading using GLUtils, load using 
> gl-method 
> >> > > directly 
> >> > >         // GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); 
> >> > >         int[] pixels = extractPixels(bitmap); 
> >> > >         byte[] pixelComponents = new byte[pixels.length*4]; 
> >> > >         int byteIndex = 0; 
> >> > >         for (int i = 0; i < pixels.length; i++) { 
> >> > >                 int p = pixels[i]; 
> >> > >                         // Convert to byte representation RGBA 
> >> > > required by gl.glTexImage2D. 
> >> > >                         // We don't use intbuffer, because then we 
> >> > >                         // would be relying on the intbuffer 
> wrapping 
> >> > > to write the ints in 
> >> > >                         // big-endian format, which means it would 
> >> > > work for the wrong 
> >> > >                         // reasons, and it might brake on some 
> >> > > hardware. 
> >> > >                 pixelComponents[byteIndex++] = (byte) ((p >> 16) & 
> >> > > 0xFF); // red 
> >> > >                 pixelComponents[byteIndex++] = (byte) ((p >> 8) & 
> >> > > 0xFF); // 
> >> > > green 
> >> > >                 pixelComponents[byteIndex++] = (byte) ((p) & 0xFF); 
> // 
> >> > > blue 
> >> > >                 pixelComponents[byteIndex++] = (byte) (p >> 24); 
> >> > >  //alpha 
> >> > >         } 
> >> > >         ByteBuffer pixelBuffer = ByteBuffer.wrap(pixelComponents); 
> >> > 
> >> > >         gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, 
> >> > > bitmap.getWidth(), bitmap.getHeight(), 0, GL10.GL_RGBA, 
> >> > > GL10.GL_UNSIGNED_BYTE, pixelBuffer); 
> >> > >         } 
> >> > 
> >> > >         public static int[] extractPixels(Bitmap src) { 
> >> > >                 int x = 0; 
> >> > >                 int y = 0; 
> >> > >                 int w = src.getWidth(); 
> >> > >                 int h = src.getHeight(); 
> >> > >                 int[] colors = new int[w * h]; 
> >> > >                 src.getPixels(colors, 0, w, x, y, w, h); 
> >> > >                 return colors; 
> >> > >         } 
> >> > 
> >> > > Since the above implementation does not use native code to convert 
> the 
> >> > > bitmap and since it also allocates the bitmap array twice besides 
> >> > > loading the bitmap (thus taking three times the memory space) its 
> not 
> >> > > quite optimal. It would be quite reasonable that Android supplied a 
> >> > > native method for doing this. Certainly the documenation for 
> GLUtils 
> >> > > should state that it loads apremultipliedalphatexture. Does anyone 
> >> > > know if there is a bugreport/feature request on this on Android? I 
> >> > > cant seem to find any mentioning of it in the issue 
> >> > > list:http://code.google.com/p/android/issues/list 
> >> > 
> >> > > Alex. 
> > 
> > -- 
> > You received this message because you are subscribed to the Google 
> > Groups "Android Developers" group. 
> > To post to this group, send email to [email protected] 
> > To unsubscribe from this group, send email to 
> > [email protected] 
> > For more options, visit this group at 
> > http://groups.google.com/group/android-developers?hl=en 
>
>
>
> -- 
> Romain Guy 
> Android framework engineer 
> [email protected] 
>

-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

Reply via email to