본문 바로가기
delphi

이미지 파일명으로 사이즈(폭/높이) 알아내기

by doran365 2024. 8. 2.

JPEG, PNG, GIF 포맷에 대해 이미지 사이즈 구하는 방법

이미지 컴포넌트를 이용하지 않고 파일명만을 가지고 직접 이미지 파일의 사이즈를 얻는 방법에 대해 알아보겠습니다. JPEG, PNG, GIF 포맷에 대해 각각 구현된 방법을 설명합니다.

이미지 사이즈를 얻기 위한 준비

이미지 파일의 사이즈를 얻기 위해 필요한 기본적인 준비 사항을 설명합니다. 본격적인 코딩에 앞서 필요한 유닛과 기본 함수들을 준비합니다.

unit uImageSize;

interface

uses 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);

implementation

uses SysUtils;

JPEG 이미지 사이즈 구하기

JPEG 파일의 사이즈를 구하기 위해 JPEG 파일 포맷의 구조를 이해해야 합니다. JPEG 파일의 헤더를 읽어 실제 이미지의 폭과 높이를 추출하는 방법을 설명합니다.

function ReadMWord(f: TFileStream): Word;
type
  TMotorolaWord = record
    case Byte of
      0: (Value: Word);
      1: (Byte1, Byte2: Byte);
  end;
var
  MW: TMotorolaWord;
begin
  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) do
      if Sig[x] <> ValidSig[x] then ReadLen := 0;

    if ReadLen > 0 then
    begin
      ReadLen := f.read(Seg, 1);
      while (Seg = $FF) and (ReadLen > 0) do
      begin
        ReadLen := f.read(Seg, 1);
        if Seg <> $FF then
        begin
          if (Seg = $C0) or (Seg = $C1) then
          begin
            ReadLen := f.read(Dummy[0], 3); 
            wHeight := ReadMWord(f);
            wWidth  := ReadMWord(f);
          end 
          else 
          begin
            if not (Seg in Parameterless) then
            begin
              Len := ReadMWord(f);
              f.Seek(Len - 2, 1);
              f.read(Seg, 1);
            end 
            else
              Seg := $FF; 
          end;
        end;
      end;
    end;
  finally
    f.Free;
  end;
end;

PNG 이미지 사이즈 구하기

PNG 파일의 구조와 이를 통해 이미지 사이즈를 얻는 방법을 설명합니다. PNG 헤더를 읽어 이미지의 폭과 높이를 추출합니다.

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) do
      if 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;

GIF 이미지 사이즈 구하기

GIF 파일의 구조를 이해하고 이를 통해 이미지의 사이즈를 추출하는 방법을 설명합니다. GIF 파일의 헤더를 읽어 실제 이미지의 폭과 높이를 구하는 방법을 설명합니다.

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;   
  AssignFile(f, sGifFile);
  reset(f, 1);
  if IOResult <> 0 then
    Exit;

  BlockRead(f, Header, SizeOf(TGifHeader), nResult);
  if (nResult <> SizeOf(TGifHeader)) or (IOResult <> 0) or
    (StrLComp('GIF', Header.Sig, 3) <> 0) then
  begin
    Close(f);
    Exit;
  end;

  if (Header.Flags and $80) > 0 then
  begin
    x := 3 * (1 shl ((Header.Flags and 7) + 1));
    Seek(f, x);
    if IOResult <> 0 then
    begin
      Close(f);
      Exit;
    end;
  end;

  DimensionsFound := False;
  FillChar(ImageBlock, SizeOf(TGIFImageBlock), #0);
  BlockRead(f, c, 1, nResult);
  while (not EOF(f)) and (not DimensionsFound) do
  begin
    case c of
      ',': 
        begin
          BlockRead(f, ImageBlock, SizeOf(TGIFImageBlock), nResult);
          if nResult <> SizeOf(TGIFImageBlock) then 
          begin
            Close(f);
            Exit;
          end;
          wWidth := ImageBlock.Width;
          wHeight := ImageBlock.Height;
          DimensionsFound := True;
        end;
      'y': 
        begin
        end;
    end;
    BlockRead(f, c, 1, nResult);
  end;
  Close(f);
  {$I+}
end;

결론

이제 우리는 JPEG, PNG, GIF 파일의 사이즈를 파일명을 통해 얻는 방법을 상세히 살펴보았습니다. 각 이미지 포맷에 맞는 구조를 이해하고, 파일 스트림을 통해 필요한 정보를 추출하는 것이 중요합니다. 이 방법들을 활용하면 다양한 환경에서 이미지의 사이즈를 쉽게 얻을 수 있습니다.