Recent

Author Topic: Image manipulation in Lazarus  (Read 35514 times)

Leledumbo

  • Hero Member
  • *****
  • Posts: 8310
  • Programming + Glam Metal + Tae Kwon Do = Me
Image manipulation in Lazarus
« on: January 07, 2008, 01:49:27 pm »
Some questions, How can I ...
1. split an image file?
2. flip/rotate an image?
3. change colored image to monochrome?

All those functions would be very useful, esp. for game development. I see that none of those are implemented by LCL currently.

Oh, yeah one more. I've seen many posts about this, but it's still annoying. Is there anyway to avoid flickering when drawing a 2D image instead of creating a custom control that draws itself?

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3541
RE: Image manipulation in Lazarus
« Reply #1 on: January 07, 2008, 02:56:47 pm »
If the operations are static (i.e. you load an image file, do the operation, and save back to disk), I would use PascalMagick:

http://wiki.lazarus.freepascal.org/PascalMagick

If you want to show the result of the operations on the screen at the same time they are made, I think you should try using another imaging library. Graphics32 and OpenGL can be used inside a normal Lazarus Form. For SDL I think you will need to write the entire app in SDL.

Some screenshots of Graphics32 for Lazarus:

http://magnifier.sourceforge.net/photos/screenshots/

http://graphics32.org/wiki/

One can download the current source with examples here:

http://magnifier.sourceforge.net/tmp/GR32.zip

But it's mostly tested on Mac OS X. It may also work on Windows and no Linux implementation is present.

OpenGL information:

http://wiki.lazarus.freepascal.org/OpenGL

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3541
Re: Image manipulation in Lazarus
« Reply #2 on: January 07, 2008, 02:58:11 pm »
Quote from: "Leledumbo"
Oh, yeah one more. I've seen many posts about this, but it's still annoying. Is there anyway to avoid flickering when drawing a 2D image instead of creating a custom control that draws itself?


What is the problem in creating a custom control?

Leledumbo

  • Hero Member
  • *****
  • Posts: 8310
  • Programming + Glam Metal + Tae Kwon Do = Me
RE: Re: Image manipulation in Lazarus
« Reply #3 on: January 08, 2008, 06:50:14 am »
For 3D, I've used OpenGL. I works nice and I like it. But what I want is to do it all using LCL (or FCL). But after seeing Graphics32, I think that would suit my needs. Thanks for that.
Quote
What is the problem in creating a custom control?

The problem is, if it can be built that way by default, why should we create it ourselves?

Leledumbo

  • Hero Member
  • *****
  • Posts: 8310
  • Programming + Glam Metal + Tae Kwon Do = Me
RE: Re: Image manipulation in Lazarus
« Reply #4 on: January 08, 2008, 08:00:28 am »
Just as I thought that Graphics32 won't be easy to compile.
Code: [Select]

Hint: Start of reading config file H:\fpc\bin\i386-win32\fpc.cfg
Hint: End of reading config file H:\fpc\bin\i386-win32\fpc.cfg
Free Pascal Compiler version 2.2.0 [2007/10/04] for i386
Copyright (c) 1993-2007 by Florian Klaempfl
Target OS: Win32 for i386
Compiling GR32_L.pas
Compiling D:\GR32\GR32.pas
D:\GR32\GR32.pas(165,16) Hint: Type "PByteArray" redefinition
D:\GR32\GR32.pas(166,16) Hint: Type "TByteArray" redefinition
D:\GR32\GR32.pas(170,16) Hint: Type "PWordArray" redefinition
D:\GR32\GR32.pas(171,16) Hint: Type "TWordArray" redefinition
D:\GR32\GR32.pas(175,19) Hint: Type "PIntegerArray" redefinition
D:\GR32\GR32.pas(176,19) Hint: Type "TIntegerArray" redefinition
D:\GR32\GR32.pas(204,12) Hint: Type "PPoint" redefinition
D:\GR32\GR32.pas(1135,26) Hint: use DIV instead to get an integer result
D:\GR32\GR32.pas(1136,28) Hint: use DIV instead to get an integer result
D:\GR32\GR32.pas(1137,27) Hint: use DIV instead to get an integer result
D:\GR32\GR32.pas(1660,43) Hint: use DIV instead to get an integer result
D:\GR32\GR32.pas(1746,29) Error: Illegal type conversion: "<record type>" to "DWord"
D:\GR32\GR32.pas(1755,37) Error: Illegal type conversion: "<record type>" to "DWord"
D:\GR32\GR32.pas(1766,36) Error: Illegal type conversion: "<record type>" to "DWord"
D:\GR32\GR32.pas(1775,36) Error: Illegal type conversion: "<record type>" to "DWord"
D:\GR32\GR32.pas(3444,18) Hint: use DIV instead to get an integer result
D:\GR32\GR32.pas(3513,20) Hint: use DIV instead to get an integer result
D:\GR32\GR32.pas(3555,22) Hint: use DIV instead to get an integer result
D:\GR32\GR32.pas(3556,22) Hint: use DIV instead to get an integer result

