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
This is implemented via RegisterFileFormat which registers a new TGraphic class for use in LoadFromFile. You can then use the appropriate files with code similar to
SavePictureDialog1.Filter := GraphicFilter(TBitmap); OpenDialog1.Filter := GraphicFilter(TGraphic);GraphicFilter(TGraphic) produces the following picklist format
All (*.jpg;*.jpeg;*.bmp;*.ico;*.emf;*.wmf) JPEG Image File (*.jpg) JPEG Image File (*.jpeg) Bitmaps (*.bmp) Icons (*.ico) Enhanced Metafiles (*.emf) Metafiles (*.wmf)I was not able to find any other way to determine which file types are supported. The list used to store the registered types is private to Graphics.pas.
Manipulating Pixels
var
Form1: TForm1;
Images: TList;
procedure TForm1.Load_UIButtonClick(Sender: TObject);
var
p1:TPicture;
i:integer;
str1, str2, str3:String;
b1:TBitmap;
begin
str1 :='E:\DelphiProjects\Images\Chab-01_';
str3 := '.jpg';
p1 := TPicture.Create;
try
images.Clear;
for i := 1 to 9 do begin
str2 := format('%2.2d', [i]);
p1.LoadFromFile(str1+str2+str3); // E:\DelphiProjects\Images\Chab-01_03.JPG
b1 := TBitmap.Create ;
b1.Height := p1.Graphic.Height; // Must set Height & Width
b1.Width := p1.Graphic.Width;
b1.Canvas.Draw(0,0,p1.Graphic);
images.Add(b1);
end;
Image1.Picture.Bitmap := b1; // Just indicates that the loop is done
Image_UIScrollBar.SetParams(1, 1, images.Count);
finally
p1.Free;
end;
end;
This code fragment reads the bitmaps from the list and plots pixel values.
b1:=(TBitmap(images.Items [0]));
x1 := trunc(x * image2.Width / b1.Width);
y1 := trunc(y * image2.Height / b1.Height);
Graph_x:= 1;
Graph_y:= trunc((b1.Canvas.Pixels[x1, y1]and $ff)/4 +20 );
image2.Canvas.Pen.Color := clRed ;
image2.Canvas.MoveTo(Graph_x, Graph_y);
for i :=1 to images.Count-1 do begin
b1 := (TBitmap(images.Items [i]));
Graph_x:= 10 + x_spacing*i;
Graph_y:= b1.Canvas.Pixels[x1, y1] ;
Graph_y:= trunc((Graph_y and $ff)/4 + 20);
image2.Canvas.LineTo(Graph_x, Graph_y);
end;
Reference:
Converting a BMP to a JPEG and vice-versa under Delphi 3 - by Borland Developer Support Staff
Bogus JPEG Error #36
When writing JPEG files larger than 1 mb, you may get the bogus
One fix is to modify JPEG.pas and recompile. With Delphi 5 professional, the source code is located on the CD at
D:\Info\Extras\Jpeg\JPEG.PAS
The problem is fixed by adding a try..except block and recompiling.
procedure TJPEGImage.Compress;
try // this is the fix
jpeg_finish_compress(jc.c); // This line generates the error
except
end;
Note that jpeg_finish_compress is implemented in the library
(it is external) and not written in Delphi.
Though several web pages say different, this problem was observed in Delphi 6.
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