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
 Help with Annotations & Layers in a multi-user app
 New Topic  Reply to Topic
Author Previous Topic Topic Next Topic  

stuartclennett@gmail.com

United Kingdom
72 Posts

Posted - Oct 20 2016 :  11:49:03  Show Profile  Reply
Hi,

In my app, each image requires a set of annotations for each user. I need to save each set of annotations separately from each other, and separately from the (background) image. I also need to be able to toggle the visibility of each users set of annotations independently of each other.

I've got as far as creating a new layer (intUserLayer), setting it's transparency to zero, and adding new objects to that layer using ObJLayer[IEV_NEXT_INSERTED_OBJECT[ := intUserLayer;

I've also been able (I think) to save each set of objects to a filestream (ultimately will be into a database field) using code I found on here (sorry, lost the link to the topic). The code is:

fs := TFileStream.Create(fAnnotFilename, fmCreate);
  try
    for I := 0 to ImageEnVect1.ObjectsCount-1 do
    begin
      // gets an ObjectID from the index
      ihObj := ImageEnVect1.GetObjFromIndex(i);
      // if the ohObj is on the userlayer then save it
      iObjLayer := ImageEnVect1.ObjLayer[ihObj];
      if iObjLayer = intUserLayer then
        ImageEnVect1.SaveToStreamIEV(fs, ihobj);
    end;
  finally
    fs.Free;
  end;


I'm now trying to load the annotations back to the layer. I've used LoadFromSteamIEV and I've got the two following issues:

1) If I saved multiple annotations using the above code, i'm just getting multiple copies of the first annotation loaded back. In other words - if I add a line, ellipse & a box - Save - Load. I get 3 identical lines.

2) The annotations are not loaded back into the user's layer, but are loaded to the background image.

Am I approaching this the right way?

*Edit* It now seems that when the 3 annot objects are loaded, 2 are on the bg image, but 1 is on the layer. This is the loading code I'm using (files for now- it's based on your Vectorial demo app.

if dlgOpenImage.Execute then
  begin
    ImageEnVect1.IO.LoadFromFile(dlgOpenImage.FileName);
    fAnnotFileName := TPath.ChangeExtension(dlgOpenImage.FileName, '.annot');
    ImageEnVect1.LayersSync := TRUE; // must do this.
    intUserLayer := ImageEnVect1.LayersAdd;

    if fileExists(fAnnotFileName) then
    begin
      fs := TFileStream.Create(fAnnotFilename, fmOpenRead);
      try
        ImageEnVect1.ObjLayer[IEV_NEXT_INSERTED_OBJECT] := intUserLayer;
        ImageEnVect1.LoadFromStreamIEV(fs, TRUE);
      finally
        fs.free;
      end;
    end;

    ImageEnVect1.ObjLayer[IEV_NEXT_INSERTED_OBJECT] := intUserLayer;
    ImageEnVect1.Layers[intUserLayer].Transparency := 10;  // should be ZERO really


Thanks,
Stuart

Stuart Clennett
Delphi Berlin 10.1

xequte

38616 Posts

Posted - Oct 20 2016 :  18:28:29  Show Profile  Reply
Hi Stuart

1. Ensure that the AppendObjects parameter of LoadFromStreamIEV is set to false.

2. All objects will be loaded into the background layer.

(This is one of the reasons for the upcoming changes that will add vectorial layer support to TImageEnView, but that will be a long process).


Nigel
Xequte Software
www.xequte.com
nigel@xequte.com
Go to Top of Page

stuartclennett@gmail.com

United Kingdom
72 Posts

Posted - Oct 21 2016 :  05:19:47  Show Profile  Reply
Hi Nigel,

Thanks for getting back to me - this functionality is vital to my app.

> 2. All objects will be loaded into the background layer.

Think I can solve that by manually moving newly loaded objects into the correct layer.

> 1. Ensure that the AppendObjects parameter of LoadFromStreamIEV is set to false.

I've tried with TRUE _and_ FALSE, but I get the same results - namely multiple copies of the same annotation.

Here's my original, with annotations added to a single transparent layer:



Annotations saved to a separate file (as per above code). Restarted app, opened image & added the images back from the file using LoadFromStreamIEV(FileStream, FALSE) (see above for rest of the code)



Notice the grey ellipse - there's actually THREE ellipse there - as shown when I move them apart:



So perhaps you could tell me where I'm going wrong - either in the loading, or saving of the annotations.

The image and the annotations file created are here:

https://www.dropbox.com/s/ny0vyl7rxj4mxwn/ImageEn-CT%2BAnnots.zip?dl=0

As I said, ultimately, the annotations will be streamed to a database field, but this will suffice for a test :)

Look forward to hearing from you

Stuart




Stuart Clennett
Delphi Berlin 10.1
Go to Top of Page

stuartclennett@gmail.com

United Kingdom
72 Posts