D:\GR32\GR32.pas(3602,45) Hint: use DIV instead to get an integer result
D:\GR32\GR32.pas(3602,64) Hint: use DIV instead to get an integer result
D:\GR32\GR32.pas(3620,45) Hint: use DIV instead to get an integer result
D:\GR32\GR32.pas(3620,64) Hint: use DIV instead to get an integer result
D:\GR32\GR32.pas(3632,22) Hint: use DIV instead to get an integer result
D:\GR32\GR32.pas(3632,53) Hint: use DIV instead to get an integer result
D:\GR32\GR32.pas(3650,45) Hint: use DIV instead to get an integer result
D:\GR32\GR32.pas(3650,64) Hint: use DIV instead to get an integer result
D:\GR32\GR32.pas(4369,28) Hint: Local variable "w" does not seem to be initialized
D:\GR32\GR32.pas(4370,28) Hint: Local variable "h" does not seem to be initialized
D:\GR32\GR32.pas(4572,5) Hint: Local variable "Buffer" does not seem to be initialized
D:\GR32\GR32.pas(5453,8) Warning: Symbol "Handle" is deprecated
D:\GR32\GR32.pas(5710,43) Hint: Local variable "Height" does not seem to be initialized
D:\GR32\GR32.pas(5710,43) Hint: Local variable "Width" does not seem to be initialized
D:\GR32\GR32.pas(5872) Fatal: There were 4 errors compiling module, stopping

The errors seem logical since TCriticalSection is defined as PtrUInt, while
Flock is of type TRTLCriticalSection, which is a record. Any solution to this?

pch

  • Jr. Member
  • **
  • Posts: 51
    • http://ap-i.net
RE: Re: Image manipulation in Lazarus
« Reply #5 on: January 08, 2008, 09:18:58 am »
If your are interested in image manipulation I suggest you learn how to use TLazIntfImage as this is very powerful to implement any graphic algorithm.
To start look at the fadein example in the graphic wiki page, this show how to have efficient direct access to all the pixel with 16 bit depth.
After that programming split, rotation or change to monochrome is really straightforward.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8310
  • Programming + Glam Metal + Tae Kwon Do = Me
RE: Re: Image manipulation in Lazarus
« Reply #6 on: January 08, 2008, 09:42:25 am »
Actually, I'm not. I just need it to make games. For example, instead of having 16 separated pictures for a sprite, its better to put them in 1 picture which is splitted into an 4x4 array.

theo

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1891
RE: Re: Image manipulation in Lazarus
« Reply #7 on: January 08, 2008, 11:20:05 am »
You can split the image using CopyRect.
Pixel Manipulation like Flip or Monochrome can be done like in this example:
http://wiki.lazarus.freepascal.org/Developing_with_Graphics#A_fading_example

bee

  • Sr. Member
  • ****
  • Posts: 393
RE: Re: Image manipulation in Lazarus
« Reply #8 on: January 08, 2008, 12:05:32 pm »
SDL anyone?
-Bee-

A long time pascal lover.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8310
  • Programming + Glam Metal + Tae Kwon Do = Me
RE: Re: Image manipulation in Lazarus
« Reply #9 on: January 11, 2008, 04:46:55 am »
I finally managed to compile Graphics32 by commenting all lines having this code:
Code: [Select]

InitializeCriticalSection(TCriticalSection(FLock));

and the same code that finalize it (I forgot the function name).
But I feel like kinda afraid, what's this function called for? moreover, what's critical section? Is it important?

Quote
You can split the image using CopyRect.

Any example?

theo

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1891
Re: RE: Re: Image manipulation in Lazarus
« Reply #10 on: January 11, 2008, 12:06:58 pm »
Quote from: "Leledumbo"

Any example?


In this example, the source image contains 8 sprites in a row, each 23*23 px.

