0

Some JPEG files with the following formats aren't displaying in Delphi's TImage control.

and comparing the speed to my existing grayscale code. The scanline process they use appears to be slightly faster than the scanline process that I currently have in place. It is a great starting point for someone working with images. I added the standard jpeg conversion code and scrollboxes when I ran into the issue and noticed the file size. I believe the question was valid, but I reworded it. If I find another related answer where the question is easier to find, I will pull this post. If not, I will leave it.

For example, from a Nikon digital camera.

Dimensions : Width 5184 x Height 3888
Vertical Resolution : 300 dpi
Color Representation : sRGB
Compressed bits/pixel : 2
Bit depth : 24
EXIF version : 0230
Attributes : N

From a Samsung cell phone camera:

Dimensions : Width 4128 x Height 2322
Horizontal & Vertical Resolution : 72 dpi
Color Representation : sRGB
Resolution unit : 2
Compressed bits/pixel : [blank]
Bit depth : 24
EXIF version : 0220
Attributes : A

A grayscale file from Adobe Photoshop:

Dimensions : Width 1800 x Height 3600
Horizontal and Vertical Resolution : 300 dpi
Color Representation : Uncalibrated
Compressed bits/pixel : [blank]
Bit depth : 8
EXIF version : [blank]
Attributes : A

A file with the exact format as the last one, but with much smaller dimensions, works.

Dimensions of one working file : Width 570 x Height 248

Files with 24-bit depth, smaller dimensions, and no resolution or compression settings, work correctly as well.

When I try to display the pictures using the code below, the picture on the failing files is always blank, and no errors are returned. It works perfectly with many other jpg and bmp files.

Is there a conversion that is required for sRGB formatted files? Is there a size limit on what the control can display on screen? If so, is there a way to display larger files?

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;
Joseph Poirier
  • 386
  • 2
  • 17
  • Could you add link to sample jpg file that does not work – EugeneK Jan 17 '17 at 20:33
  • Which version of Delphi are you using? – Remy Lebeau Jan 17 '17 at 21:31
  • I can confirm that it does not work even on Delphi 10.1 update 2. Works in FMX though, if this is an acceptable workaround. – EugeneK Jan 17 '17 at 21:40
  • 10.1 Seattle, I believe. I have not loaded the latest service pack. – Joseph Poirier Jan 17 '17 at 21:41
  • Also note. Operating System is Windows 10. Though, I kinda miss Win7 interface, I do feel that 10 is a bit safer for most users. – Joseph Poirier Jan 17 '17 at 21:49
  • There is some Delphi image JPEG source code at http://colosseumbuilders.com/sourcecode/index.html It may not be up to date with the most recent version and may need updating. You might be able to step through and find any problems. – user3344003 Jan 18 '17 at 00:39
  • @EugeneK - is there a good USB virtual comport or HID component out for FMX? If so, I can consider throwing out a copy of the software in FMX format in the near future. – Joseph Poirier Jan 18 '17 at 14:12
  • @JosephPoirier I don't know any, I don't work with FMX as much as I want unfortunately. – EugeneK Jan 18 '17 at 17:51
  • I was going to delete this question, but the system says I can get blocked from asking future questions, so I'm leaving it up unless the managers ask me to remove it. – Joseph Poirier Jan 31 '17 at 15:12

1 Answers1

2

Since you are not getting an error when loading the JPEG image, I suspect the problem may be in the conversion from TJPEGImage to TBitmap. Unless you are going to be manipulating the image pixels, you don't need the conversion at all, you can assign the original TJPEGImage directly to the TImage. The VCL's TPicture class uses derived TGraphic classes so it can display images in their native formats, you should utilize that feature, eg:

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;

Update: I did some tests in XE2 on Windows 7, and saw the same issue you do.

If I load the JPGs as-is using TImage.Picture.LoadFromFile(), they display fine only if the TImage.Stretch or TImage.Proportional property is True. If they are both set to False (the default), the images display blank.

If I load the JPGs into TJPEGImage first and then assign that to TBitmap, the conversion itself works fine (proved by saving the TBitmap to a .bmp file), and the bitmaps are displayed fine only if Stretch or Proportional are True, otherwise they display blank.

So, as another test, I tried using TPaintBox, drawing the images manually in its OnPaint event. If I use TCanvas.Draw() to draw the images as-is in their full dimensions, they display empty. If I use TCanvas.StretchDraw() to fit the images within the `PaintBox's client area, they display fine.

So, I think TCanvas is likely running into memory issues trying to display images at such larger dimensions. It has nothing to do with the particular type of JPGs being used (which are being loaded fine).


Update: nevermind what I said above. I see that the provided JPGs just have really large DPIs and happen to all be white in their top-left corners. If the TImage/TPaintBox is sized large to compensate, I can now see the images in their full dimensions (it is easier to see if the TImage is placed on a TScrollBox with TImage.AutoSize set to True). That would explain why stretch/proportional drawing works, by stretching the images to match TImage's dimensions when needed.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Hi Remy... I was doing that first and it was doing the same thing, only on some pictures. So I retested that to verify, still blank. Pushed out zipped folder of the three images to a download folder for testing. I moved this code line, [ Image1.Picture.LoadFromFile(name);], right to the top inside the try code and removed the [Image1.Picture.Assign(bmp)] to retest it. – Joseph Poirier Jan 17 '17 at 21:19
  • I saw your comment from this post earlier [http://stackoverflow.com/questions/22291162/delphi-tbitmap-why-are-pixels-and-scanline-different] and I wondered if there was a formatting change for sRGB vs. regular RGB files as there is in 24-bit vs. 32-bit files. If there is that and it isn't covered in the component or JPEG file, I could see where it would just display blank. – Joseph Poirier Jan 17 '17 at 21:28
  • thx for the update, I tried the stretchDraw and scrollbox earlier, but I may have missed the Autosize option. I'll give that a go. – Joseph Poirier Jan 18 '17 at 01:50
  • AutoSize is off by default. Only needed to check that option in the form image component and it worked as expected. Thx so much. Tomorrow, I'm going to rollin' the newer grayscale routine I was testing today, and our software rev will be complete. I can't believe I missed that checkbox. ps. .Assign(bmp) works as well as .Picture.LoadFromFile(name) with the checkbox set to [True] – Joseph Poirier Jan 18 '17 at 02:04