Процедуры быстрого получения размера изображения из файлов JPG, GIF, PNG
unit ImgSize;
interfaceuses
Classes;
procedure GetJPGSize(const sFile: string; var wWidth, wHeight: word);
procedure GetPNGSize(const sFile: string; var wWidth, wHeight: word);
procedure GetGIFSize(const sGIFFile: string; var wWidth, wHeight: word);
implementationuses
SysUtils;
function ReadMWord(f: TFileStream): word;
type TMotorolaWord = recordcase byte of
0: (Value: word);
1: (Byte1, Byte2: byte);
end;
var
MW: TMotorolaWord;
begin{ It would probably be better to just read these two bytes in normally }{ and then do a small ASM routine to swap them. But we aren't talking }{ about reading entire files, so I doubt the performance gain would be }{ worth the trouble.}
f.read(MW.Byte2, SizeOf(Byte));
f.read(MW.Byte1, SizeOf(Byte));
Result := MW.Value;
end;
procedure GetJPGSize(const sFile: string; var wWidth, wHeight: word);
const
ValidSig : array[0..1] of byte = ($FF, $D8);
Parameterless = [$01, $D0, $D1, $D2, $D3, $D4, $D5, $D6, $D7];
var
Sig: array[0..1] of byte;
f: TFileStream;
x: integer;
Seg: byte;
Dummy: array[0..15] of byte;
Len: word;
ReadLen: LongInt;
begin
FillChar(Sig, SizeOf(Sig), #0);
f := TFileStream.Create(sFile, fmOpenRead);
try
ReadLen := f.read(Sig[0], SizeOf(Sig));
for x := Low(Sig) to High(Sig) doif Sig[x] <> ValidSig[x] then
ReadLen := 0;
if ReadLen > 0 thenbegin
ReadLen := f.read(Seg, 1);
while (Seg = $FF) and (ReadLen > 0) dobegin
ReadLen := f.read(Seg, 1);
if Seg <> $FF thenbeginif (Seg = $C0) or (Seg = $C1) thenbegin
ReadLen := f.read(Dummy[0], 3);
{ don't need these bytes }
wHeight := ReadMWord(f);
wWidth := ReadMWord(f);
endelsebeginifnot (Seg in Parameterless) thenbegin
Len := ReadMWord(f);
f.Seek(Len-2, 1);
f.read(Seg, 1);
endelse
Seg := $FF;
{ Fake it to keep looping. }end;
end;
end;
end;
finally
f.Free;
end;
end;
procedure GetPNGSize(const sFile: string; var wWidth, wHeight: word);
type TPNGSig = array[0..7] of byte;
const
ValidSig: TPNGSig = (137,80,78,71,13,10,26,10);
var
Sig: TPNGSig;
f: tFileStream;
x: integer;
begin
FillChar(Sig, SizeOf(Sig), #0);
f := TFileStream.Create(sFile, fmOpenRead);
try
f.read(Sig[0], SizeOf(Sig));
for x := Low(Sig) to High(Sig) doif Sig[x] <> ValidSig[x] then
exit;
f.Seek(18, 0);
wWidth := ReadMWord(f);
f.Seek(22, 0);
wHeight := ReadMWord(f);
finally
f.Free;
end;
end;
procedure GetGIFSize(const sGIFFile: string; var wWidth, wHeight: word);
type
TGIFHeader = record
Sig: array[0..5] of char;
ScreenWidth, ScreenHeight: word;
Flags, Background, Aspect: byte;
end;
TGIFImageBlock = record
Left, Top, Width, Height: word;
Flags: byte;
end;
var
f: file;
Header: TGifHeader;
ImageBlock: TGifImageBlock;
nResult: integer;
x: integer;
c: char;
DimensionsFound: boolean;
begin
wWidth := 0;
wHeight := 0;
if sGifFile = '' then
exit;
{$I-}
FileMode := 0; { read-only }
AssignFile(f, sGifFile);
reset(f, 1);
if IOResult <> 0 then{Could not open file }
exit; { Read header and ensure valid file. }
BlockRead(f, Header, SizeOf(TGifHeader), nResult);
if (nResult <> SizeOf(TGifHeader)) or (IOResult <> 0)
or (StrLComp('GIF', Header.Sig, 3) <> 0) thenbegin{ Image file invalid }
close(f);
exit;
end; { Skip color map, if there is one }if (Header.Flags and $80) > 0 thenbegin
x := 3 * (1 shl ((Header.Flags and 7) + 1));
Seek(f, x);
if IOResult <> 0 thenbegin{ Color map thrashed }
close(f);
exit;
end;
end;
DimensionsFound := False;
FillChar(ImageBlock, SizeOf(TGIFImageBlock), #0);
{ Step through blocks. }
BlockRead(f, c, 1, nResult);
while (not EOF(f)) and (not DimensionsFound) dobegincase c of
',': { Found image }begin
BlockRead(f, ImageBlock, SizeOf(TGIFImageBlock), nResult);
if nResult <> SizeOf(TGIFImageBlock) thenbegin{ Invalid image block encountered }
close(f);
exit;
end;
wWidth := ImageBlock.Width;
wHeight := ImageBlock.Height;
DimensionsFound := True;
end;
'y' : { Skip }begin{ NOP }end;
{ nothing else. just ignore }end;
BlockRead(f, c, 1, nResult);
end;
close(f);
{$I+}end;
end.
Программный модуль на языке Delphi Pascal, предназначенный для быстрого извлечения размеров изображений из файлов форматов JPG, PNG и GIF.
Вот краткое описание каждой процедуры:
GetJPGSize(const sFile: string; var wWidth, wHeight: word): Эта процедура читает файл JPG и извлекает его ширину и высоту.
GetPNGSize(const sFile: string; var wWidth, wHeight: word): Эта процедура читает файл PNG и извлекает его ширину и высоту.
GetGIFSize(const sGIFFile: string; var wWidth, wHeight: word): Эта процедура читает файл GIF и извлекает его ширину и высоту.
Каждая процедура использует разные методы для чтения изображений:
Для файлов JPG процедура читает заголовок файла и затем итерирует по файлу, чтобы найти значения ширины и высоты.
Для файлов PNG процедура читает заголовок файла и затем SEEK'ит к конкретным местам в файле, чтобы прочитать значения ширины и высоты.
Для файлов GIF процедура читает заголовок файла и затем шагает по блокам данных в файле, пока не найдет блок изображения, содержащий значения ширины и высоты.
Вот некоторые примечания к коду:
Процедуры используют объекты TFileStream для чтения изображений.
Процедура GetJPGSize использует вспомогательную функцию ReadMWord, чтобы прочитать 2-байтовые целые числа из файла в little-endian byte order (то есть, Motorola style).
Процедура GetGIFSize использует тип записи TGIFHeader для представления заголовка GIF-файла и другой тип записи TGIFImageBlock для представления блока изображения.
Код включает в себя некоторые обработчики ошибок, такие как проверка на то, мог ли файл не быть открыт или прочитан.
В целом, этот код предоставляет простой способ быстро извлечь размеры изображений из файлов форматов JPG, PNG и GIF.
Процедуры быстрого получения размера изображения из файлов JPG, GIF и PNG.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.