Code: [Select]
procedure DrawImgNum(SrcCanvas,DestCanvas:TCanvas;Number:integer);
const
SprW=23;
SprH=23;
var SrcR, DestR:TRect;
begin
 DestR:=Rect(0,0,SprW,SprH);
 SrcR:=Rect(Number*SprW,0,(Number*SprW)+SprW,SprH);
 DestCanvas.CopyRect(DestR,SrcCanvas,SrcR);
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
  DrawImgNum(Image1.Picture.Bitmap.Canvas,Canvas,Number);
  If Number<8 then Inc(Number) else Number:=0;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Repaint;
end;    

Leledumbo

  • Hero Member
  • *****
  • Posts: 8310
  • Programming + Glam Metal + Tae Kwon Do = Me
RE: Re: RE: Re: Image manipulation in Lazarus
« Reply #11 on: January 13, 2008, 07:04:53 am »
For Theo:
Thanx, I'll try.

For pch:
I've tried using TLazInfImage, call GetRawImage, then use ExtractRect of returned TRawImage. Still I got a blank picture. Have you ever used this?

pch

  • Jr. Member
  • **
  • Posts: 51
    • http://ap-i.net
RE: Re: RE: Re: Image manipulation in Lazarus
« Reply #12 on: January 14, 2008, 10:37:17 am »
No, I never have to use the rawimage, TLazInfImage.colors give all what I need with good performance.

But to just split an image in piece I also use copyrect as describe by Theo.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8310
  • Programming + Glam Metal + Tae Kwon Do = Me
RE: Re: RE: Re: Image manipulation in Lazarus
« Reply #13 on: January 14, 2008, 11:15:33 am »
For Theo:
I've tested your code and it works! Thanks. My previous approach was to use copy rect on every pictures canvas, but it failed. More or less the code was:
Code: [Select]

var
  Sprites: array [0..3,0..3] of TPicture;

procedure TMainForm.FormCreate(Sender: TObject);
var
  i,j: Byte;
  TempPic: TPicture;
begin
  TempPic:=TPicture.Create;
  TempPic.LoadFromFile('plane.png'); // This picture is a 4x4 sprite with size of 65x65 each.
  for i:=0 to 3 do
    for j:=0 to 3 do begin
      Sprites[i,j]:=TPicture.Create;
      Sprites[i,j].Bitmap.Canvas.CopyRect(
        Rect(0,0,65,65),
        TempPic.Bitmap.Canvas,
        Rect(i*65,j*65,i*65+65,j*65+65)
      );
    end;
    TempPic.Free;
end;

procedure TMainForm.GameTimerTimer(Sender: TObject);
begin
  // x and y are sprite's position
  // SpriteDir is sprite's direction
  // SpriteLoop is the loop of sprite's direction
  Canvas.Draw(x,y,Sprites[SpriteDir,SpriteLoop].Graphic);
end;

And all I've got was a blank form. Btw, using CopyRect makes the picture loses its transparency. Setting Transparent to true doesn't give any effect. How can I solve this?

For pch:
Yeah, I think Colors property is the core of TLazIntfImage. I know I can also split the image using it, by placing it pixel by pixel, but it kinda waste of time and I'm sure there's a faster way to do it.

theo

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1891
RE: Re: RE: Re: Image manipulation in Lazarus
« Reply #14 on: January 14, 2008, 11:40:49 am »
I'd say you forgot to set width and height of the bitmap.
You can use my function DrawImgNum to copy the part to a TBitmap.Canvas.
I'd take a TBitmap instead of TPicture and set the dimensions after creation.
Transparency is tricky. As described here http://wiki.lazarus.freepascal.org/Developing_with_Graphics#Drawing_color_transparent_bitmaps
change in my example TForm1.Paint() to

Code: [Select]
procedure TForm1.FormPaint(Sender: TObject);
var bmp:TBitmap;
memstream:TMemoryStream;
begin
  Bmp:=TBitmap.create;
  Bmp.width:=23;
  Bmp.Height:=23;
  DrawImgNum(Image1.Picture.Bitmap.Canvas,Bmp.Canvas,Number);

  memstream := TMemoryStream.create;
  try
    bmp.SaveToStream(memstream);
    memstream.position := 0;
    bmp.LoadFromStream(memstream);
  finally
    memstream.free;
  end;
  Bmp.Transparent:=True;
  Bmp.TransparentColor:=Bmp.Canvas.Pixels[1,1];
 
  Canvas.Draw(0,0,Bmp);
  Bmp.free;
  If Number<8 then Inc(Number) else Number:=0;
end;    

Of course you can do this also once at startup with your sprites array.

 

TinyPortal © 2005-2018