I am attempting (and failing) to add an image to a map layout using ArcObjects via Python comtypes. I do need to run this outside of ArcMap (i.e. not in the ArcMap Python window).
The basic idea is: open mxd, place jpg in layout, save/close mxd.
Python solution preferred, but I would also accept a similar workflow in VB.NET.
Using ArcGIS 10.2.2, Python 2.7.5
Script:
from comtypes.client import GetModule, CreateObject
from Snippets import GetLibPath, InitStandalone
def CType(obj, interface):
"""Casts obj to interface and returns comtypes POINTER or None"""
try:
newobj = obj.QueryInterface(interface)
return newobj
except:
return None
def main():
InitStandalone()
modCarto = GetModule(r"C:\Program Files (x86)\ArcGIS\Desktop10.2\com\esriCarto.olb")
modGeom = GetModule(r"C:\Program Files (x86)\ArcGIS\Desktop10.2\com\esriGeometry.olb")
modArcMapUI = GetModule(r"C:\Program Files (x86)\ArcGIS\Desktop10.2\com\esriArcMapUI.olb")
modFramework = GetModule(r"C:\Program Files (x86)\ArcGIS\Desktop10.2\com\esriFramework.olb")
app = CreateObject(modFramework.AppROT, interface=modFramework.IAppROT)
mxDoc = CType(app.Item(0).Document,modArcMapUI.IMxDocument)
layout = mxDoc.PageLayout
graphicContainer = CType(layout, modCarto.IGraphicsContainer)
pictureElement = CreateObject(modCarto.JpgPictureElement, interface=modCarto.IPictureElement)
envelope = CreateObject(modGeom.Envelope, interface=modGeom.IEnvelope)
envelope.PutCoords(0, 0, 5, 5)
pictureElement.Geometry = envelope
pictureElement.ImportPictureFromFile(r'C:\junk\happy.jpg')
iElement = CType(pictureElement,modCarto.IElement)
graphicContainer.AddElement(pictureElement,0) # ERROR HERE
#graphicContainer.AddElement(iElement,0)
app.Item(0).SaveDocument()
if __name__ == '__main__':
main()
Traceback (whether attempting to add pictureElement or iElement):
Traceback (most recent call last):
File "C:\Scripts\arcobjects_add_jpeg.py", line 54, in
main()
File "C:\Scripts\arcobjects_add_jpeg.py", line 47, in main
graphicContainer.AddElement(pictureElement,0)
COMError: (-2147024809, 'The parameter is incorrect.', (None, None, None, 0, None))
Full disclosure: I am absolutely new with ArcObjects, so whether or not I am handling/creating/juggling objects between interfaces correctly, I am not sure, but I think I'm close.
Answer
The Esri help can be quite counter-intuitive, you need to know what you're searching for to get the description...
The issue here is that the pictureElement doesn't have a geometry property.. see the Help page for picture element:
However the IElement, which implements JpegPictureElement, does have a geometry:
Explanation of Esri help symbols, they are in the documentation for Properties and Methods:
This is from the Esri help, methods do something and properties are values in/of the object. These symbols are very important, especially when you're getting frustrated trying to set values on an object only to find that they're read only. In this case you can get the SelectionTracker but you cannot set it, conversely you can update or retrieve the Geometry 'value' of the object.
But the only way to tell if you can make a JpegPictureElement into an IElement is on the IElement help page in the CoClasses that implement IElement:
This tells you that any of the listed CoClasses can be cast into an IElement, if it's not on the list you will get an error if you try to cast. For example IFeature
isn't on the list so if you try iElement = CType(myFeature,modCarto.IElement)
it will fail!
The correct order to do this in is:
pictureElement.ImportPictureFromFile(r'C:\junk\happy.jpg') # populate the JpegPictureElement
iElement = CType(pictureElement,modCarto.IElement) # convert JpegPictureElement into IElement
iElement.Geometry = envelope # set the geometry
graphicContainer.AddElement(iElement,0) # add to frame
No comments:
Post a Comment