Posted - Oct 25 2016 :  05:05:40  Show Profile  Reply
Hi,

Any progress on this issue?

Did you manage to replicate the problem?

Am I even on the right track with this?

Thanks

Stuart Clennett
Delphi Berlin 10.1
Go to Top of Page

xequte

38616 Posts

Posted - Oct 26 2016 :  20:32:35  Show Profile  Reply
Hi Stuart

Can you send me the code to reproduce this.

When I remove the unexpected layer code it works as expected:

if dlgOpenImage.Execute then
  begin
    ImageEnVect1.IO.LoadFromFile(dlgOpenImage.FileName);
    fAnnotFileName := TPath.ChangeExtension(dlgOpenImage.FileName, '.annot');

    if fileExists(fAnnotFileName) then
    begin
      fs := TFileStream.Create(fAnnotFilename, fmOpenRead);
      try
        ImageEnVect1.LoadFromStreamIEV(fs, TRUE);
      finally
        fs.free;
      end;
    end;




Nigel
Xequte Software
www.xequte.com
nigel@xequte.com
Go to Top of Page

stuartclennett@gmail.com

United Kingdom
72 Posts

Posted - Oct 27 2016 :  05:12:02  Show Profile  Reply
Hi Nigel,

Thanks for getting back to me.

I also tried removing all "layer" code, but the problem still persists - I save 3 different objects to a single file, then re-load and I have 3 copies of the first annotation. (As per screen shot 1 & 2 above)

The above download link for the image & saved annotations is still valid.

The project is just a small modification to your Annotations\Vectorial demo:

https://www.dropbox.com/s/8hvwq85jx4jw6ks/Annotions_Vectorial_Demo_Modified.zip?dl=0

When I load the annotations with this demo app from the above files, I still get this (3 identical ellipse) instead of the original 3 annotations (ellipse, box, memo):



I'd love to see what you get & how.

The lack of "layer" support isn't a showstopper, I guess it just means I won't be able to show all users annotations at the same time (which might not be such a bad thing)

But I do need to store & retrieve multiple sets of annotations for each image - i.e. one set per user. I'm still hoping to be able to show each set of annotations independently (or hide all, obvs)

However, I'd love to know where I'm going wrong with just the loading/saving right now.

Cheers :-)
Stu



Stuart Clennett
Delphi Berlin 10.1
Go to Top of Page

w2m

USA
1990 Posts

Posted - Oct 27 2016 :  12:15:47  Show Profile  Reply
Maybe you should try loading the objects from a iev file instead of a file stream? Loading objects this way works here.
iObjectsFilename := ChangeFileExt(iFilename, '.iev');
if FileExists(iObjectsFilename) then
begin
  ImageEnVect.LoadFromFileIEV(iObjectsFilename);
end;

Bill Miller
Adirondack Software & Graphics
Email: w2m@hughes.net
EBook: http://www.imageen.com/ebook/
Custom Commercial ImageEn Development
Go to Top of Page

stuartclennett@gmail.com

United Kingdom
72 Posts

Posted - Oct 27 2016 :  12:25:00  Show Profile  Reply
Thanks Bill, appreciate the input, but the filestream was just for testing, ultimately need to store annotations in the database.

I'll certainly give that a try just to see if it works differently from the LoadFromStreamIEV.

*UPDATE* I did try it, and it gave the same results, that is I create (for example) a line, box & ellipse and when I reopen the IEV file I get 4 lines.

To confirm, this is my save routine (using the File method not stream):



    strMsg := 'Annotation save log:';
    for I := 0 to ImageEnVect1.ObjectsCount-1 do
    begin
      // gets an ObjectID from the index
      ihObj := ImageEnVect1.GetObjFromIndex(i);
      ImageEnVect1.SaveToFileIEV(fAnnotFileName, ihObj);
      strMsg := strMsg + #13#10 + Format('Object %d saved.', [ihobj]);
    end;
    MessageDlg(strMsg, mtInformation, [mbOK], 0);


From this I get confirmation that objects 0,1 & 2 have been saved okay. Does this look okay?

Cheers,
Stuart

Stuart Clennett
Delphi Berlin 10.1
Go to Top of Page

w2m

USA
1990 Posts

Posted - Oct 27 2016 :  14:22:34  Show Profile  Reply
I did not use your demo, but without manipulating anything, the correct number of objects and object types are loaded correctly into the specified layer. I do not get your result!

When you save objects to a file I would just use ImageEnVect.SaveToFileIEV(iObjectsFilename);
If you want objects to appear on a specific layer then the ObjLayer must be set for each object as the object is loaded, so try using OnNewObject to achieve this.
procedure TForm1.ImageEnVectNewObject(Sender: TObject; hobj: Integer);
{ This event is executed whenever an new object is added }
begin
  ImageEnVect.ObjLayer[hobj] := ImageEnVect.LayersCurrent;
