Lazarus
Miscellaneous => Suggestions => LCL => Topic started by: Leledumbo 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? (http://wiki.lazarus.freepascal.org/Developing_with_Graphics#Create_a_custom_control_which_draws_itself)
-
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
-
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? (http://wiki.lazarus.freepascal.org/Developing_with_Graphics#Create_a_custom_control_which_draws_itself)
What is the problem in creating a custom control?
-
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.
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?
-
Just as I thought that Graphics32 won't be easy to compile.
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?
-
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.
-
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.
-
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
-
SDL anyone?
-
I finally managed to compile Graphics32 by commenting all lines having this code:
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?
You can split the image using CopyRect.
Any example?
-
Any example?
In this example, the source image contains 8 sprites in a row, each 23*23 px.
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;
-
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?
-
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.
-
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:
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.
-
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
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.
-
I'm sorry, what are these:
bmp.SaveToStream(memstream);
memstream.position := 0;
bmp.LoadFromStream(memstream);
for?
-
http://wiki.lazarus.freepascal.org/Developing_with_Graphics#Drawing_color_transparent_bitmaps
Notice the memory operations performed with the TMemoryStream. They are necessary to ensure the correct loading of the image.
-
I've finally found the easiest way, Vampyre Imaging Library (http://imaginglib.sourceforge.net/)
This one really has everything needed to manipulate images! Thanks for everyone's response.
-
Hi, i'm trying to convert binary to image to store my data on image-hosting . So my example. Put Button1 on Form1. Copy click handler:
uses
Classes, SysUtils, LCLType, LResources, Forms, Controls, Graphics, Dialogs,
Buttons, FPImage, IntfGraphics,Math, StdCtrls,
graphtype,windows;
{...}
procedure TForm1.Button1Click(Sender: TObject);
var
IntfImg1, IntfImg2: TLazIntfImage;
var
ms:tmemorystream;
dwFileCont:dword;
lRawImage: TRawImage;
AUXw,AUXh:integer;
s_unique_num:string;
Frequency,Duration:dword;
begin
try
Ms := TMemoryStream.Create;
ms.LoadFromFile(ExtractFilePath(paramstr(0))+'project1.exe');
dwFileCont:=pdword(pdword(@ms)^+4)^;
AUXw :=trunc(sqrt(ms.Size/4));
AUXh:= AUXw;
if 4*AUXw*AUXh<ms.Size then AUXw:=AUXw+1;
if 4*AUXw*AUXh<ms.Size then AUXh:=AUXh+1;
lRawImage.Init;
lRawImage.Description.Init_BPP32_A8R8G8B8_BIO_TTB(AUXw,AUXh);
lRawImage.CreateData(True);
lRawImage.Data:=pbyte(dwFileCont);
IntfImg1 := TLazIntfImage.Create(0,0);
IntfImg1.SetRawImage(lRawImage);
//sleep(dword(lRawImage.data));
s_unique_num:=FormatDateTime('yymmddhhnnss', now);
IntfImg1.SaveToFile(ExtractFilePath(paramstr(0))+'testimage'+s_unique_num+'.png');
lRawImage.Init;
lRawImage.Description.Init_BPP32_A8R8G8B8_BIO_TTB(0,0);
lRawImage.CreateData(false);
IntfImg2:=TLazIntfImage.Create(0,0);
IntfImg2.SetRawImage(lRawImage);
IntfImg2.LoadFromFile(ExtractFilePath(paramstr(0))+'testimage'+s_unique_num+'.png');
IntfImg2.GETRawImage(lRawImage);
//sleep(dword(lRawImage.data));
finally
IntfImg1.Free;
IntfImg2.Free;
//Ms.Free; {stupid SIGSEG error}
(*
Duration:=$64;
Frequency:=$417;
windows.beep(Frequency,Duration);
Duration:=$64;
Frequency:=$455;
windows.beep(Frequency,Duration);
Duration:=$64;
Frequency:=$497;
windows.beep(Frequency,Duration);
*)
Duration:=$64;
Frequency:=$82D;
windows.beep(Frequency,Duration);
Duration:=$64;
Frequency:=$7B8;
windows.beep(Frequency,Duration);
Duration:=$64;
Frequency:=$741;
windows.beep(Frequency,Duration);
(*
Duration:=$1F4;
Frequency:=$28;
windows.beep(Frequency,Duration);
*)
end;
end;
But it does not save PNG-image with thansparency. Transparent-byte swithced to $FF everywhere:
http://img826.imageshack.us/img826/6610/38724552.png (I've uncommented second sleep and set breakpoint on "sleep" procedure).
-
Where is sources for these files:
"C:\lazarus\fpc\2.7.1\units\i386-win32\fcl-image\fpimage.o" "C:\lazarus\fpc\2.7.1\units\i386-win32\fcl-image\fpimage.ppu"
Lazarus' debugger can't set breakpoint on source code of fpimage unit. Why?
Also I cannot see blue dots by left side of source of fpimage unit. So this unit is not recompiled by running project. Why?
-
I solve my problem by adding special saving procedure:
procedure SaveToPng(const src_SaveToPng: TLazIntfImage; PngFileName: String);
var
png : TPortableNetworkGraphic;
begin
png := TPortableNetworkGraphic.Create;
try
png.Assign(src_SaveToPng);
png.SaveToFile(PngFileName);
finally
png.Free;
end;
end;
But why TLazIntfImage does not have this feature? Why I myst go roundabout road ?
-
Where is sources for these files
$(fpcdir)/packages/fcl-image, I think you can easily guess from the unit path.
Lazarus' debugger can't set breakpoint on source code of fpimage unit. Why?
The units are probably not compiled with debugging information, which I guess is the default if you don't supply additional compiler option when building the package. I assume you compile from source, if you get the compiler (probably the ide as well) elsewhere, it's likely no other option is given.
Also I cannot see blue dots by left side of source of fpimage unit. So this unit is not recompiled by running project. Why?
fpc (rtl and packages) units are plain units, they're not shipped in lazarus package form. The ide NEVER feeds their source to the compiler (which is a good thing), unless you specify in your project's unit path (which is a bad thing), it only uses the source for autocompletion.
-
I have another question. How to save 64-bit image? Even with special saving procedure, it saves 32-bit image. Is there 64-bit Init procedure?Maybe I must make it by hands:
procedure TRawImageDescription.Init_BPP64_A16R16G16B16_BIO_TTB(AWidth, AHeight: integer);
begin
FillChar(Self, SizeOf(Self), 0);
Format := ricfRGBA;
Depth := 64; // used bits per pixel
Width := AWidth;
Height := AHeight;
BitOrder := riboBitsInOrder;
ByteOrder := riboLSBFirst;
LineOrder := riloTopToBottom;
BitsPerPixel := 64; // bits per pixel. can be greater than Depth.
LineEnd := rileDWordBoundary;
RedPrec := 16; // red precision. bits for red
RedShift := 16;
GreenPrec := 16;
GreenShift := 32; // bitshift. Direction: from least to most signifikant
BluePrec := 16;
BlueShift := 48;
AlphaPrec := 16;
AlphaShift := 0;
// MaskBitsPerPixel := 0;
end;
I have added this init , but project saves 32-bit. And why GraphType unit recompiled? As you said it impossible. Ah?
As I can see TLazIntfImage just adds one more byte for each in RawDate. So TLazIntfImage is not fully 64-bit component - it just 32bit+ duplicate. Isn't it?
-
So TLazIntfImage is not fully 64-bit component - it just 32bit+ duplicate. Isn't it?
What OS do you use ? It seems that, for the Windows Lazarus 64 bit version, the default compiler is 32 bit. You have to compile the fpc-source 64 bit to have a real 64 bit compiler.
But maybe that has nothing to do with your problem... :-[
-
So TLazIntfImage is not fully 64-bit component - it just 32bit+ duplicate. Isn't it?
What OS do you use ? It seems that, for the Windows Lazarus 64 bit version, the default compiler is 32 bit. You have to compile the fpc-source 64 bit to have a real 64 bit compiler.
But maybe that has nothing to do with your problem... :-[
My OS is WinXP SP3 Pro Russian 32-bit. Lazarus: Lazarus-1.1-41044-fpc-2.7.1-20130506-win32.exe
But on my 32-bit system I can see 64-bit PNG files. So colours is not connected with OS' Bit depth
-
Is there no Load.../SaveToStream()? You wouldn't need anything related to RawImage in your code then.
-
My OS is WinXP SP3 Pro Russian 32-bit. Lazarus: Lazarus-1.1-41044-fpc-2.7.1-20130506-win32.exe
Ok, so nothing to do with your problem...
PS : Could you add that description of your system in your profile ?
(Profile > Forum Profile > Signature)
Thanks
-
And why GraphType unit recompiled? As you said it impossible. Ah?
GraphType is not part of fcl-image, it's part of LCL.
So TLazIntfImage is not fully 64-bit component - it just 32bit+ duplicate. Isn't it?
Perhaps, 64-bit image is just too much I guess. Unless the writing/reading method is separated per depth/bpp, it could be a noticable slow down.
@Fred:
What anna means is 64-bit image, it's not related to architecture.
-
I do not think that there exists any graphics card that supports 64bit images. Just to make sure what you are saying a 64bit image should be what photoshop call a 16bit color depth. aka 2 bytes per color (including alpha channel) instead of one.
This is not support currently and it will probably not be supported until the hardware starts to support that kind of color depth.
-
This is not support currently
First image in google my Opera Browser can show and Opera even says right color depth:
http://img819.imageshack.us/img819/7910/55140694.png
For my problem it is not important to see all 2^64 colours. It's important to restore correctly data encrypted inside of image. I am using OllyDBG to test decrypted data. And it absolutelly not equal input data (in my example it is project executable).
-
Is there no Load.../SaveToStream()? You wouldn't need anything related to RawImage in your code then.
Does not work. "Jpeg error". I think Loadfromstream tries to find image header or other image system information
-
I have made working example, which encrypt project.exe to PNG-image. Then PNG-image can be decrypted. No cheching errors...
But example makes 32-bit image (v_v)
-
In this wiki page http://wiki.freepascal.org/Fast_direct_pixel_access is said that "TLazIntfImage is a memory image. I can store transparency and 16-bit values for each channel." So it can keep 64-bit per pixel raw data. But where can I find routines for correctly saving that images?
-
You should first check if you can simply save 64-bit JPG normally, and afterwards include the encryption. I'm still in opinion that the streams should do the trick, it's just matter of doing everything in right order. Resetting position to 0 in right place etc.
-
You should first check if you can simply save 64-bit JPG normally, and afterwards include the encryption. I'm still in opinion that the streams should do the trick, it's just matter of doing everything in right order. Resetting position to 0 in right place etc.
I don't know how to do it . Can you give a routine, please?
-
Starting with something simple, just SaveToFile() first. How do you build a 64bit image in the first place? I don't know how to make it 64-bit. Does it draw properly on your form, using standard Canvas.Draw command? Add that to roughly this kind code:
var pic: TPicture;
begin
// --- Build the image ---
pic:=TPicture.Create;
//pic.Bitmap.PixelFormat:=pfCustom; // ???
pic.Bitmap.SetSize(256, 256);
pic.Bitmap.Canvas.TextOut(10, 10, 'Test');
// --- Save it ---
pic.SaveToFile('c:\test.jpg');
pic.Free;
If that works, you can then look into how to encrypt the stream. SaveToFile is using FileStream internally, so it's good enough for testing.