PDA

View Full Version : Image data to bitmap?!?



M109uk
12-04-2003, 07:55 PM
I am writting a games engine which uses its own image format, simply a TGA file with most of the extras taken out, just left with the size, data and some other information. But i would also like the ability to view this image in a Bitmap and use it with TOpenPictureDialog, but im not really sure where i can put the data in the bitmap?

I read the image data using Blockread and a PChar, can i use this with scanline or something?

Alimonster
14-04-2003, 01:28 PM
Yep, you can write to a bitmap's scanlines in order to copy over stuff. First, ensure three things:

1) Your bitmap's pixel format is set appropriately
2) You've set its width
3) You've set its height

You declare a type that's a pointer to an array of whatever for your pixel type, and then a pointer to it. The "whatever" in this case is the appropriate pixel type (e.g. Longword -> 32 bit, a packed record w/ rgb for 24 bit, word for 16 bit, etc.).

There's some sample code from another thread that you should hopefully be able to adapt: here you go (http://terraqueous.f2o.org/dgdev/viewtopic.php?t=279)

M109uk
15-04-2003, 05:24 PM
Hmm i don't seem to be getting anything :(

The format started as an uncompressed 24bit TGA file and then basic info passed to the new format.
I have my Texture class to load the texture from file and stores the data in a header.

the header looks like this:


TcxtHeader = Record
Height,Width,BPP: Cardinal;
Format: Word;
Data: PChar;
end;


and i try to get a bitmap from the data:


function TcxTexture.GetBitmap: TBitmap;
var
wScanLine, i: Integer;
begin
Result := TBitmap.Create;
Result.PixelFormat := pf24bit;
Result.Width := Header.Width;
Result.Height := Header.Height;
wScanLine := Header.Width*(Header.BPP div 8);
For i := 0 to Header.Height-1 Do
Begin
PPixelArray(Result.Scanline[i])^[0] := wScanLine;
End;
end;


Im guessing that i have made a really stupid mistake some where here :roll:.

I am also using a TImage to view the extracted TBitmap, by assigning it to the Picture property.

Alimonster
15-04-2003, 05:51 PM
You're reasonably close but there are a couple of problems with your code.

The process is as follows (note that this assumes your data is linear, i.e. no gaps between a row of pixels, so adjust it if it's not):

Set the width, height and bpp for your bitmap appropriately
Set the next-row-of-pixels-to-copy variable to the first source pixel
for every scanline, copy width * (bpp div 8 ) bytes from your source tga to your destination bitmap then increase the offset by width bytes.

Remember that the scanlines for a bitmap are just pointers -- you have to write to the memory at that address, and you have to ensure that you're writing enough info to fill up a row of pixels each time. Something like this (untested but compiles):

function TcxTexture.GetBitmap: TBitmap;
var
wScanLine, i: Integer;
Offset: PChar; // next row of pixels to copy from source
begin
Result := TBitmap.Create;
Result.PixelFormat := pf24bit;
Result.Width := Header.Width;
Result.Height := Header.Height;
wScanLine := Header.Width*(Header.BPP div 8);

// start with the first pixel of the image
Offset := Header.Data;

for i := 0 to Header.Height-1 Do
begin
// copy over a row worth of pixels at a time
Move(Offset^, PPixelArray(Result.Scanline[ i ])^[0], wScanline);

// move a row of pixels further for next time
Inc(offset, wScanline);
end;
end;

Notice that I'm using Move here -- this will copy n bytes of data from one place to another (in this case, copying over your image data onto the newly created bitmap).

As a side note, it's better style to create and destroy classes (or allocate memory) in the same scope. The above function creates a bitmap, but the caller must free it. This is pretty bad news in terms of exception handling and call lead to jumping through hoops if you want to be safe. I'd recommend passing in a bitmap and having the GetBitmap function thing just using it, without allocating things for itself. This not only clears up the code (it's much easier to track where objects are created and freed) but it gives more intuitive exception handling. E.g.

procedure TcxTexture.GetBitmap(UseMe: TBitmap);
var
// vars here
begin
Bmp.PixelFormat := pf24Bit;
Bmp.Width := Header.Width;
//etc
end;

// and later on in your code

procedure TcxTexture.Whatever;
var
Bmp: TBitmap;
begin
Bmp := TBitmap.Create;
try
GetBitmap(Bmp);
// do stuff
finally
Bmp.Free;
end;
end;

M109uk
15-04-2003, 06:31 PM
Hmm im still not getting anything back, im sure im doing something stupid. Im thinking when im loading the texture at the beginning im not copying the data correctly?!? im not sure.

heres a copy of the project and files, could you possibly have a look to see where im going wrong :D.

http://www.biocoders.org/files/Quick.zip

its about 332kb

The TcxTexture is a class which im using in my Games engine, I just need this bit so i can view the texture in the editors im building.

Ultra
16-04-2003, 02:33 PM
I belive that you can't save/load a PChar so you should try to change
TcxtHeader = Record
Height,Width,BPP: Cardinal;
Format: Word;
Data: PChar;
end;
to
TcxtHeader = Record
Height,Width,BPP: Cardinal;
Format: Word;
Data: String;
end;

M109uk
16-04-2003, 03:41 PM
I use PChar to store the data in the loading procedure of the texture, TcxtHeader is just being used to store the data incase i need it, like in the GetBitmap function.

I know that the texture is being saved and loaded correctly in the class because it works fine in OpenGL.

But im not sure if i am using it properly.. When the texture is loaded at the end when i set the TcxtHeader information i just use

Header.Data := Data;

Them both being PChar's.

When i view the texture using TImage all i get is a plain white rectangle the size of the texture, but with well no texture :?

Turbo_Pascal
16-04-2003, 06:55 PM
[quote="M109uk"]I use PChar to store the data in the loading procedure
But im not sure if i am using it properly.. When the texture is loaded at the end when i set the TcxtHeader information i just use

Header.Data := Data;

Them both being PChar's.

Nope, is not correct, Pchar assigment is used as null terminated string, mean that it will copy the "string" pointed until any byte zero is found.

use Move command for copy the whole block data from one pointer to another, you have to tell your data size.


tp.

Alimonster
18-04-2003, 09:32 AM
I've finally got around to taking a look at your code. Some things I spotted that may cause problems:

First of all, bpp in my example stood for "bits per pixel", hence you needed to divide by 8. However, your code uses "bytes per pixel", so you don't want to be dividing by 8 in the GetBitmap function.

Secondly, and most importantly, you're freeing the data pointer at the end of the LoadTexture function so the header's data pointer will then point to freed memory.

I'll take another look some time tonight or tomorrow. Sorry about the delay!

M109uk
18-04-2003, 02:58 PM
First of all, bpp in my example stood for "bits per pixel", hence you needed to divide by 8. However, your code uses "bytes per pixel", so you don't want to be dividing by 8 in the GetBitmap function.


Yeah i thought that might of been a problem, i tried to use the same math i did when writing the image: Width*Height*BPP in the GetBitmap function, but that just came up with errors :(



Secondly, and most importantly, you're freeing the data pointer at the end of the LoadTexture function so the header's data pointer will then point to freed memory.


:oops:, i knew it was something stupid :roll:



I'll take another look some time tonight or tomorrow. Sorry about the delay!


Thanks that would be great :)

M109uk
24-04-2003, 11:04 AM
Secondly, and most importantly, you're freeing the data pointer at the end of the LoadTexture function so the header's data pointer will then point to freed memory.


, i knew it was something stupid :oops:


I tried to do that but nothing has changed, i still get a blank image :(