Skip to main content
Participating Frequently
October 11, 2023
Answered

Link associated with an image

  • October 11, 2023
  • 2 replies
  • 1445 views

I want to get, into my (C++)plugin the link associated with a selected image in an indd document

 

I tried following to achieve:

 

  • I tried to attach an observer with the associated kImageItem so that when the image is clicked the observer is called and I can get the image link from the subject associated. However the observer::update is never called when I select or click on the image. The code for attaching the observer:
 
InterfacePtr<ISubject> isb(pr, UseDefaultIID());
if (isb == nil) {
ASSERT("Null ISubject from kImageItem");
break;
}
isb->AttachObserver(this, IBooleanControlData::kDefaultIID);

 

  • I tried to extend (AddIn) by adding  IID_IEVENTHANDLER interface and wrote its implementer, however when I click on the image, the event handler is never called. The event handler code:

 

extension of kImageItem

------------------------------

AddIn
{
kImageItem,
kInvalidClass,
{

IID_IEVENTHANDLER, kImageItemEventHandlerImpl,
}
},

 

Event Handletr Implementation

-----------------------------------------

class WFPImageItemEV : public CEventHandler
{
public:
 
/** Constructor.
@9397041 boss interface ptr on the boss object to which the interface implemented here belongs.
*/
WFPImageItemEV(IPMUnknown* boss);
 
/** Destructor
*/
virtual ~WFPImageItemEV(){}
 
virtual bool16 LButtonDn(IEvent* e); // { bool16 retval; InterfacePtr<IEventHandler> delegate(this, IID_IPNLTRVSHADOWEVENTHANDLER);  retval = delegate->LButtonDn(e);  return retval; }
 
};
 
/* CREATE_PMINTERFACE
 Binds the C++ implementation class onto its ImplementationID 
 making the C++ code callable by the application.
*/
 
CREATE_PMINTERFACE(WFPImageItemEV, kImageItemEventHandlerImpl)
 
 
WFPImageItemEV::WFPImageItemEV(IPMUnknown* boss) :
CEventHandler(boss)
{
 
}
 
bool16 WFPImageItemEV::LButtonDn(IEvent* e) {
bool16 retval = kTrue;
PMString s1 = "LButtonDn";
do {
InterfacePtr<IPanelControlData> panelData(this, IID_IPANELCONTROLDATA);
if (panelData == nil)
{
ASSERT_FAIL("IPanelControlData is invalid");
retval = kFalse;
break;
}
uint32 ln = panelData->Length();
IControlView* panelControlView = panelData->GetWidget(0);
 
} while (kFalse);
return retval;
}

 

  • I tried using IImageObjectSuite selection suite to get the graphics item associated with it but it doesn't give me the function GetGraphicItem (UIDRef &itemUIDRef) returns Failure (ErrorCode = 1), The code is as below:

ISelectionManager* sm = Utils<ISelectionUtils>()->GetActiveSelection();
InterfacePtr<IImageObjectSuite> ios(sm, UseDefaultIID());
UIDRef gi;
ErrorCode ec = ios->GetGraphicItem(gi);

 

My goal is to get the link associated with the image when I click on it or select it.

 

Kindly help.

 

This topic has been closed for replies.
Correct answer Rahul_Rastogi

Assuming you have got the UIDRef of kSplineItemBoss -

 

InterfacePtr<ILinkManager> iLinkManager(docRef, UseDefaultIID());

 

InterfacePtr<IHierarchy> iFrameHierarchy(frameRef, UseDefaultIID());

 

// below line get the iHierarchy of kImageItem or kEPSItem depending upon content is image or eps or pdf.

InterfacePtr<IHierarchy> iChildHierarchy(frameHier->QueryChild (0) );

 

InterfacePtr<ILinklObject> iLinkObject(iChildHierarchy, UseDefaultIID());

 

UIDList linkList(docRef.GetDataBase());
iLinkManager->QueryLinksByObjectUID(::GetUID(iChildHierarchy), linkList);
InterfacePtr<ILink> iLink (linkList.GetRef(0),UseDefaultIID());

 

InterfacePtr<ILinkResource> iLinkResource(iLinkManager->QueryResourceByUID(iLink->GetResource()));

 

PMString strFilePath  = iLinkResource->GetLongName(kFalse);

 

Now strFilePath contains the full path of the linked image. You can retrieve the image name from it.

 

- Rahul Rastogi

Adobe InDesign C++ Plugin Architect

2 replies

Inspiring
October 12, 2023

As Dirk Becker mentioned - your approach is wrong.

 

1. Implement ActiveSelectionObserver.

Search the Frame Label Sample code and you would see that if frame is selected then panel is updated showing the frame label. 

 

This will solve the problem of selection.

 

2. You might need to implement SelectionSuite, to get the UIDRef of the underlying selection.

Once you have the UIDRef of the frame, then detect whether it is text frame or graphic frame. If graphic frame then proceed to find the link.

 

