ImageEn for Delphi and C++ Builder ImageEn for Delphi and C++ Builder

 

ImageEn Forum
Profile    Join    Active Topics    Forum FAQ    Search this forumSearch
Forum membership is Free!  Click Join to sign-up
Username:
Password:
Save Password
Forgot your Password?

 All Forums
 ImageEn Library for Delphi, C++ and .Net
 ImageEn and IEvolution Support Forum
 Error loading DB image into MView with IDRequestEx
 New Topic  Reply to Topic
Author Previous Topic Topic Next Topic  

hinsona

14 Posts

Posted - May 07 2021 :  01:04:39  Show Profile  Reply
I have a project in Delphi 7. I'm using ImageEn 9.3.1.

Code that I've been using for several years to load images from a query using a blobstream throws an AV when calling LoadFromStream. Has something changed or am I doing something wrong?

I've broken the code into a sample project to illustrate the issue. I've uploaded it to OneDrive since it was giving me an issue attaching it.
https://1drv.ms/u/s!AsNfPwVDI-xGsMxUnIrcMgBCb9BBIg

There is a .SQL file in the project zip that contains a query to add a test table and insert the images I am using, if needed.



unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ieview, iemview, DB, ADODB, imageenview, hyiedefs, hyieutils, iemio, imageenio,
  iexBitmaps, StdCtrls;

type
  TForm1 = class(TForm)
    DataSource1: TDataSource;
    ImgEnMv: TImageEnMView;
    QryImages: TADOQuery;
    Label1: TLabel;
    procedure ImgEnMvImageIDRequestEx(Sender: TObject; Index, ID: Integer; var Bitmap: TIEBitmap);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    TmpEnV: TImageEnView;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  TmpEnV := TImageEnView.Create(nil);
  ImgEnMv.Clear;

  QryImages.Close;
  QryImages.Open;
  QryImages.First;
  while not QryImages.Eof do
  begin
    ImgEnMv.ImageID[ImgEnMv.AppendImage] := QryImages.RecNo;
    QryImages.Next;
  end;
end;

procedure TForm1.ImgEnMvImageIDRequestEx(Sender: TObject; Index, ID: Integer; var Bitmap: TIEBitmap);
var
  s: TStream;
begin
  s := QryImages.CreateBlobStream(QryImages.FieldByName('ImageData'), bmRead);
  s.Position := 0;
  try
    try
      if (TmpEnV.IO.LoadFromStream(s)) then
        Bitmap := TmpEnV.IO.IEBitmap;
    except on e: Exception do
      Label1.Caption := 'An error occurred while loading image, Index: ' + IntToStr(Index) + ', ID: ' + IntToStr(ID) + ' Error:' + E.Message;
    end;
  finally
    s.Free;
  end;
end;
end.


Thank you.

hinsona

14 Posts

Posted - May 09 2021 :  20:24:31  Show Profile  Reply
I tried modifying the DBMultiBitmap example project by adding an ADO query using the same data and it didn't work either.

If I point a reporting services report at the data and tell it the column is a jpeg image it displays correctly, so the data appears to be intact.

The data was inserted using the following...

Files are selected in TImageEnFolderMView.

for I := 0 to AImgFMView.ImageCount -1 do
      begin
        if (AImgFMView.Checked[I]) then
        begin
          srcPath := AImgFMView.MIO.Params[I].Filename;

          if not ieImage.IO.LoadFromFileAuto(srcPath) then
          begin
            ShowMessage(GetMsg('Unable to load the image file: ' + #13 +
                                    '[' + srcPath + '].' + #13 +
                                    'This image will be skipped.',0));
            Continue;
          end;

          //Create new image index in iemImage
          newI := iemImage.AppendImage;
          //Set the IEBitmap at newI in iemImage to the IEBitmap at I in AImgFMView
          //iemImage.SetIEBitmap(newI, AImgFMView.GetTIEBitmap(I));
          iemImage.SetImage(newI, ieImage.IO.IEBitmap);

          //Release the temporary bitmap in AImgFMView to free memory
          AImgFMView.ReleaseBitmap(I);

          //Copy the MIO.Params and text from AImgFMView to iemImage
          iemImage.MIO.Params[newI].Assign(AImgFMView.MIO.Params[I]);

          ImgTop_ImgSeq    := DMImages.GetNextSeq(TicketId);
          ImgBottom_TypeId := AImgFMView.ImageBottomText[I];
          ImgInfo_Info     := AImgFMView.ImageInfoText[I];

          iemImage.ImageTopText[newI]    := IntToStr(ImgTop_ImgSeq);
          iemImage.ImageBottomText[newI] := ImgBottom_TypeId;
          iemImage.ImageInfoText[newI]   := ImgInfo_Info;

          //get the local user profile temp folder
          tmpPath := GetSpecialFolderPath(CSIDL_LOCAL_APPDATA) + '\Temp\';

          if (AResizeOnImport) then
          begin
            //resample oversized images to save space
            if (ieImage.IO.IEBitmap.Width > ieImage.IO.IEBitmap.Height) then
            begin
              if (ieImage.IO.IEBitmap.Width > 1024) then // resample it
                ieImage.Proc.Resample(1024, -1, rfLanczos3, True);
            end
            else
            begin
              if (ieImage.IO.IEBitmap.Height > 1024) then // resample it
                ieImage.Proc.Resample(-1, 1024, rfLanczos3, True);
            end;
          end;

          // Save as JPEG
          ImgFormat := ioJPEG;
          ieImage.IO.StreamHeaders := False;
          ieImage.IO.Params.JPEG_Progressive := True;
          ieImage.IO.Params.JPEG_Smooth := 50;
          ieImage.IO.Params.JPEG_Quality := 60;
          ieImage.IO.Params.JPEG_ColorSpace := ioJPEG_YCbCr;

          // Generate a temp file name so there are no issues
          tmpFileName := CreateTmpFileName(tmpPath, 'tmpimg', '.jpg');
          // Save the temp file to the temp path
          ieImage.IO.SaveToFileJpeg(tmpPath + tmpFileName);

          // Blank the image to clear the canvas
          ieImage.Blank();

          // Add the image to the database
          try
            DMImage.SaveImage(TicketId, tmpPath + tmpFileName, ImgBottom_TypeId, ImgInfo_Info, ImgTop_ImgSeq, ImgFormat);
            if (ADelAfterImport) then
              ImgsToDel.Add(srcPath);
          except
            // The save failed ... remove the current image from iemImage
            iemImage.DeleteImage(newI);
            raise;
          end;

          DelFile(tmpPath + tmpFileName);
        end;

