Python win32com and 2-dimensional arrays

荒凉一梦 提交于 2019-12-03 17:29:43

I encountered this same issue when trying to determine selection areas using win32com. I found that using comtypes rather than win32com to access photoshop solved the multidimensional array problem outright.

I believe that the one dimensional array problem is a limitation of win32com, but I may be wrong.

You can get comtypes here: http://sourceforge.net/projects/comtypes/

There is a post about this issue on Tech Artists Org which is worth a look through.

Here is an example of passing through an array using comtypes from the tech artist's forum post linked above. The implementation for path points should be similar.

import comtypes.client
ps_app = comtypes.client.CreateObject('Photoshop.Application') 
# makes a new 128x128 image
ps_app.Documents.Add(128, 128, 72)

# select 10x10 pixels in the upper left corner
sel_area = ((0, 0), (10, 0), (10, 10), (0, 10), (0, 0))
ps_app.ActiveDocument.Selection.Select(sel_area)

Here is a alternate solution that actually uses win32com module. It happens that the array type of Illustrator as well as Photoshop is a singe array of variant types. Where the variant type is also an array. There are also other applications like solidworks that use the same strategy. You can force win32com to make a variant type with the following code:

from win32com.client import VARIANT
from pythoncom import VT_VARIANT

def variant(data):
    return VARIANT(VT_VARIANT, data)

It would be convenient that one would not need to always type variant everywhere so you can just take a python array and make each sub element variants with:

import collections

def vararr(*data):
    if (  len(data) == 1 and 
          isinstance(data, collections.Iterable) ):
        data = data[0]
    return map(variant, data)

So finally my full code looks as follows:

from win32com.client import Dispatch, VARIANT
from pythoncom import VT_VARIANT
import collections


appObj = Dispatch("Illustrator.Application")  
docObj = appObj.Documents.Add()

def variant(data):
    return VARIANT(VT_VARIANT, data)

def vararr(*data):
    if (  len(data) == 1 and 
          isinstance(data, collections.Iterable) ):
        data = data[0]
    return map(variant, data)

pathItem = docObj.PathItems.Add()
pathItem.SetEntirePath( vararr( [0.0,0.0], [20.0,20.0] )  )

#or you can have a iterable of iterables
pathItem = docObj.PathItems.Add()
pathItem.SetEntirePath( vararr( [[30.0,10.0], [60.0,60.0]] )  )

Yes, this can be done with comtypes but this answers my the real question of how to do this in win32com. Besides there are reasons to use win32com, such as being able to generate constants. So after a long time I have finally found a answer to the question that really puzzled me. Hope this helps somebody.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!