- Rahul Rastogi

 Adobe InDesign SDK C++ Plugin Development Architect

Participating Frequently
October 12, 2023

Thanx Rahul for your answer.

 

It seems I have not made question clear. By "link associated with the image" I meant the name of  the image file from which the image was inserted. see the image below for reference:

 

 

 

I am able to get the UIDRef of the selected image which is UIDRef of the undelying kSplineItemBoss. From the kSplineItemBoss I get the kImageItem. From kItemBoss I get IImageAttributes assuming atleast one of the tags : kPMTagDocumentName = 104, // TYPE: array null terminated string

 OR

kPMTagOPIImageID = 121, // TYPE: array Full path name of original high-res image

 

will have the name of the file. But none of this tags are present when I get IImageAttributes.

 

How do I get the file name of the image, given that I have the UIDref of the selected image(underlying kSplineItemBoss)?

Rahul_RastogiCorrect answer
Inspiring
October 13, 2023

Assuming you have got the UIDRef of kSplineItemBoss -

 

InterfacePtr<ILinkManager> iLinkManager(docRef, UseDefaultIID());

 

InterfacePtr<IHierarchy> iFrameHierarchy(frameRef, UseDefaultIID());

 

// below line get the iHierarchy of kImageItem or kEPSItem depending upon content is image or eps or pdf.

InterfacePtr<IHierarchy> iChildHierarchy(frameHier->QueryChild (0) );

 

InterfacePtr<ILinklObject> iLinkObject(iChildHierarchy, UseDefaultIID());

 

UIDList linkList(docRef.GetDataBase());
iLinkManager->QueryLinksByObjectUID(::GetUID(iChildHierarchy), linkList);
InterfacePtr<ILink> iLink (linkList.GetRef(0),UseDefaultIID());

 

InterfacePtr<ILinkResource> iLinkResource(iLinkManager->QueryResourceByUID(iLink->GetResource()));

 

PMString strFilePath  = iLinkResource->GetLongName(kFalse);

 

Now strFilePath contains the full path of the linked image. You can retrieve the image name from it.

 

- Rahul Rastogi

Adobe InDesign C++ Plugin Architect

Legend
October 11, 2023

There are plenty things wrong here. Welcome to a different world.

 

As a rough concept, an observer is notified for changes within or close to a particular object. So you'd watch for some very special aspect of a single page item, e.g. its attribute or its position (geometric bounds), or when it gets associated with a different link.

 

With your approach you'd have to attach such an observer to every single of the 10.000 images within the publication / document. Won't work. Instead, typical page item notifications are also notified at the document object itself. But only, when the item itself changes.

 

If you select an image, most of the time you actually select the enclosing page item which is a spline item. You'd use the direct selection tool (the other arrow) to select the image, likely you do not want that limitation.

 

Then, this is about the selection. A very different thing than the actual image. Your observer should observe the selection rather than the page item. Search the SDK for SelectionObserver, it is a bit complicated to even follow the selection across multiple windows of the same document, or other documents, or no document at all.

 

Your other approach to add an event handler is a no-go, as neither the image item boss nor the interface are yours. There can be only one implementation for an interface, that becomes part of the overall object. This is unlike scripting where any object can accept a ton of separate event listeners. Anyway, event handlers are far too lo level, forget about them. You would not want to decode the mouse click on an image to back-guess that it might have something to do with selection. That mouse click would get decoded in a far different object.

 

Let's return to the selection though. InDesign's selection is an abstraction. You might have selected no item, one, or a multitude of them. Different ones - text frames, form fields at the same time. Within the structure selection (aka XML) you might have a selection across many pages. Text frames, via their story, can also have a link.

To correctly participate in the selection, you have to think about those cases. You ask the selection to get its (in your case: image link), in an abstract way, and it deals about it in all the different concrete cases.

E.g. you have a text selection with three anchored image anchored somewhere within character 200 and 399, would you consider their links?

 

Also there are more kinds of images - as you mention kImageItem but omit PDF, EPS, WMF and so forth. What do you want to see, and later on what do you want to modify, when there are multiple images selected. Or if only one page item is selected that happens to be a group of 10 spline items which all enclose a different kind of image.

 

This concept of an abstract selection with different concrete implementations is expressed by a suite, as you already have found one. It is not meant though to just pass you the selection and let you work on that from outside. If you want to work on details, you have to implement your own suite. Define how they are aggregated across the multi-selection (even if that to you just means to give up and show blank) of each concrete selection's target. There you'd also handle the cases of these nested images (group, anchored etc.).

 

Finally, as you say "my goal … when I click or select it" - the click is a different beast. E.g. you can have an image locked (see layer panel) so not selectable, but use the eyedropper tool to pick up some attributes from it. That would be a click. A link-peeker could even display the link below it on mouse-over. Completely different subsystem, and somewhere closer to an event handler. Do you really want that?

Participating Frequently
October 12, 2023

Thanx Dirk for a detailed answer. Will get back to you if I have any questions.