Thursday 25 January 2018

arcgis desktop - ArcObjects/Python: Add JPG to layout


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:


enter image description here


However the IElement, which implements JpegPictureElement, does have a geometry: enter image description here


Explanation of Esri help symbols, they are in the documentation for Properties and Methods:


enter image description here


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: enter image description here


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

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...