2012-04-15 1 views
3

При использовании python и win32com для автоматизации формы программного обеспечения Adobe сталкивается с проблемой с передающими массивами координат 2d. Если вы посмотрите на код, который Adobe отправляет для визуального базового (VB), это просто. Упрощенный пример для рисования линии в Illustrator будет выглядеть следующим образом:Python win32com и 2-мерные массивы

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)) 

Теперь наивное предположение, что VB код может просто быть просто превратился в питон, преобразовывая его следующим образом:

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] ]) 

Очевидно , это не так просто, python выдает сообщение об ошибке «Поддерживаются только массивы с размером 1». Теперь я знаю, что существует разница между массивами массивов и двумерными массивами. Итак, вопрос в том, как заставить python создать массив нужного типа?

Я пробовал сделать свой собственный тип VARIANT, но неудачно провалился. Ive также посмотрел на ctypes для этого. У кого-то была такая же проблема и может пролить свет?

PS:

Я знаю, что эта проблема может быть преодолена с помощью:

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

Но есть подобные случаи, когда это на самом деле не работа. Во всяком случае, дело в том, чтобы написать рекомендации по портированию ученикам, чтобы быть ближе к первоначальному намерению.

ответ

2

Я столкнулся с этой проблемой при попытке определить области выделения с помощью win32com. Я обнаружил, что использование comtypes, а не win32com для доступа к фотошопу, решило проблему многомерного массива.

Я считаю, что проблема одномерного массива является ограничением win32com, но я могу ошибаться.

Вы можете получить comtypes здесь: http://sourceforge.net/projects/comtypes/

Существует пост об этой проблеме на Tech Artists Org, который стоит посмотреть до конца.

Вот пример прохождения массива с использованием comtypes из сообщения форума Tech Artist, связанного выше. Реализация для точек пути должна быть аналогичной.

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) 
+0

Да, это работает именно так, что я бы предпочел сделать это в win32com, потому что это то, что было отправлено на эти компьютеры по умолчанию. Ну, еще один месяц переговоров с ИТ-отделом, я полагаю. – joojaa

+0

Замечательно знать joojaa, спасибо за публикацию нового решения! – MrNoob

7

Вот альтернативное решение, которое фактически использует win32com модуль. Бывает, что тип массива Иллюстратор, а также Photoshop - это единый массив вариантов. Если тип варианта также является массивом. Существуют и другие приложения, такие как SolidWorks, которые используют ту же стратегию.Вы можете заставить win32com сделать тип варианта со следующим кодом:

from win32com.client import VARIANT 
from pythoncom import VT_VARIANT 

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

Было бы удобно, что не нужно будет всегда вводить вариант везде, так что вы можете просто взять массив питона и сделать каждый суб элемент варианты с :

import collections 

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

Итак, наконец, мой полный код выглядит следующим образом:

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]]) ) 

Да, это может быть сделано с comtypes, но это отвечает на мой реальный вопрос о том, как это сделать в win32com. Кроме того, есть причины использовать win32com, например, возможность генерации констант. Поэтому после долгого времени я наконец нашел ответ на вопрос, который действительно озадачил меня. Надеюсь, это поможет кому-то.