Images & Pixmaps - simple explanation please

BlitzMax Forums/BlitzMax Programming/Images & Pixmaps - simple explanation please

mulawa1(Posted 2009) [#1]
Hi,

I still haven't a clear picture (pun intended) in my mind of the difference between an image and a pixmap and would welcome a simple explanation.

My latest encounter involved trying to get a masked sector image from a larger image. My mask is a black sector on a white background. Is this code the best way to do this?

Graphics 800,600
img:TImage=LoadImage("img.bmp")
mask:TImage=LoadImage("mask.bmp")
DrawImage img,0,0
DrawImage mask,0,0
px:TPixmap=GrabPixmap(0,0,128,128)
px=MaskPixmap(px,255,255,255)
img1:TImage=LoadImage(px) 
DrawImage img1,200,200
Flip
WaitKey
End


Thanks ... Peter


degac(Posted 2009) [#2]
(I hope this is the correct interpretation)

Pixmap is a 'representation' of a bitmap in to main RAM
Image is a 'representation' of the same bitmap into the VIDEO RAM (on the gfx board).
You can have a Pixmap, but NO image, until you 'load it into the graphic card'.


plash(Posted 2009) [#3]
Pixmaps can be accessed on the pixel-level, images can't really (but you can access the underlaying pixmaps for an image and change it that way).

Are you trying to convert the background of 'img.bmp' to the background of 'mask.bmp'?
Images and a working/not working code example help vastly!


ImaginaryHuman(Posted 2009) [#4]
One of the main reasons we have pixmaps is because a graphics API like OpenGl or DirectX, coupled with a Graphics Processing Unit (GPU), typically can only access data stored in special on-board `graphics memory`, which is not usually the same as system RAM (except when integrated like some Intel etc). The graphics ram is considered separate memory from main memory and so the graphics card really can only work on data stored within the confines of graphics ram.

The graphics ram is then connected to the main computer via a graphics `bus` which ferries data back and forth to main memory. You typically can't load `files`, like a PNG image, into graphics ram. Where the CPU needs to get involved and if the graphics API doesn't support it, stuff has to be loaded into main memory first before loading into graphics ram. So you need somewhere to store that data - which is what we need `bitmaps` for, ie pixmaps/pixel maps. Once you've either loaded or created a pixmap it isn't available to the graphics processing unit. It can't work with it. It has to be sent over the graphics bus and turned into an `internal` representation of the image, as a `texture`, which Blitz refers to as Images. The format of the texture might be different to the format of the pixmap data.

Once you have the pixmap copied to graphics ram, the pixmap could be ditched, but Max2D keeps it around to make it easier for you to edit it. When you `lock` an image you just edit the pixmap in main memory and re-upload it, you don't really `download` it at all. Also once the pixmap has been transferred into a texture in graphics ram, the GPU and graphics API can now `use it` to draw pixels on the screen. The CPU could technically also draw pixels on the screen, and can even access video ram directly, and can even load data directly from disk into graphics ram, but those are more advanced features not made easily available in Blitz.

If you want to save an `Image` to disk, you need to either convert it into a pixmap first and save the pixmap, or have kept the pixmap that the image was created from originally.


xMicky(Posted 2009) [#5]
Seeing it from the Oop -features of Blitz Max: Pixmaps are simply the separately defined raw pixel data of Images.

Therefore: Type TImage Extends TData
has a property: Field pixmaps:TPixmap[]
for the Images frames.

You might want to have a look of:
brl.mod/max2D.mod/image.bmx
and:
brl.mod/pixmap.mod/pixmap.bmx
to see the distributed functionalities given through methods/fields of TImage/TPixmap.

TImage is on Top of objects definitions hierarchy for an easy display/use in program, while pixmaps below are dealing with pixel formats, access to single pixels, saving/loading from stream a.o.


mulawa1(Posted 2009) [#6]
Sorry for the slow response - I checked back during the first 24 hours and assumed no-one was going to reply.

I suspected the difference was to do with memory location - that still doesn't give me a clear idea of when I should use pixmaps and when I should use images. I tend to survive empirically - when I can't achieve what I want with one I use the other.

Plash, the code fragment works fine. I'm simply building a kaleidoscope effect by transforming my sector image 7 times and laying them one on top of the other. End result looks like this:



I continuously rotate the underlying image so the kaleidoscope image is constantly changing.

IH, thx for your lengthy reply - makes a lot of sense but as I said it doesn't translate into how I should go about working with images.

My code fragment seems very roundabout which is why I asked if it was the best way to do what I was trying to do.

I have used BB since Day One but have only recently moved to BlitzMax hence my newbie questions about pixmaps. I must say that BlitzMax is terrific to use and is allowing me to do so many things so much better than BB. And being able to program for the Mac is a great bonus!

Many thanks for your time.

Peter


zambani(Posted 2009) [#7]
This is the way I think of the it when it comes to pictures.
Disk to Pixmap to Image to Screen. Pixmaps gives you the most flexibility as for manipulating the picture down to the pixel level. Once the pixmap "becomes" an image you loose the flexibility to edit it at the pixel level. From this point on you must deal with the picture as a whole. In many situations you're just placing pictures unmodified on to the screen. In this case there's no need for pixmaps

I always use images unless I have to work with the individual pixels.

Hope this helps


ImaginaryHuman(Posted 2009) [#8]
You want to use images as much as possible because that means you have a texture in graphics ram which the gpu can use to draw the pixels - much much faster and hardware accelerated, going straight from graphics ram into the backbuffer (also in graphics ram). Anything you try to do regarding drawing using a pixmap has to be transferred over the bus between graphics ram and main memory which is relatively slow. Pixmaps can be 10 to 100 times slower to draw than images. However like people have said, when you want to edit the image you typically have to use pixmaps - but try to convert them back to images before drawing with them. Think of the image as a `cached` image, it's much faster to draw it from cached memory.


DavidDC(Posted 2009) [#9]
How are your frame rates for the above kaleidoscope? Any chance of some demo code? Looks interesting.


mulawa1(Posted 2009) [#10]
Excellent! Many thanks! You've provided a good platform of info to build on.

Here's the mask image - it's not anti-aliased - in fact it's just 2 colour.



And here's a working demo - you'll need your own 1.png (800x600).

Strict
Graphics 800,600
Global gimg:TImage=LoadImage("1.png");MidHandleImage(gimg)
Global gmask:Timage=LoadImage("mask.png")
Global gr=ImageWidth(gmask),gr2=gr/2
Global grot=0
Global gms=MilliSecs()

Repeat
	display()
	Flip
Until AppTerminate() Or KeyHit(KEY_ESCAPE)
End

Function display()
	Local sw=GraphicsWidth()
	Local sh=GraphicsHeight()
	Local mx,my,px:TPixmap,bl,pce:TImage
	mx=MouseX();my=MouseY()
	If mx<gr Then MoveMouse(gr,my);mx=gr
	If my<gr Then MoveMouse(mx,gr);my=gr
	If mx>sw-gr Then MoveMouse(sw-gr,my);mx=sw-gr
	If my>sh-gr Then MoveMouse(mx,sh-gr);my=sh-gr
	SetRotation grot
	DrawImage gimg,sw/2,sh/2
	SetRotation 0
	DrawImage gmask,mx-gr,my-gr
	px:TPixmap=GrabPixmap(mx-gr,my-gr,gr,gr)
	px=MaskPixmap(px,255,255,255)
	pce=LoadImage(px);MidHandleImage(pce)
	SetClsColor 0,0,0;Cls
	DrawImage pce,mx-gr2,my-gr2
	SetTransform 0,-1,1;DrawImage pce,mx+gr-gr2,my-gr2
	SetTransform 0,1,-1;DrawImage pce,mx-gr2,my+gr-gr2
	SetTransform 0,-1,-1;DrawImage pce,mx+gr-gr2,my+gr-gr2
	SetTransform 90,1,1;DrawImage pce,mx+gr-gr2,my-gr2
	SetTransform 90,-1,1;DrawImage pce,mx+gr-gr2,my+gr-gr2
	SetTransform -90,1,1;DrawImage pce,mx-gr2,my+gr-gr2
	SetTransform -90,-1,1;DrawImage pce,mx-gr2,my-gr2
	SetTransform 0,1,1
	If MilliSecs()-gms>50 Then grot=grot+1;gms=MilliSecs();If grot=360 Then grot=0
End Function

Strictly speaking the image should be rotating about the mouse position but that did slow it down too much! Probably cos my maths was too involved!

I never bother with frame rates since most of my work involves fairly simply apps.

If you want to see the whole program in action, you can check it out here:

http://mulawa.net/easy/

Thanks again ... Peter


DavidDC(Posted 2009) [#11]
Hey Peter thanks so much for posting this!

The frame rate is 252 in the above sample on my 2 year old iMac running XP btw. Faster than I expected. What a neat piece of code. Makes me fall in love with Blitzmax all over again seeing such a small piece of code do all that!


plash(Posted 2009) [#12]
Thats a really cool effect!


mulawa1(Posted 2009) [#13]
Great to give something back in return for the support I've received over the years from this forum.

This thread has certainly answered my original question but I'd like to go a little further (just out of curiosity) by asking a further question.

Am I right in assuming that SetRotation, SetBlend, SetColor, SetAlpha, etc are handled by the GPU and, in cases where this is not possible (eg on an old graphics card), this is emulated in software and hence is handled by the CPU?

Peter


TomToad(Posted 2009) [#14]
I made something a while ago that's similar here.
http://www.blitzbasic.com/codearcs/codearcs.php?code=2250

Difference in mine is that I go through pixel by pixel each frame and copy the pixels onto an image that will be displayed later.
Also, since I turn the "mirrors" instead of the image, some artifacting shows up when at certain angles and using certain colors.


Mr. Write Errors Man(Posted 2009) [#15]
mulawa1,

There is no fallback software emulation. If the graphics card can't handle it, you will get unsatisfactory results or a full crash.


DavidDC(Posted 2009) [#16]
Also, since I turn the "mirrors" instead of the image, some artifacting shows up when at certain angles and using certain colors

I was pleasantly surprised this method didn't produce artifacts on triangle overlay as well actually.

I wrote a screensaver around 2000 that used a slightly different approach again. A dynamic (plasma) texture was applied to a bunch of triangles. Rotate the tris and flip the texture mapping on every 2nd tri and you are home. Removes the need for a mask - but this was done in C/C++ and direct x. I'm sure it would be possible with one of the blitmax 3d mods though. See Angelicus on my site (sig) if curious.


mulawa1(Posted 2009) [#17]
Further to my sample code - I have come across an old system where the MaskPixmap command seems to have failed in that the final picture has the white of the mask showing - very unattractive!

This forum mentions problems with MaskPixmap a long time ago. I am at a loss to understand how this command could fail on some PCs cos if I understand all that I have been told above, this command is carried out in CPU and hence should be unaffected by "old" graphics cards.

Anyway I'm trying this:

replacing
px=MaskPixmap(px,255,255,255)
pce=LoadImage(px);MidHandleImage(pce)

with
SetMaskColor 255,255,255
pce=LoadImage(px,MASKEDIMAGE);MidHandleImage(pce)
SetMaskColor 0,0,0


It will be some time before I can test this on the problem system - I'll let you know when I do.

Peter


Mr. Write Errors Man(Posted 2009) [#18]
Programs that use graphics do not necessarily work at all on older computers. You may get black screen or they crash. Right at the Graphics command.


mulawa1(Posted 2009) [#19]
Mr Errors Writer Man,

I understood your earlier post and accept it but it is my understanding that pixmaps reside in CPU memory and therefore their manipulation is purely a software operation and should not be affected by the age of the computer. The fact that I have ended up with the white showing clearly indicates that the MaskPixmap command did not work.

I can't wait to try my workaround but as I said that will be some time before I visit that old system again.

Peter


TomToad(Posted 2009) [#20]
What happens is when you try and draw the image and mask initially, some video cards will try and smooth out the hard edges, so along your white mask will be a row of pixels that are not quite white. When you grab the image into a pixmap, those not quite white pixels go along with it.
Then when you use MaskPixmap(), the not quite white pixels remain.
First thing to try and remedy the problem would be to make sure that the person has their video card's driver setting so anti-aliasing is program controlled instead of defaulting to 2x, 4x, etc...


mulawa1(Posted 2009) [#21]
Thanks for your thoughts TomToad but the entire white mask remains - not just a fringe.

Peter


DavidDC(Posted 2009) [#22]
It just occurred to me that the masked image problem you mentioned could be something to do with a weird argb pixel format of the graphcs card in question.

Might be 24 bit or 15 bit? Just a wild 2am guess :-)

[edit] Wilder 3am guess... perhaps the app is assuming a default renderstate that isn't there? Maybe you need to explicitly switch on alpha blending?


mulawa1(Posted 2009) [#23]
Thanks for your continuing thoughts on this issue David.

Unfortunately I don't have ready access to the problem system and the owner isn't even on the Internet so it's not easy for me to "play around".

I still haven't had a chance to try my workaround!

Peter


_Skully(Posted 2009) [#24]
I understand the purpose of the pixelmap now... but.. why do images have the ability to have multiple pixelmaps? When I request an image pixelmap its

Image:TImage=CreateImage(32,32)
pxm:TPixMap=Image.PixMap[0]


Yet, when you lock image it just simply returns a Pixel Map (I'm assuming 0)

Image:TImage=CreateImage(32,32)
pxm:TPixMap=LockImage(Image)


Are the multiple pixelmap layers for textures?


Pete Rigz(Posted 2009) [#25]
It's for images with more then one frame of animation. When you lock an image you can specify which frame you want to get, lockimage(Image, Frame).


_Skully(Posted 2009) [#26]
oh... that was... kinda obvious LOL... Waaaaay over-thought that...


mulawa1(Posted 2009) [#27]
Never did get to test my workaround on the problem system but today I tried this code on my "new" eMac and found the same problem - here's what I get:



So I'm back to square one.

Maybe one of our Mac Blitzers can check this out for me.

Peter