Bitmap alpha pixels odd behaviour [SOLVED]
-
On 26/08/2014 at 04:45, xxxxxxxx wrote:
User Information:
Cinema 4D Version: R14
Platform: Windows ;
Language(s) : C++ ;---------
Hi folks,I've been running some experiments with bitmaps and have come across some odd behaviour during a custom 'copy-pixel' loop. The following is for all intents and purposes a full function that is called via a button command press:
// Note: the MyStruct.Str_Bitmap used in the loop is // valid and does display in the picture viewer BaseBitmap *Copied_BMP = BaseBitmap::Alloc(); BaseBitmap *Alpha = NULL; Alpha = Copied_BMP->GetInternalChannel(); Alpha = Copied_BMP->AddChannel(TRUE,TRUE); Copied_BMP->Init(100,100,32,INITBITMAPFLAGS_0); LONG rr,gg,bb,aa; UWORD Ru,Gu,Bu,Au; for(int h = 0; h <= Copied_BMP->GetBh()-1;) { for(int w = 0; w <= Copied_BMP->GetBw()-1;) { MyStruct.Str_Bitmap->GetPixel(w,h,&Ru;,&Gu;,&Bu;); MyStruct.Str_Bitmap->GetAlphaPixel(MyStruct.Str_Bitmap_Alpha,w,h,&Au;); if(h == 23 && w == 14) { GePrint("In-loop 14x23 alpha pixel = " + LongToString(Au)); // correct } rr = Ru; gg = Gu; bb = Bu; aa = Au; if(h == 23 && w == 14) { GePrint("In-loop 14x23 alpha pixel = " + LongToString(aa)); // correct } Copied_BMP->SetPixel(w,h,rr,gg,bb); Copied_BMP->SetAlphaPixel(Alpha,w,h,aa); if(h == 22 && w == 13) // previous pixel test { Copied_BMP->GetAlphaPixel(Alpha,12,21,&Au;); aa = Au; GePrint("Post-set: 12x21 alpha LONG = " + LongToString(aa)); // wrong GePrint("Post-set: 12x21 alpha UWORD = " + LongToString(Au)); // wrong } else if(h == 23 && w == 14) { Copied_BMP->GetAlphaPixel(Alpha,14,23,&Au;); aa = Au; GePrint("Post-set: 14x23 alpha LONG = " + LongToString(aa)); // correct GePrint("Post-set: 14x23 alpha UWORD = " + LongToString(Au)); // correct } else if(h == 26 && w == 4) { Copied_BMP->GetAlphaPixel(Alpha,4,26,&Au;); aa = Au; GePrint("Post-set: 4x26 alpha LONG = " + LongToString(aa)); // correct GePrint("Post-set: 4x26 alpha UWORD = " + LongToString(Au)); // correct } w++; } h++; } // Now test pixel value at 14x23 again Copied_BMP->GetAlphaPixel(Alpha,14,23,&Au;); aa = Au; GePrint("Post-loop: 14x23 alpha LONG = " + LongToString(aa)); // wrong GePrint("Post-loop: 14x23 alpha UWORD = " + LongToString(Au)); // wrong //... I hope the above is all correct, from here the // code is mainly changing some pixel colours and // freeing bitmaps etc.
The issue is that the printed values after the for loop are all null, but the printed values inside the loop are correct (once the alpha value is set). The only time one of the prints in the loop doesn't print correct values is when trying to print a previous pixels value (so if h=10 and w=10, printing h=9 and w=9 values are also null). It's like the alpha data is erased as soon as the loops' skopes are left.
I've tested the above in both a dialog and object plugin, and both are running into the same problem. Sending either pictures to the picture viewer also seems to ignore the alpha data (including the original image!), but the colour data in both seems fine. Images are all in 32-bit form.
Is anyone with a beady eye able to spot what I'm doing wrong here? Or has anyone else come across this behaviour before?
WP.
P.s. just for note's sake, I'm aware of the bitmap->CopyTo() and bitmap->SetPixelCnt(), but I can't use these in the above because the routine will be expanded on and the operation will need to be on a per-pixel basis.
-
On 27/08/2014 at 10:03, xxxxxxxx wrote:
Here's an example of copying image data that also works outside of the for() loop for me:
//This code creates a bitmap copy of an image by manually copying the alpha and color values from an image line-by-line //The source image that contains an alpha channel Filename fn = GeGetC4DPath(C4D_PATH_DESKTOP) + "source.psd"; AutoAlloc<BaseBitmap> sourceImg; if(IMAGERESULT_OK != sourceImg->Init(fn)) return FALSE; BaseBitmap *sourceImg_Alpha = sourceImg->GetInternalChannel(); //Create a copy AutoAlloc<BaseBitmap> copied_BMP; if(!copied_BMP) return FALSE; copied_BMP->Init(sourceImg->GetBw(), sourceImg->GetBh(), 32); copied_BMP->AddChannel(TRUE, FALSE); BaseBitmap *copied_Alpha = copied_BMP->GetInternalChannel(); UWORD r,g,b,a; INT h,w; //Loop through the source image and copy the data to the other bitmap for(h=0; h <= copied_BMP->GetBh()-1; h++) { for(w=0; w <= copied_BMP->GetBw()-1; w++) { //Copy the alpha & color values from the source to the copy sourceImg->GetPixel(w,h,&r,&g,&b); sourceImg->GetAlphaPixel(sourceImg_Alpha,w,h,&a); copied_BMP->SetPixel(w,h,r,g,b); copied_BMP->SetAlphaPixel(copied_Alpha,w,h,a); //Check the alpha and color values in the copy at a specific location if(h == 100 && w == 100) { GePrint("Alpha = " + LongToString(a)); GePrint("color = " + LongToString(r) + " " + LongToString(g) + " " + LongToString(b)); } } } //Check the alpha and color values in the copy again...This time outside of the loop copied_BMP->GetPixel(100,100,&r,&g,&b); copied_BMP->GetAlphaPixel(copied_Alpha,100,100,&a); GePrint("Post-loop Alpha = " + LongToString(a)); GePrint("Post-loop color = " + LongToString(r) + " " + LongToString(g) + " " + LongToString(b));
-ScottA
-
On 27/08/2014 at 18:30, xxxxxxxx wrote:
Interesting, I found where the problem is Scott. I had the same problem with your code which was copied and pasted all except for the initialising of the bitmaps. And I found that it was the way I was setting up the bitmaps pre-loop that was causing the alpha channel to be wiped. So, instead of:
BaseBitmap *bmp = BaseBitmap::Alloc(); BaseBitmap alpha = NULL; alpha = bmp->GetInternalChannel(); alpha = bmp->AddChannel(TRUE,TRUE); bmp->Init(100,100,32,INITBITMAPFLAGS_0);
it appears we should be applying the alpha channels after the init'ing, like:
BaseBitmap *bmp = BaseBitmap::Alloc(); BaseBitmap alpha = NULL; bmp->Init(100,100,32,INITBITMAPFLAGS_0); alpha = bmp->GetInternalChannel(); alpha = bmp->AddChannel(TRUE,TRUE); // or BaseBitmap *bmp = BaseBitmap::Alloc(); bmp->Init(100,100,32,INITBITMAPFLAGS_0); BaseBitmap alpha = NULL; alpha = bmp->GetInternalChannel(); alpha = bmp->AddChannel(TRUE,TRUE);
If someone could confirm this outside of my programming that would be great, otherwise it might be one for the notes Scott! Thanks for your input as always,
WP.
-
On 27/08/2014 at 21:27, xxxxxxxx wrote:
Correct.
Allocated Bitmaps do not contain an Alpha channel by default. We have to add them by hand.
And we can't add them until we Init() the bitmap first.And it probably goes without saying that we cant "Get" the Alpha channel until after we add it.
-ScottA
-
On 28/08/2014 at 06:28, xxxxxxxx wrote:
Doh! I read over this a few times and couldn`t figure it out.. Will commit this to memory.