end;

That way if you load from a stream or a file the objects should appear in the correct layer.

I don't think the problem is a bug in ImageEn. You just have to set the ObjLayer for each object. That way you will not have to use code to change which layer the objects will appear on which may resolve your problem.

I hope this helps.

Bill Miller
Adirondack Software & Graphics
Email: w2m@hughes.net
EBook: http://www.imageen.com/ebook/
Custom Commercial ImageEn Development
Go to Top of Page

stuartclennett@gmail.com

United Kingdom
72 Posts

Posted - Oct 27 2016 :  15:03:45  Show Profile  Reply
Bill,

Thanks so much for your help.

I used SaveToStreamIEV(aFileStream) (ie without the hObj param) and then LoadFromStreamIEV(aFileStream) and, like you said it worked perfectly.

The problem lies when I try to loop through each object and save them to a stream or file.

I've been using this code from Nigel (http://www.imageen.com/ieforum/topic.asp?TOPIC_ID=1710) where he suggests using this to save only the objects that are on a specific layer.


  fs := TFileStream.Create(sFilename, fmCreate);
  for i := 0 to ImageEnVect1.ObjectsCount - 1 do
  begin
    ihobj := ImageEnVect1.GetObjFromIndex(i);
    // if hobj is on the specified layer then save it
    iobjLayer := ImageEnVect1.ObjLayer[ihobj];
    if iobjLayer = iLayerToSave then
      ImageEnVect1.SaveToStreamIEV(fs, ihobj);
  end;
  fs.free;


Admittedly, he says its untested in that topic, but I thought this might suit my requirements nicely. I.e. having each users set of annotations on a different layer to differentiate them.

Even if there's another way to differentiate the objects (apart from Layers), I'd still need a way to selectively save objects to a single stream? Is this possible?

Many thanks,

Stuart

PS : the OnNewObject event didn't seem to get triggered when using the LoadFromXxxxIEV methods -- however not a huge problem as its straight forward enough to loop through the loaded objects and place on the required layer. Useful to know though :-)


Stuart Clennett
Delphi Berlin 10.1
Go to Top of Page

w2m

USA
1990 Posts

Posted - Oct 27 2016 :  15:09:44  Show Profile  Reply
Maybe just use ImageEnVect1.SaveToStreamIEV(fs) without a loop because the ObjLayer has already been set when the file is loaded so it is not necessary to set it again when saving.

Bill Miller
Adirondack Software & Graphics
Email: w2m@hughes.net
EBook: http://www.imageen.com/ebook/
Custom Commercial ImageEn Development
Go to Top of Page

stuartclennett@gmail.com

United Kingdom
72 Posts

Posted - Oct 27 2016 :  15:12:58  Show Profile  Reply
Thanks Bill.

It looks like I might have to limit myself to a one-layer-at-a-time then.

I was hoping to have multiple layers simultaneously (representing multiple users) & thus saving objects selectively would be necessary.

Are you saying that's not possible?

Thanks again

Stuart Clennett
Delphi Berlin 10.1
Go to Top of Page

w2m

USA
1990 Posts

Posted - Oct 27 2016 :  15:16:27  Show Profile  Reply
I do not know. Get it working correctly first then you can try other techniques.

Bill Miller
Adirondack Software & Graphics
Email: w2m@hughes.net
EBook: http://www.imageen.com/ebook/
Custom Commercial ImageEn Development
Go to Top of Page

stuartclennett@gmail.com

United Kingdom
72 Posts

Posted - Oct 27 2016 :  15:19:04  Show Profile  Reply
Indeed. I shall press on with a simplified design and re-visit the issue later.

Thanks for your help
Stuart

Stuart Clennett
Delphi Berlin 10.1
Go to Top of Page

w2m

USA
1990 Posts

Posted - Oct 27 2016 :  15:32:27  Show Profile  Reply
ImageEnVectBeforeDrawObject is executed for each object even when loaded from a file so it should be called when using a stream as well:
procedure TForm1.ImageEnVectBeforeDrawObject(Sender: TObject; hobj: Integer; destination: TIEBitmap;
  destCanvas: TIECanvas; destRect: TRect; drawingAlpha: Boolean; var handled: Boolean);
begin
  ImageEnVect.ObjLayer[hobj] := ImageEnVect.LayersCurrent;
end;

Bill Miller
Adirondack Software & Graphics
Email: w2m@hughes.net
EBook: http://www.imageen.com/ebook/
Custom Commercial ImageEn Development
Go to Top of Page

stuartclennett@gmail.com

United Kingdom
72 Posts

Posted - Oct 28 2016 :  04:36:43  Show Profile  Reply
Thanks Bill - very useful information, I'll look into that.

Cheers

Stuart Clennett
Delphi Berlin 10.1
Go to Top of Page
  Previous Topic Topic Next Topic  
 New Topic  Reply to Topic
Jump To: