Image1.Picture.LoadFromFile('c:\windows\help.ico');
Image1.Picture.LoadFromFile('c:\windows\Bubbles.bmp');
Image1.Picture.LoadFromFile('c:\QUAKE2\q2.ico'); // this fails
It also won't display some metafiles.
Getting Rid of Flicker
procedure TForm1.FormCreate(Sender: TObject); begin Form1.DoubleBuffered := true; end;For other solutions, see GDI Graphics In Delphi - Four Ways To Kill Flicker and Picture Motion--Avoid The Flicker .
The Clipboard
Instead, you should use TClipboard.Assign and TPicture.Assign which do use the TPicture clipboard commands.
Clipboard.Assign(Image1.Picture); Clipboard.Assign(SpeedButton1.Glyph); // Glyph is a TBitmap Image1.Picture.Assign(Clipboard);For these to work, be sure to add clipbrd to the uses clause.
For more info, see the Clipboard section of efg's Delphi Graphics: Algorithms.
Problems
Icons
Image1.Picture.LoadFromFile('c:\windows\help.ico');
Clipboard.Assign(Image1.Picture); // This fails
Clipboard.Assign(Image1.Picture.Graphic); // and this fails
Monochrome Bitmaps
Image1.Picture.LoadFromFile('c:\windows\Bubbles.bmp');
Clipboard.Assign(Image1.Picture); // This works fine
Image1.Picture.LoadFromFile('c:\windows\Circles.bmp');
Clipboard.Assign(Image1.Picture); // This crashes the system
I was able to track this to TBitmap.SaveToClipboardFormat.
It also "appears" to only be a problem with bmp files which have a
2-color (monochrome) palette, those with On a separate system (running Windows 95), I got "Invalid clipboard format" the first time this code executed. Afterwards, it simply copied a null graphic to the clipboard. (Note: Windows 98 crashes, Windows 95 simply reports an error.)
On the Windows 98 system, Circles.bmp also causes the Microsoft Paint program to crash if you select Edit / Select All.
Using Windows XP, it sort of works. Circles.bmp is monochrome - Dark Blue and Light Blue - but when you paste it, it is black and white. (Well, at least it doesn't crash.) Of course, this means that Delphi is ok, it is just another Windows design problem that users will blame on you and your code.
Fix
Image1.Picture.LoadFromFile('c:\windows\Circles.bmp');
if Image1.Picture.Graphic is TBitmap then
if not Image1.Picture.Bitmap.Monochrome then
Clipboard.Assign(Image1.Picture.Graphic)
else
Clipboard.Clear
else if Image1.Picture.Graphic is TIcon then
Clipboard.Clear
else // Metafile, jpeg, ...
Clipboard.Assign(Image1.Picture.Graphic);
if Clipboard.HasFormat(CF_PICTURE) then
Image2.Picture.Assign(Clipboard);
end;
JPEG
Modifying and/or creating JPEG images is a bit more complex and is covered in the separate JPEG Image page.
PNG
Locating, installing, and using this code is covered in the separate PNG Image page.
GIF
Uses ..., axctrls;
procedure TForm1.Open1Click(Sender: TObject);
var
f : TFileStream;
graphic : TOleGraphic;
begin
if OpenDialog1.Execute then
begin
graphic := TOleGraphic.Create;
f := TFileStream.Create (OpenDialog1.FileName,
fmOpenRead or fmShareDenyNone);
try
graphic.LoadFromStream(f);
Image1.Picture.Assign(graphic);
finally
f.Free
end
end
end;
Also see
Torry's Delphi GIF Pages.
TGIFImage (By Anders Melander) Integrates with TPicture to add GIF support to the TImage.
(Full source code is provided.)
TIFF
To create a tiff file, just copy Bmp2tiff.pas to your program directory and call it via something like this
// Save Image as TIFF in the same path with extension '.TIF'
WriteTiffToFile( ChangeFileExt(OpenDialog1.FileName, '.TIF'),
Image1.Picture.Bitmap );
Related Commands
SavePictureDialog1.DefaultExt := GraphicExtension(TBitmap); SavePictureDialog1.Filter := GraphicFilter(TBitmap); if SavePictureDialog1.Execute thenThese work on colors
ColorToRGB ColorToString StringToColorThere are 42 "named" colors.
Reading Images
I have an application that displays MRI images that are stored as simple data files (2 bytes per pixel).
The following code requires about 3 seconds to load each image
var
// F: File; // Defined as a global variable
S: string;
i, j: integer;
buff: array [0..131072] of char;
tc:TColor;
begin
AssignFile(F, 'downloads\bruce_June5.txt');
Reset(F, 2);
BlockRead(F, ImageArray[0, 0], 256*256);
Image1.Picture.Bitmap.Height := 256;
Image1.Picture.Bitmap.Width := 256;
for i := 0 to 255 do
for j := 0 to 255 do begin
tc := ImageArray[i, j];
Image1.Picture.Bitmap.Canvas.Pixels[i, j] := tc;
end;
Image1.Canvas.Refresh;
// CloseFile(F);
end;
By first writing to a non-displayed bitmap,
this code requires only 1 second per bitmap.
var
// F: File;
S: string;
i, j, k: integer;
buff: array [0..131072] of char;
tc:TColor;
Bitmap: TBitmap;
begin
AssignFile(F, 'downloads\bruce_June5.txt');
Reset(F, 2);
ImageList1.CreateSize(256, 256);
for k := 0 to 155 do begin // 155
Bitmap := TBitmap.Create;
Bitmap.Height := 256;
Bitmap.Width := 256;
BlockRead(F, ImageArray[0, 0], 256*256);
for i := 0 to 255 do
for j := 0 to 255 do begin
tc := ImageArray[i, j];
Bitmap.Canvas.Pixels[i, j] := tc;
end;
ImageList1.Add(Bitmap, nil);
end;
Image1.Picture.Bitmap := Bitmap; // This just indicates that the load is done
end;
Reading an *.bmp file is very fast (about 6 seconds for 155 images),
however, the images are arranged
as
var
hb: HBITMAP;
Stream: TFileStream;
begin
Stream := TFileStream.Create('xxyy.bmp',fmOpenRead );
Imagelist1.Height := 256; Imagelist1.Width := 256;
Imagelist1.Clear;
bm.LoadFromStream(Stream);
Imagelist1.Add(bm, nil);
// bm.ReleaseHandle;
Stream.Destroy;
Image1.Picture.Bitmap := bm; // This just indicates that the load is done
end;
The problem is with how the *.bmp file was created - I loaded the 156 images into an imagelist (but only the first 74 are available using Windows 98, they are all read using Windows XP - same *.exe) and then saved them to the *.bmp file using this code.
var
hb: HBITMAP;
Stream: TFileStream;
bm: TBitmap;
begin
Stream := TFileStream.Create('xxyy.bmp',fmCreate );
bm := TBitmap.Create;
hb := Imagelist1.GetImageBitmap ;
bm.Width := 256*100; // This is part of the debug
bm.Handle := hb;
bm.SaveToStream (Stream);
bm.ReleaseHandle;
Stream.Destroy;
end;
The Delphi 5 help says
All images in an image list are contained in a single, wide bitmap in screen device format.but, apparently, that is not true.
I tried setting the width of the bitmap object before assigning the handle - no effect. Either way, after
Presumably, this is controlled by the AllocBy parameter.
Changing Images via a TMemoryStream
It only takes a second to read the entire 20M file into an array. Reformatting it into a second array with RGB planes takes 20 seconds. I assume that the Trunc command is taking too long. I have experimented with several commands that convert an integer to a byte (trunc, dividing by 256, and shr which is the fastest).
Tbitmap writes to a stream as 3 bytes (RGB) per pixel.
This code replaces one image with another (it is actually fairly fast).
If you don't set PixelFormat to
var bm2: TBitmap; st: TMemoryStream; begin bm2:= TBitmap.Create; bm2.PixelFormat := pf24bit; bm2.Width := 256 ; bm2.Height := 256 ; st := TMemoryStream.Create; bm2.SaveToStream (st); st.Seek( - (256*256*3), soFromEnd); st.WriteBuffer( ColorArray[ScrollPos,0,0,1] , 256*256*3); st.Seek(0, soFromBeginning ); bm2.LoadFromStream(st); Image1.Picture.Bitmap := bm2; bm2.Destroy ; st.Destroy; end;Notice how the bits are arranged
ColorArray[ScrollPos,0,0,1]
| | |
| | - color plane - 1-blue 2-green 3-red
| --- x 0 is left of bitmap, Increases toward right
----- y 0 is bottom of bitmap, Increases toward top
Using Scanlines[] to Edit a Canvas
Keeping the Same Aspect Ratio
Reference: efg's Computer Lab
Undocumented Data
PRGBTriple = ^TRGBTriple;
{$EXTERNALSYM tagRGBTRIPLE}
tagRGBTRIPLE = packed record
rgbtBlue: Byte;
rgbtGreen: Byte;
rgbtRed: Byte;
end;
TRGBTriple = tagRGBTRIPLE;
{$EXTERNALSYM RGBTRIPLE}
RGBTRIPLE = tagRGBTRIPLE;
PRGBQuad = ^TRGBQuad;
{$EXTERNALSYM tagRGBQUAD}
tagRGBQUAD = packed record
rgbBlue: Byte;
rgbGreen: Byte;
rgbRed: Byte;
rgbReserved: Byte;
end;
TRGBQuad = tagRGBQUAD;
{$EXTERNALSYM RGBQUAD}
RGBQUAD = tagRGBQUAD;
If a bitmap's height is positive, then 0,0 is at the bottom left
corner of the image;
if it is negative, then it is at the top left
corner of the image. (or vise versa - its not documented in the help,
I found this in TBitmap.GetScanLine in graphics.pas)
Also useful and undocumented in the Delphi 5 help file