Results 1 to 7 of 7

Thread: Saving graphics to non-standard files

  1. #1

    Saving graphics to non-standard files

    I am attempting to save a bitmap image to a file that only my program can understand (this is more than just changing the file extension). I have tried using blockread/blockwrite but when I tried to load the image back to another bitmap, the bitmap is just blank. The code goes something like below.

    procedure SavePic(FileName: String);
    var
    OldBitmap: TBitmap;
    Data: File;
    begin
    OldBitmap:=TBitmap.Create;
    OldBitmap.Picture.LoadFromFile('C:\MyPicture.Bmp') ;
    AssignFile(Data,'MyPicture.Dat');
    Rewrite(Data,Sizeof(Bitmap);
    BlockWrite(Data,Bitmap,1);
    OldBitmap.Free;
    end;

    procedure LoadPic(FileName: String);
    var
    NewBitmap: TBitmap;
    Data: File;
    begin
    NewBitmap:=TBitmap.Create;
    NewBitmap.Picture.LoadFromFile('C:\MyPicture.Bmp') ;
    AssignFile(Data,'MyPicture.Dat');
    Reset(Data,Sizeof(Bitmap);
    BlockRead(Data,Bitmap,1);
    Canvas.Draw(0,0,NewBitmap);
    NewBitmap.Free;
    end;

    But it won't work, any suggestions or alternative ways I can save the pic without anyone being able to edit the pictures.
    Isometric game development blog http://isoenginedev.blogspot.com/

  2. #2

    Saving graphics to non-standard files

    I didn't look at your example very long but perhaps you'd be better saving the pic using a for loop for the y axis, BlockWriting each scanline in turn (because the padding might screw up things, not sure).

    Check out this page on EFG's site: http://www.efg2.com/Lab/ImageProcessing/CryptImage.htm. If you used that then you could apply it once and use SaveToFile/LoadFromFile without any more fuss. XOR encryption isn't the strongest in the world but it'll do for starters. You can always add different, better encryption to the whole file using a block cipher later on.
    "All paid jobs absorb and degrade the mind."
    <br />-- Aristotle

  3. #3

    Saving graphics to non-standard files

    I did spend a small amount of time trying to save a series of scanlines but the problem is that a scanline stores a pointer and not the actual data so if I tried to save a series of scanlines then I would be saving pointers which obviously wouldn't work, well, as I say I only spent a small amount of time trying that so maybe I was doing it poorly/wrong.
    Isometric game development blog http://isoenginedev.blogspot.com/

  4. #4

    Saving graphics to non-standard files

    Each scanline is a pointer to an array of pixels for that row, so you can save it by saving the first element of the scanline array. Here's some generalised code for saving 16, 24 and 32 bit bmps as RAW files (the usual disclaimers apply):


    [pascal][background=#FFFFFF][comment=#0000FF][normal=#000000]
    [number=#C00000][reserved=#000000][string=#00C000]type
    TRawHeader = record
    Width: Integer;
    Height: Integer;
    BitsPerPixel: Integer;
    end;
    PRawHeader = ^TRawHeader;

    TPixelArray = array[0..0] of Byte;
    PPixelArray = ^TPixelArray;

    const
    BitCount: array[TPixelFormat] of Integer = (-1, 1, 4, 8, 15, 16, 24, 32, -1);

    // the following doesn't handle pfCustom
    function PixelFormatToInt(PixFormat: TPixelFormat): Integer;
    var
    DC: HDC;
    begin
    if PixFormat = pfDevice then // get current screen bpp
    begin
    DC := GetDC(0);
    try
    // todo: confirm this is correct
    Result := GetDeviceCaps(DC, PLANES) * GetDeviceCaps(DC, BITSPIXEL);
    finally
    ReleaseDC(0, DC);
    end;
    end
    else
    if (PixFormat >= pf1Bit) and (PixFormat <= pf32Bit) then
    Result := BitCount[PixFormat]
    else
    raise Exception.Create('Unexpected pixel format in PixelFormatToInt');
    end;

    function IntToPixelFormat(BitsPerPixel: Integer): TPixelFormat;
    begin
    case BitsPerPixel of
    1 : Result := pf1Bit;
    4 : Result := pf4Bit;
    8 : Result := pf8Bit;
    15: Result := pf15Bit;
    16: Result := pf16Bit;
    24: Result := pf24Bit;
    32: Result := pf32Bit;
    else
    raise Exception.CreateFmt('Unexpected bits per pixel count in IntToPixelFormat: %d', [BitsPerPixel]);
    end;
    end;

    //
    // SaveAsRaw
    //
    // loads up the bitmap file given by InFile (e.g. "c:\windows\setup.bmp") and
    // saves it to a raw file in the given pixel format
    //
    procedure SaveAsRaw(const InFilename, OutFilename: String; PixFormat: TPixelFormat);
    var
    bmp: TBitmap;
    i: integer;
    F: File;
    ThisLine: PPixelArray;
    Header: TRawHeader;
    BitsPerPixel: Integer;
    WidthOfScanline: Integer;
    begin
    BitsPerPixel := PixelFormatToInt(PixFormat);

    if not (BitsPerPixel in [16, 24, 32]) then
    raise Exception.Create('SaveAsRaw only supports 16, 24 and 32 bpp at present');

    if not FileExists(InFilename) then
    raise Exception.Create('The file ' + InFilename + ' does not exist');

    bmp := TBitmap.Create;
    try
    bmp.LoadFromFile(InFilename);
    bmp.PixelFormat := PixFormat;

    Header.Width := Bmp.Width;
    Header.Height := Bmp.Height;
    Header.BitsPerPixel := BitsPerPixel;

    AssignFile(F, OutFilename);
    try
    Rewrite(F, 1);

    WidthOfScanline := Bmp.Width * (BitsPerPixel div ; // bytes per scanline

    BlockWrite(F, Header, SizeOf(TRawHeader));

    for i := 0 to Bmp.Height - 1 do
    begin
    ThisLine := Bmp.ScanLine[i];
    BlockWrite(F, ThisLine[0], WidthOfScanline);
    end;
    finally
    CloseFile(F);
    end;
    finally
    Bmp.free;
    end;
    end;

    //
    // LoadBitmapFromRAW
    //
    // Loads the RAW file given by filename into the supplied Bmp. The result
    // will be a DIB of the RAW's pixel format
    //
    procedure LoadBitmapFromRAW(const Filename: String; Bmp: TBitmap);
    var
    F: File;
    Header: TRawHeader;
    y: Integer;
    WidthOfScanline: Integer;
    begin
    if not FileExists(Filename) then
    raise Exception.Create('The file ' + Filename + ' does not exist!');

    AssignFile(F, Filename);
    try
    Reset(F, 1);

    BlockRead(F, Header, SizeOf(TRawHeader));

    if not (Header.BitsPerPixel in [16, 24, 32]) then
    raise Exception.Create('LoadBitmapFromRAW only supports 16, 24 or 32 bits per pixel at present');

    Bmp.PixelFormat := IntToPixelFormat(Header.BitsPerPixel);
    Bmp.Width := Header.Width;
    Bmp.Height := Header.Height;

    WidthOfScanline := Bmp.Width * (Header.BitsPerPixel div ; // bytes per scanline

    for y := 0 to Header.Height - 1 do
    begin
    BlockRead(F, PPixelArray(Bmp.Scanline[y])^[0], WidthOfScanline);
    end;
    finally
    CloseFile(F);
    end;
    end;

    ////////////////////////////////////////////////////////////////////////////////
    // QUICK TEST PROCEDURES
    ////////////////////////////////////////////////////////////////////////////////

    procedure TForm1.btnSaveClick(Sender: TObject);
    begin
    SaveAsRaw('c:\windows\setup.bmp', 'c:\test.raw', pf24Bit);
    end;

    procedure TForm1.btnLoadClick(Sender: TObject);
    var
    Bmp: TBitmap;
    begin
    Bmp := TBitmap.Create;
    try
    LoadBitmapFromRAW('c:\test.raw', Bmp);
    Canvas.Draw(0,0, Bmp);
    finally
    Bmp.Free;
    end;
    end;[/pascal]

    You'd definitely want to encrypt them though! See the EFG link; saving in binary format with BlockWrite gives you no additional protection. You can also have a look around Torry for encryption components - there are plenty free ones there.
    "All paid jobs absorb and degrade the mind."
    <br />-- Aristotle

  5. #5

    Saving graphics to non-standard files

    Cheers for that AliMonster, muchos gracias. Also, the encryption part is no biggy 'cause I just wanted to stop the lamen from loading them into Paint and messing them up.

    Thanks Again
    Isometric game development blog http://isoenginedev.blogspot.com/

  6. #6

    Saving graphics to non-standard files

    Ello!

    It works perfectly if you want to store one pic (with data) to one file, how about several pics with data to the same file? (An array...)

    Tried to make it work with some modifications to the code above but without success so far...
    What echoes in Eternity has been done in someone's life...

  7. #7

    Saving graphics to non-standard files

    This topic was mentioned in another thread somewhere (forgot which one), and I ended up writing a small article on it. That may be of some help to you.

    It's possible to skip the header or footer part in the packing tutorial entirely, though I wouldn't recommend it. You can pass in an array of TBitmap to the writing function and loop over every TBitmap to save each as a raw file. When reading in the files, you'd pass an index for the wanted raw. Reading it would be a case of reading each header, figuring out how many bytes the raw takes, and seeking to the next one for however many times are required. Each loop will take you to the next header if done correctly, which means that you will eventually reach the wanted raw file - but this will be a little annoying.

    I'd recommend writing out a header or footer though, since that will both make things easier and allow you more customisation (CRCs, per-file options, and so on).
    "All paid jobs absorb and degrade the mind."
    <br />-- Aristotle

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •