Salut à tous!
Cela fait un bon moment que je n'ai plus développé et je crois que je suis quelque peu rouillé!
Je suis en train de développer un petit logiciel afin de me permettre d'archiver mes anciennes photographies. Le principe est assez simple, j'ai numérisé quelques anciennes photos de famille et mon application devrait me permettre d'ouvrir les fichiers (au format JPG), d'ajouter un commentaire comme par exemple le nom des personnes photographiées, et d'enregistrer le tout dans un nouveau fichier.
J'ai donc créé un nouveau composant TImageComment en m'inspirant de la source de Antidote:
http://www.delphifr.com/codes/ENREGISTREMENT-IMAGE-TEXTE-DANS-FICHIER_17586.aspx
J'ai apporté quelques modifications à cette source afin de la transformer en composant et de lui permettre de faire la détection entre les formats graphiques suivant: Graphic, Bitmap, Icon et Metafile.
La procédure d'enregistrement du fichier de sortie semble se passer correctement pour l'ensemble des formats graphiques, mais lorsque je souhaite rouvrir les fichiers, l'application se plante uniquement lors du chargement d'une image JPEG (Graphic), l'erreur intervient au niveau de la ligne Picture.Graphic.LoadFromStream(MemS);
Mon nouveau composant possède les propriétés suivantes:
- DefaultExt (String): pour l'extention du fichier global. Extention ".icf" par défaut.
- FileType (String): pour le format du fichier, signature d'identification. Format "IMGCMT10" par défaut.
- Lines (TStrings): pour contenir le commentaire.
- Picture (TPicture): pour contenir l'image.
Voici le code source de mon nouveau composant qui ressemble fort à celui de Antidote:
unit ImageComment;
interface
uses
SysUtils, Windows, Graphics, Classes, Controls, ExtCtrls, StdCtrls,
JPEG;
type
TGraphicFormat = (gfUnknow, gfGraphic, gfBitmap, gfIcon, gfMetafile);
TDataInfo = record
ActiveImage: Boolean;
ActiveText: Boolean;
FormatImage: TGraphicFormat;
PosImage: Int64;
PosText: Int64;
SizeImage: Int64;
SizeText: Int64;
end;
TImageComment = class(TComponent)
private
FDefaultExt: String;
FFileType: String;
FLines: TStrings;
FPicture: TPicture;
procedure SetDefaultExt(Value: String);
procedure SetFileType(Value: String);
procedure SetLines(Value: TStrings);
procedure SetPicture(Value: TPicture);
{ Déclarations privées }
protected
DataInfo: TDataInfo;
FileFormat: String[8];
{ Déclarations protégées }
public
LoadError: Byte;
constructor Create(Aowner: TComponent); override;
destructor Destroy; override;
procedure LoadFromFile(const Filename: String);
procedure SaveToFile(const Filename: String);
{ Déclarations publiques }
published
property DefaultExt: String read FDefaultExt write SetDefaultExt;
property FileType: String read FFileType write SetFileType;
property Lines: TStrings read FLines write SetLines;
property Picture: TPicture read FPicture write SetPicture;
{ Déclarations publiées }
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('LeGuepard', [TImageComment]);
end;
constructor TImageComment.Create(Aowner :TComponent);
begin
inherited Create(Aowner);
FDefaultExt:='icf'; //ImageCommentFile
FFileType:='IMGCMT10'; //ImageCommentFile 1.0
FLines:=TStringList.Create;
FPicture:=TPicture.Create;
FileFormat:=FFileType;
LoadError:=0;
end;
destructor TImageComment.Destroy;
begin
FPicture.Free;
FLines.Free;
inherited Destroy;
end;
procedure TImageComment.SetDefaultExt;
begin
if FDefaultExt<>Value then
begin
FDefaultExt:=Value;
end;
end;
procedure TImageComment.SetFileType;
begin
if FFileType<>Value then
begin
if Length(Value)>0 then FFileType:=Value
else FFileType:='IMGCMT10';
FileFormat:=FFileType;
end;
end;
procedure TImageComment.SetLines;
begin
FLines.Assign(Value);
end;
procedure TImageComment.SetPicture;
begin
FPicture.Assign(Value);
end;
procedure TImageComment.LoadFromFile;
var
FFormat: String[8];
FileS: TFileStream;
MemS: TMemoryStream;
begin
LoadError:=0;
if not FileExists(Filename) then
begin
LoadError:=1;
Exit;
end;
FileS:=TFileStream.Create(Filename, fmOpenRead);
MemS:=TMemoryStream.Create;
try
FileS.Read(FFormat, SizeOf(FileFormat));
if FFormat<>FileFormat then
begin
LoadError:=2;
Exit;
end;
FileS.Read(DataInfo, SizeOf(TDataInfo));
if DataInfo.ActiveImage then
begin
FileS.Position:=DataInfo.PosImage;
MemS.SetSize(DataInfo.SizeImage);
MemS.CopyFrom(FileS,DataInfo.SizeImage);
MemS.Position:=0;
case DataInfo.FormatImage of
gfGraphic: Picture.Graphic.LoadFromStream(MemS); // Ligne du Bug !
gfBitmap: Picture.Bitmap.LoadFromStream(MemS);
gfIcon: Picture.Icon.LoadFromStream(MemS);
gfMetafile: Picture.Metafile.LoadFromStream(MemS);
end;
MemS.Clear;
end;
if DataInfo.ActiveText then
begin
FileS.Position:=DataInfo.PosText;
MemS.SetSize(DataInfo.SizeText);
MemS.CopyFrom(FileS,DataInfo.SizeText);
MemS.Position:=0;
Lines.LoadFromStream(MemS);
MemS.Clear;
end;
finally
MemS.Free;
FileS.Free;
end;
end;
procedure TImageComment.SaveToFile;
var
ext: String;
path: String;
FileS: TFileStream;
MemS: TMemoryStream;
begin
if Length(DefaultExt)=0 then ext:='icf'
else ext:=LowerCase(DefaultExt);
if Pos('.',ext)>1 then ext:=Copy(ext,1,(Pos('.',ext)-1));
if Pos('.',ext)=0 then ext:='.'+ext;
if ext='.' then ext:='.icf';
if ExtractFileExt(Filename)='' then path:=Filename+ext
else path:=Filename;
ChangeFileExt(path,LowerCase(ExtractFileExt(path)));
FileS:=TFileStream.Create(path, fmCreate);
MemS:=TMemoryStream.Create;
try
MemS.Write(FileFormat, SizeOf(FileFormat));
MemS.Write(DataInfo, SizeOf(DataInfo));
DataInfo.FormatImage:=gfUnknow;
if (Picture.Graphic is TGraphic) then DataInfo.FormatImage:=gfGraphic;
if (Picture.Graphic is TBitmap) then DataInfo.FormatImage:=gfBitmap;
if (Picture.Graphic is TIcon) then DataInfo.FormatImage:=gfIcon;
if (Picture.Graphic is TMetafile) then DataInfo.FormatImage:=gfMetafile;
DataInfo.ActiveImage:=(DataInfo.FormatImage<>gfUnknow);
if DataInfo.ActiveImage then
begin
DataInfo.PosImage:=MemS.Position;
case GraphicFormat of
gfGraphic: Picture.Graphic.SaveToStream(MemS);
gfBitmap: Picture.Bitmap.SaveToStream(MemS);
gfIcon: Picture.Icon.SaveToStream(MemS);
gfMetafile: Picture.Metafile.SaveToStream(MemS);
end;
DataInfo.SizeImage:=MemS.Position-DataInfo.PosImage;
end;
DataInfo.ActiveText:=(Length(Lines.Text)>0);
if DataInfo.ActiveText then
begin
DataInfo.PosText:=MemS.Position;
Lines.SaveToStream(MemS);
DataInfo.SizeText:=MemS.Position-DataInfo.PosText;
end;
FileS.Write(FileFormat, SizeOf(FileFormat));
FileS.Write(DataInfo, SizeOf(TDataInfo));
if DataInfo.ActiveImage then
begin
case GraphicFormat of
gfGraphic: Picture.Graphic.SaveToStream(FileS);
gfBitmap: Picture.Bitmap.SaveToStream(FileS);
gfIcon: Picture.Icon.SaveToStream(FileS);
gfMetafile: Picture.Metafile.SaveToStream(FileS);
end;
end;
if DataInfo.ActiveText then Lines.SaveToStream(FileS);
finally
MemS.Free;
FileS.Free;
end;
end;
end.
Le code du prototype de l'application qui fait appel à ce composant est le suivant:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, jpeg, ExtCtrls, ExtDlgs, ImageComment;
type
TForm1 = class(TForm)
Memo1: TMemo;
ScrollBox1: TScrollBox;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Image1: TImage;
OpenDialog1: TOpenDialog;
SaveDialog1: TSaveDialog;
OpenPictureDialog1: TOpenPictureDialog;
ImageComment1: TImageComment;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
{ Déclarations privées }
public
{ Déclarations publiques }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
if OpenPictureDialog1.Execute then
begin
Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);
ImgExt:= ExtractFileExt(OpenPictureDialog1.FileName);
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
ImageComment1.Picture:=Image1.Picture;
ImageComment1.Lines:=Memo1.Lines;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
if SaveDialog1.Execute then ImageComment1.SaveToFile(SaveDialog1.FileName);
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
if OpenDialog1.Execute then ImageComment1.LoadFromFile(OpenDialog1.FileName);
Image1.Picture.Assign(ImageComment1.Picture);
Memo1.Lines.Assign(ImageComment1.Lines);
end;
end.
Cela fait plusieurs jours que je planche sur ce bug et je commence à devenir "chèvre", j'ai beau comparer avec le code source de Antidote, je ne vois vraiment pas où se trouve le problème d'autant plus que ce composant fonctionne correctement pour trois des quatre format.
Je me suis donc dit que l'un d'entre vous pourrait y voir plus clair et trouver la solution à mon problème.
Pour celui qui le désir, je peux lui envoyer un e-mail avec le zip de mon travail pour faire des tests.
Je vous remercie d'avance pour le temps que vous apporterez à ce problème.
Bizz à tous!
Julien.