Python win32com and 2-dimensional arrays

≯℡__Kan透↙ 提交于 2019-12-21 05:44:16

问题


When using python and win32com to automate the software form Adobe one encounters problem with passing arrays of 2d coordinates. If one looks at code that Adobe ships for visual basic (VB) its simple. A simplified example for drawing a line in Illustrator would look as follows:

Set appObj = CreateObject("Illustrator.Application")
Set docObj = appObj.Documents.Add

Set pathItem = docObj.PathItems.Add
    pathItem.SetEntirePath Array(Array(0.0, 0.0), Array(20.0, 20.0))

Now the naive assumption is that VB code could just just be turned into python by converting it as follows:

from win32com.client import Dispatch

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

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

Obviously, it's not that easy, python issues a error saying "Only arrays with dimension 1 are supported". Now i know that there's a difference between arrays of arrays and 2 dimensional arrays. So the question is how do i force python to make a array of the right kind?

I tried making my own VARIANT type but failed miserably. Ive also looked at ctypes for this. Anybody have had the same problem and could shed some light?

PS:

I am aware that the problem can be circumvented by using:

pathItem = docObj.PathItems.Add()
for point in (  [0.0,0.0], [20.0,20.0] ):
    pp = pathItem.PathPoints.Add() 
    pp.Anchor = point

But there are similar cases where this does not in fact work. Anyway the point is to write guidelines on porting to students so being as close to the original intent would be better.


回答1:


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)



回答2:


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.



来源:https://stackoverflow.com/questions/10166064/python-win32com-and-2-dimensional-arrays

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