Author |
Topic |
|
stuartclennett@gmail.com
United Kingdom
72 Posts |
Posted - Oct 20 2016 : 11:49:03
|
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
|
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
|
|
|
stuartclennett@gmail.com
United Kingdom
72 Posts |
Posted - Oct 21 2016 : 05:19:47
|
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 |
|
|
stuartclennett@gmail.com
United Kingdom
72 Posts |
Posted - Oct 25 2016 : 05:05:40
|
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 |
|
|
xequte
38616 Posts |
Posted - Oct 26 2016 : 20:32:35
|
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
|
|
|
stuartclennett@gmail.com
United Kingdom
72 Posts |
Posted - Oct 27 2016 : 05:12:02
|
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 |
|
|
w2m
USA
1990 Posts |
Posted - Oct 27 2016 : 12:15:47
|
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 |
|
|
stuartclennett@gmail.com
United Kingdom
72 Posts |
Posted - Oct 27 2016 : 12:25:00
|
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 |
|
|
w2m
USA
1990 Posts |
Posted - Oct 27 2016 : 14:22:34
|
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 |
|
|
stuartclennett@gmail.com
United Kingdom
72 Posts |
Posted - Oct 27 2016 : 15:03:45
|
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 |
|
|
w2m
USA
1990 Posts |
Posted - Oct 27 2016 : 15:09:44
|
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 |
|
|
stuartclennett@gmail.com
United Kingdom
72 Posts |
Posted - Oct 27 2016 : 15:12:58
|
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 |
|
|
w2m
USA
1990 Posts |
Posted - Oct 27 2016 : 15:16:27
|
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 |
|
|
stuartclennett@gmail.com
United Kingdom
72 Posts |
Posted - Oct 27 2016 : 15:19:04
|
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 |
|
|
w2m
USA
1990 Posts |
Posted - Oct 27 2016 : 15:32:27
|
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 |
|
|
stuartclennett@gmail.com
United Kingdom
72 Posts |
Posted - Oct 28 2016 : 04:36:43
|
Thanks Bill - very useful information, I'll look into that.
Cheers
Stuart Clennett Delphi Berlin 10.1 |
|
|
|
Topic |
|