Cirec
Messages postés3833Date d'inscriptionvendredi 23 juillet 2004StatutModérateurDernière intervention18 septembre 2022
-
20 juil. 2007 à 22:37
Cirec
Messages postés3833Date d'inscriptionvendredi 23 juillet 2004StatutModérateurDernière intervention18 septembre 2022
-
27 juil. 2007 à 14:27
Salut à tous,
Je fais appel à vos lumières parce que là je coince grave.
Je cherche le moyen de récuperer la taille (en pixels) d'une Image JPEG et PNG
sans devoir la charger (sinon ce serait trop simple) dans un TImage ou TJPEGImage
J'ai trouvé des codes qui font cela mais uniquement si le fichier comporte des données Exif
ce qui n'est pas forcément le cas pour tous les fichiers
J'ai également été faire un tour sur l'exellent site www.WotSit.org ... mais c'est pas gagné
Donc si vous avez une idée ... une solution ... un truc ... un bout de code peut être ...
WhiteHippo
Messages postés1154Date d'inscriptionsamedi 14 août 2004StatutMembreDernière intervention 5 avril 20123 21 juil. 2007 à 14:47
Bonjour
Voici un petit bout de code fait à TROP rapidement, donc pas mal d'améliorations quand à la forme et au fond sont à apporter mais le principe est là (Si quelqu'un veux se dévouer pour l'améliorer, le compléter, allez au boulot, moi j'ai autre chose à faire ce week end ) :
procedure JPEGWidthHeight( AStream : TStream ; out Width, Height : Integer ) ;
const
SOI_MARKER = #$FF#$D8;
SOF_MARKER = #$FF#$C0; // Start of Frame
JPEG_FORMAT = SOI_MARKER + #$FF#$E0 ;
EXIF_FORMAT = SOI_MARKER + #$FF#$E1 ;
JFIF_MARKER : array[0..4] of char = 'JFIF'#00 ;
EXIF_MARKER : array[0..5] of char = 'Exif'#00 ;
var
BlockPos : Integer ;
BlockLength : Integer ;
Datas : record
case byte of
0 : ( Raw : array[0..15] of char ) ;
1 : ( Marker : array[0..3] of char ) ;
2 : ( StartOf : array[0..1] of char ) ;
3 : ( BlocLength : array[0..1] of byte
) ;
4 : ( JPEGLength : array[0..1] of byte
; JPEGIdentifier : array[0..4] of char
; JPEGVersion : array[0..1] of byte
) ;
5 : ( ExifLength : array[0..1] of byte
; ExifIdentifier : array[0..5] of char
) ;
end ;
procedure BlockUpdate;
begin
AStream.Seek(BlockPos,soBeginning);
AStream.ReadBuffer(Datas,sizeof(Datas));
end ;
begin
Width := -1 ;
Height := -1 ;
BlockPos := 0 ;
BlockUpdate;
if ( Datas.Marker = JPEG_FORMAT ) then
begin
Inc( BlockPos, 4 ) ;
BlockUpdate;
BlockLength := 255 * Ord( Datas.BlocLength[0] ) + Ord( Datas.BlocLength[1] );
if ( Datas.JPEGIdentifier = JFIF_MARKER ) then
begin
while( BlockPos < AStream.Size ) do
begin
// Déplacement sur le bloc suivant
Inc( BlockPos, BlockLength ) ;
if ( BlockPos >= AStream.Size ) then Exit ;
BlockUpdate;
if ( Datas.StartOf = SOF_MARKER ) then
begin
Height := 256 * Ord( Datas.Raw[5] ) + Ord( Datas.Raw[6] ) ;
Width := 256 * Ord( Datas.Raw[7] ) + Ord( Datas.Raw[8] ) ;
Exit ;
end else
begin
Inc(BlockPos,2);
BlockUpdate;
BlockLength := 255 * Ord( Datas.BlocLength[0] ) + Ord( Datas.BlocLength[1] );
end ;
end ;
end ;
end else if ( Datas.Marker = EXIF_FORMAT ) then
begin
//
Inc( BlockPos, 4 ) ;
BlockUpdate;
// Vérification entête du JPEG ( 'JFIF'#0 )
if ( Datas.ExifIdentifier = EXIF_MARKER ) then
begin
// etc... pas le temps de le gérer
end ;
end ;
end ;
// Exemple d'utilisation
procedure TForm1.Button1Click(Sender: TObject);
var
F : TFileStream ;
W,H : Integer ;
begin
F := TFileStream.Create('C:\test.jpg',fmOpenRead);
try
JPEGWidthHeight( F, W, H ) ;
Caption := IntToStr(W)+'x'+IntToStr(H);
finally
FreeAndNil( F );
end;
end;
N.B. Le format Exif n'est pas pris en charge, mais pas beaucoup plus compliqué à gérer.
Cordialement. <hr />"L'imagination est plus importante que le savoir." Albert Einstein
Cirec
Messages postés3833Date d'inscriptionvendredi 23 juillet 2004StatutModérateurDernière intervention18 septembre 202250 22 juil. 2007 à 11:14
Salut,
Merci pour ces informations ...
J'en suis arrivé au même résultat que toi (avec beaucoup moin de classe) dans un style plus "brute"
mais qui me permet de lire la taille peut importe le format du JPEG ce que je n'ai pas réussi avec ton code.
j'ai testé ton code et fait une petite modif pour lire les fichiers Exifs et ça fonctionne mais j'ai des fichiers
avec entête JFIF contenant également un Exif et la il plante (enfin il ne trouve rien) ????
Voici le code que j'ai fais et qui fonctionne avec tous mes fichiers JPEG
Function ReadSignature(Stream: TStream; Model : LongInt; Const Size : Integer = 4): Boolean;
Var aSign : LongInt;
Begin Stream.Read(aSign, Size); Result :Model aSign;
End ;
Function ReadSignatureEx(Stream: TStream): Boolean;
Var Count, I : Integer;
Begin Count : = 0;
If ReadSignature(Stream, JPEGSignature, 3) ThenBegin Stream.Seek(3, soFromCurrent);
For I := 0 to 1 do Repeat Result : = ReadSignature(Stream, SizeSignature);
IfNot Result Then Stream.Seek(-3, soFromCurrent)
ElseBegin FoundAt[Count] := Stream.Position + 1;
Inc(Count);
End ;
Until (Result) or (Stream.Position + SizeOf(LongInt) > Stream.Size);
End;
Result : = (FoundAt[0] > -1) or (FoundAt[1] > -1);
End;
Function SwapByte(aValue : Word):Word;
Begin Result := (aValue Shr 8) or (Byte(aValue) Shl 8)
End;
procedure GetJPEGSize(FileName : TFileName ; out Width, Height : Word ) ;
Var FS : TMemoryStream;
Begin FoundAt[0] : = -1;
FoundAt[1] := -1;
FS := TMemoryStream.Create;
FS.LoadFromFile(FileName);
If ReadSignatureEx(FS) ThenBegin If FoundAt[1] > -1 Then FS.Seek(FoundAt[1], soFromBeginning)
ElseIf FoundAt[0] > -1 Then FS.Seek(FoundAt[0], soFromBeginning);
FS.ReadBuffer(Height, SizeOf(Word));
FS.ReadBuffer(Width, SizeOf(Word));
cincap
Messages postés460Date d'inscriptiondimanche 5 décembre 2004StatutMembreDernière intervention 6 avril 20092 21 juil. 2007 à 08:43
Bonjour à toutes et à tous,
@ Cirec, j'avais réalisé une unité qui me permettait de voir mes skins avant de les installer, avec un TflileListBox et un Tlabel je récupérais la hauteur et la largeur du skin.
A toutes fin voici une éventuelle solution.
var
bmp1 : Tbitmap; // bitmap lu
implementation
.....
Label1.caption := ExtractFilename(filelistbox1.filename)+ Format(' (L %d x H %d)', [bmp1.Width, bmp1.Height]);
N. B. il faut tenir compte de la conversion en cas du jpg.
Je peus te passer tout le code de l'unité "Lecture" en cas de besoin.
florenth
Messages postés1023Date d'inscriptiondimanche 1 août 2004StatutMembreDernière intervention17 août 20083 21 juil. 2007 à 12:05
Salut !
Il faudra forcément lire un bout du fichier pour trouver les infos voulues !
Mais si tu ne veux pas tout décompresser, alors la librairie GraphicEx permet de le faire sans aucun problème. Par contre, aucun moyen de me souvenir comment on fait.
florenth
Messages postés1023Date d'inscriptiondimanche 1 août 2004StatutMembreDernière intervention17 août 20083 21 juil. 2007 à 12:19
Après une petite recherche :
<hr size= "2" width="100%" /> uses
Jpg; // unité de lecture des jpeg version GraphicEx.
[...]
procedure TForm1.Button1Click(Sender: TObject);
var W, H: Cardinal;
begin if OpenDialog1.Execute then
begin
GetJPEGInfo(OpenDialog1.FileName, W, H); ShowMessageFmt('W %d - H %d', [W, H]);
end;
end;
<hr size="2" width="100%" />
Ce que je peux t'assurer, c'est que le fichier n'est pas décompressé, mais il doit être lu en grande partie. A mon avis, il doit y avoir moyen d'aller encore plus vite.
Cirec
Messages postés3833Date d'inscriptionvendredi 23 juillet 2004StatutModérateurDernière intervention18 septembre 202250 21 juil. 2007 à 12:19
Bon je vais répéter :
"Je cherche le moyen de récuperer la taille (en pixels) d'une Image JPEG et PNG
sans devoir la charger dans un TImage ou TJPEGImage (sinon ce serait trop simple)"
dans Le bout de code que tu proposes l'image (ici un BMP) est chargé dans un TBitmap afin d'en récuperer sa taille ...
le seul chargement autorisé pour moi c'est dans TMemoryStream ... pourquoi
Tout simplement parce que je charge les images (*.JPEG; *.PNG; ...) sans l'utilisation d'unité dédié
comme "JPEG.PAS; PNGLIB.PAS ..."
d'ailleurs pour un BMP c'est très simple, il suffit de lire les informations dans le "bmiHeader "
florenth
Messages postés1023Date d'inscriptiondimanche 1 août 2004StatutMembreDernière intervention17 août 20083 27 juil. 2007 à 14:22
Ah ouais sympathique celle là. L'avantage de passer via scrippting c'est qu'on peut lire tous les fichiers images reconnus par windows.
ça sent le snippet tout ça ...