I am building a plugin that allows a user to place graphic assets from our own external asset management system into their InDesign document. These assets need to maintain a "custom link" to the external assets.
Everything was working great for simple raster image formats (like JPEG) but the custom link information seems to get lost for EPS files.
After doing some deep debugging I decided to try building one of the sample plugins that ship with CS5 - 'customdatalink' and the accompanying 'customdatalinkui'. This sample does a similar type of thing with CSV files that reference external assets.
To make a long story short, the sample plugin exhibits the exact same behavior. If you edit one of the sample csv files to point to an EPS image and place that in a document, you'll see that the Link URI is replaced with a file:// style path instead of the custom csv:// URI. It works as expected for JPEG files.
Surely this is not expected behavior. Am I missing something obious here or is this a simple (but pretty major for my plugin) bug?
Thanks in advance for any assistance.
p.s. this behavior is identical on both Mac and Windows.
I had this problem too with CS4 and I assume that it's the same with CS5. It's complicated why it happens to EPS files but it's because the weird way the EPS importer works. If I remember correctly it's because the importer sees that the IPMStream boss includes an IID_IFILESTREAMDATA and creates it's own link resource. The link then ends up with 2 link resources.
You will need to change your ILinkResourceHandler::CreateResourceReadStream to return your own IPMStream when dealing with EPS files. I know it's wacked but what about custom links, especially handling InCopy files, isn't..? You can just make your stream a proxy for a real IPMStream and since your stream dosen't include an IID_IFILESTREAMDATA you won't get the double link resource issue.
Wauw thanks! This really helped! In stead of the CreateFileStreamReadLazy I used the CreatePointerStreamRead and passed a pointer to the image in memory. This works great for EPS files. I never expected the IID_IFILESTREAMDATA to give those problems ... I'm very glad this solved it for me.
Hi Doug,
Thanks so much for your suggestion, and it seems you're definitely on to something. I'm a bit concerned about reading the entire EPS file into memory as Erik did, since our EPS files can be quite large. Is that my only option or is there another way to create the IPMStream myself from a file without including an IID_IFILESTREAMDATA?
Here is the current implementation from StreamUtils:
IPMStream *StreamUtil::CreateFileStreamReadLazy(const SysFile& sysFile, uint32 mode , OSType fileType , OSType creator)
{
return CreateFileStreamLazy(kFileStreamReadBoss, sysFile, mode, fileType, creator);
}
IPMStream *CreateFileStreamLazy(ClassID clsID, const SysFile& sysFile, uint32 mode , OSType fileType , OSType creator)
{
IPMStream *s = static_cast<IPMStream *>(::CreateObject(clsID, IID_IPMSTREAM));
InterfacePtr<IFileStreamData> data(s, IID_IFILESTREAMDATA);
data->Set(sysFile, mode, fileType, creator);
return s;
}
Here's a bit more detail. Again the idea is to return an IPMStream that doesn't include a IID_IFILESTREAMDATA. So I make a proxy IPMStream that just forwards requests to a real IPMStream.
I've abbreviated a bit here for space reasons.
So I make my own IPMStream object adding the class to my .fr file:
class FileProxyWriteStream : public CPMUnknown<IPMStream>
{
public:
FileProxyWriteStream(IPMUnknown* boss);
virtual ~FileProxyWriteStream();
void SetRealStream(IPMStream *, AeInDesignGeo *);
virtual uchar XferByte(uchar& chr) { return mRealStream->XferByte(chr); }
... all IPMStream methods
};
Create my proxy stream:
proxyStream = ::CreateObject2<IPMStream>(kFileProxyWriteStreamBoss, IID_IPMSTREAM);
And I create a IPMStream:
InterfacePtr<IPMStream> realStream(StreamUtil::CreateFileStreamReadLazy(file, kOpenIn));
Tell my proxyStream about the realStream
proxyStream->SetRealStream(proxyStream);
and CreateResourceReadStream returns my proxyStream
Hope this helps
-doug
Doug,
Thanks so much for the detailed response. I seem to have things working properly now.
My implementation of CreateResourceReadStream() now looks something like this:
IPMStream *proxyStream = ::CreateObject2<IPMStream>(kFileProxyWriteStreamBoss, IID_IPMSTREAM);
InterfacePtr<IPMStream> realStream(StreamUtil::CreateFileStreamReadLazy(file, kOpenIn));
((FileProxyWriteStream*)proxyStream)->SetRealStream(realStream);
realStream.forget();
return proxyStream;
My knowledge of InDesign SDK programming is very minimal - I am simply working on fixing some bugs in a plugin that was developed by somebody else. I just want to be sure I'm not going to be introducing any unintended memory leaks by doing things the way I have done them.
Thanks again. You are a life saver!
One more thing I've noticed:
This solution doesn't appear to work when placing INDD files. I had previously had similar problems with both EPS and INDD files - the custom links were not being preserved.
EPS now works but when I try to use the above technique with INDD files, I get an error in the debugger:
NativeImportFilter: can only import from file
Are you guys having similar problems placing INDD files?
Thanks again.
North America
Europe, Middle East and Africa
Asia Pacific