Delphi TImage: Как отобразить изображения, которые больше, чем компонент TImage, в который они загружаются или назначаются?

Некоторые файлы JPEG со следующими форматами не отображаются в Delphi's TImage контроль.

и сравнивая скорость с моим существующим кодом в градациях серого. Процесс сканирования, который они используют, кажется, немного быстрее, чем процесс сканирования, который у меня сейчас есть. Это отличная отправная точка для тех, кто работает с изображениями. Я добавил стандартный код преобразования jpeg и поля прокрутки, когда столкнулся с проблемой и заметил размер файла. Я считаю, что вопрос был верным, но я перефразировал его. Если я найду другой связанный ответ, где вопрос легче найти, я потяну этот пост. Если нет, я оставлю это.

Например, с цифровой камеры Nikon.

Размеры: ширина 5184 х высота 3888
Разрешение по вертикали: 300 точек на дюйм
Представление цвета: sRGB
Сжатые биты / пиксель: 2
Битовая глубина: 24
EXIF версия: 0230
Атрибуты: N

С камеры мобильного телефона Samsung:

Размеры: ширина 4128 х высота 2322
Горизонтальное и вертикальное разрешение: 72 dpi
Представление цвета: sRGB
Блок разрешения: 2
Сжатые биты / пиксель: [пусто]
Битовая глубина: 24
EXIF версия: 0220
Атрибуты: A

Файл в градациях серого из Adobe Photoshop:

Размеры: ширина 1800 х высота 3600
Горизонтальное и вертикальное разрешение: 300 точек на дюйм
Представление цвета: некалиброванный
Сжатые биты / пиксель: [пусто]
Битовая глубина: 8
Версия EXIF: [пусто]
Атрибуты: A

Работает файл с точным форматом, как у последнего, но с гораздо меньшими размерами.

Размеры одного рабочего файла: ширина 570 х высота 248

Файлы с 24-битной глубиной, меньшими размерами и без настроек разрешения или сжатия также работают правильно.

Когда я пытаюсь отобразить изображения с помощью приведенного ниже кода, изображение в файлах с ошибками всегда остается пустым, и ошибки не возвращаются. Это прекрасно работает со многими другими jpg а также bmp файлы.

Требуется ли преобразование для файлов в формате sRGB? Есть ли ограничение по размеру того, что элемент управления может отображать на экране? Если да, есть ли способ отобразить файлы большего размера?

procedure TForm1.btnBrowseClick(Sender: TObject);
var
  bmp: TBitmap;
  c2g: TColor2Grayscale;
  ba: TBitmapAccess;
  sw: TStopwatch;
  jpg : TJPEGImage; // jpeg does not show 32-bit support in Delphi, only 24 and 8.
  path, name, ext : string;
  alreadyGray : boolean;
begin
  bmp := TBitmap.Create;
  jpg := TJPEGImage.Create;

  OpenPicturedialog1.InitialDir := FindImageFolder(true);
  if OpenPictureDialog1.Execute() then
  try
    name := OpenPictureDialog1.FileName;
    path := ExtractFilePath(name);
    ext := Lowercase ( ExtractFileExt(name) );

    alreadyGray := false;

    try
      if ( ext = '.jpg' ) or ( ext = '.jpeg' ) then
      begin
        jpg.LoadFromFile(name);
        bmp.Assign(jpg);
        alreadyGray := jpg.Grayscale;
      end
      else
        bmp.LoadFromFile( name );
    except
      on err: Exception do
      begin
        ShowMessage(err.Message);
        Exit;
      end;
    end;

    if bmp.PixelFormat = pfDevice then
      bmp.PixelFormat := pf32bit;

    Image1.Picture.Assign(bmp);

    if alreadyGray then
    begin
      Image2.Picture.Assign(bmp);
      Exit;
    end;

  finally
    jpg.Free;
    bmp.Free;
  end;
end;

1 ответ

Решение

Так как вы не получаете сообщение об ошибке при загрузке изображения JPEG, я подозреваю, что проблема может быть в преобразовании из TJPEGImage в TBitmap, Если вы не собираетесь манипулировать пикселями изображения, вам вообще не нужно конвертировать, вы можете назначить оригинал TJPEGImage прямо к TImage, VCL's TPicture класс использует производные TGraphic классы, чтобы он мог отображать изображения в их собственных форматах, вы должны использовать эту функцию, например:

procedure TForm1.btnBrowseClick(Sender: TObject);
var
  jpg: TJPEGImage;
  bmp: TBitmap;
begin
  OpenPicturedialog1.InitialDir := FindImageFolder(true);
  if OpenPictureDialog1.Execute then
  begin
    Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);

    if Image1.Picture.Graphic is TJPEGImage then
    begin
      if TJPEGImage(Image1.Picture.Graphic).Grayscale then
      begin
        Image2.Picture.Assign(Image1.Picture.Graphic);
      end else
      begin
        jpg := TJPEGImage.Create;
        try
          jpg.Assign(Image1.Picture.Graphic);
          jpg.Grayscale := True;
          Image2.Picture.Assign(jpg);
        finally
          jpg.Free;
        end;
      end;
    end else
    begin
      bmp := TBitmap.Create;
      try
        bmp.PixelFormat := pf32bit;
        bmp.Assign(Image1.Picture.Graphic);
        ...
        Image2.Picture.Assign(bmp);
      finally
        bmp.Free;
      end;
    end;
  end;
end;

Обновление: я провел несколько тестов в XE2 в Windows 7 и увидел ту же проблему, что и вы.

Если я загружаю JPG как есть TImage.Picture.LoadFromFile(), они отображаются нормально только если TImage.Stretch или же TImage.Proportional Свойство Истина. Если они оба установлены в False (по умолчанию), изображения отображаются пустыми.

Если я загружу JPG в TJPEGImage сначала, а затем назначьте это TBitmap само преобразование работает нормально (доказано сохранением TBitmap к .bmp файл), и растровые изображения отображаются нормально, только если Stretch или же Proportional True, в противном случае они отображаются пустыми.

Итак, в качестве другого теста я попытался использовать TPaintBox, рисуя изображения вручную в своем OnPaint событие. Если я использую TCanvas.Draw() чтобы нарисовать изображения в полном размере, они отображаются пустыми. Если я использую TCanvas.StretchDraw() чтобы соответствовать изображениям в клиентской области PaintBox, они отображаются нормально.

Я так думаю TCanvas Вероятно, возникают проблемы с памятью при попытке отображения изображений в таких больших размерах. Это не имеет никакого отношения к конкретному типу используемых JPG (которые загружаются нормально).


Обновление: неважно, что я сказал выше. Я вижу, что предоставленные JPG-файлы имеют действительно большие DPI и все они имеют белый цвет в верхнем левом углу. Если TImage / TPaintBox имеет большой размер, чтобы компенсировать, теперь я могу видеть изображения в их полном размере (легче увидеть, если TImage находится на TScrollBox с TImage.AutoSize установить в True). Это объясняет, почему растягивание / пропорциональное рисование работает, растягивая изображения, чтобы соответствовать TImage Размеры при необходимости.

Другие вопросы по тегам