procedure TDMImage.SaveImage(TicketId, tmpFilePath, ImgBottom_TypeId, ImgInfo_Info: String; ImgTop_DocSeq: Integer; ImgFormat: TIOFileType);
var
  s: TStream;
  tmpIE: TImageEnView;
begin
  tmpIE := TImageEnView.Create(nil);
  fCNN.ShowWaiting('Saving images...', aviCopyFile);

  try
    tmpIE.IO.LoadFromFile(tmpFilePath, ImgFormat);
  except
    raise EError.Create('An error occurred loading a temporary file. Unable to save image, try again by importing images from Void/View.', 0, svWarning, False);
  end;

  if not (fCNN.InTransaction) then
  begin
    fCNN.StartTransaction;
    
    qryImages.Close;
    qryImages.SQL.Clear;
    qryImages.SQL.Add('select * from TICKET_IMAGE where Id = 0x' + StrToHex(Id));
    qryImages.Open;
    qryImages.Insert;

    s := qryImages.CreateBlobStream(qryImages.FieldByName('ImageData'), bmWrite);
    try
      try
        if (tmpIE.IO.SaveToStream(s, ImgFormat)) then
        begin      
          qryImages.FieldByName('Id').AsString := Id;
          qryImages.FieldByName('StoreId').AsInteger := StoreId;
          qryImages.FieldByName('ImgSeq').AsInteger  := ImgTop_DocSeq;
          qryImages.FieldByName('Info').AsString     := ImgInfo_Info;
          qryImages.FieldByName('TypeId').AsString   := GetImageTypeIdFromText(ImgBottom_TypeId);

          qryImages.Post;
          fCNN.Commit;
        end
        else
          ShowMessage('Failed to load image stream while attempting to save. Please try again.');
      except
        qryImages.Cancel;
        fCNN.Rollback;
        raise EError.Create('An error occurred while saving images. Try again or import images from Void/View.', 0, svWarning, False);
      end;
    finally
      s.Free;
      tmpIE.Free;
    end;
  end;

  fCNN.DisplayingMsg := False;
end;


Any suggestions you can provide would be helpful.

Thanks.
Go to Top of Page

xequte

39052 Posts

Posted - May 09 2021 :  22:23:34  Show Profile  Reply
Hi

The control will automatically free the TIEBitmap you pass to the OnImageIDRequestEx event, so you cannot use a TImageEnView.IEBitmap. You should create a temporary object instead.

Also, you can just read directly to the TIEBitmap:


procedure TForm1.ImgEnMvImageIDRequestEx(Sender: TObject; Index, ID: Integer; var Bitmap: TIEBitmap);
var
  s: TStream;
begin
  // todo: Position table at ID
  s := QryImages.CreateBlobStream(QryImages.FieldByName('ImageData'), bmRead);
  s.Position := 0;
  try
    try
      Bitmap := TIEBitmap.create;
      Bitmap.Read( s, ioJPEG );
    except 
      on e: Exception do
        Label1.Caption := 'An error occurred while loading image, Index: ' + IntToStr(Index) + ', ID: ' + IntToStr(ID) + ' Error:' + E.Message;
    end;
  finally
    s.Free;
  end;
end;


Nigel
Xequte Software
www.imageen.com
Go to Top of Page

hinsona

14 Posts

Posted - May 09 2021 :  23:07:13  Show Profile  Reply
I will give this a try. Thank you.
Go to Top of Page

hinsona

14 Posts

Posted - May 09 2021 :  23:21:39  Show Profile  Reply
This doesn't crash, but it loads the same image for every image.

https://i.imgur.com/A5hXce9.png
Go to Top of Page

xequte

39052 Posts

Posted - May 10 2021 :  01:02:21  Show Profile  Reply
Yes, note the TODO in the code above. You need to position your database at the correct id.

Nigel
Xequte Software
www.imageen.com
Go to Top of Page

hinsona

14 Posts

Posted - May 10 2021 :  01:12:47  Show Profile  Reply
Ah yes, that was the fix. I missed that, thank you.
Go to Top of Page
  Previous Topic Topic Next Topic  
 New Topic  Reply to Topic
Jump To: