Как показать бинарный контент переменной в виде изображения?

12 views
Skip to first unread message

Valentin

unread,
Aug 5, 2008, 11:19:12 AM8/5/08
to Russian Zope3 group
Добрый день.
Возможно, для гуру мой вопрос покажется тривиальным, тем не менее
ответа на него я пока не нашел. Есть метод, получающий по xml-rpc
бинарный контент png-файла, генерящегося вне Zope. Надо его вставить в
виде соответствующей картинки на странице. Как это организовать?

Ilshad

unread,
Aug 5, 2008, 12:27:46 PM8/5/08
to zope...@googlegroups.com
что-то вроде этого:

image = zope.app.file.image.Image(data)
id = ... выбираем имя
container[id] = image

возможно лучше сразу загонять в ks.smartimage, но здесь не подскажу.

5 августа 2008 г. 19:19 пользователь Valentin <pos...@pop3.ru> написал:



--
Ilshad Habibullin
Gadoz, Inc (http://www.gadoz.com)

Valentin

unread,
Aug 5, 2008, 1:42:29 PM8/5/08
to Russian Zope3 group

On 5 авг, 19:27, Ilshad <astoon....@gmail.com> wrote:
> image = zope.app.file.image.Image(data)
> id = ... выбираем имя
> container[id] = image

Если не затруднит, поясните - как впоследствии использовать этот
контейнер? Т.е. - как доступиться из html к его содержимому?

Ilshad

unread,
Aug 5, 2008, 2:55:26 PM8/5/08
to zope...@googlegroups.com
Хм... как обычно. id - знаем, т.е берем container/id.
Объект Image определает контент-тип (см код zope.app.file.image.Image), те об этом как бы не беспокоимся.

5 августа 2008 г. 23:42 пользователь Valentin <pos...@pop3.ru> написал:

Valentin

unread,
Aug 5, 2008, 3:10:39 PM8/5/08
to Russian Zope3 group

Прошу прощения, а нельзя ли чуть полнее? Я не могу понять - как мне в
html коде (или в шаблоне страницы) указать источник. Что писать вместо
<img src='....'>?

Ilshad

unread,
Aug 6, 2008, 3:18:04 AM8/6/08
to zope...@googlegroups.com
http://twiki.falkolab.ru/bin/view/Zope/ZPTPocketReference

6 августа 2008 г. 1:10 пользователь Valentin <pos...@pop3.ru> написал:

Valentin

unread,
Aug 6, 2008, 3:34:36 AM8/6/08
to Russian Zope3 group

> http://twiki.falkolab.ru/bin/view/Zope/ZPTPocketReference

попробовал таким образом:

(python)
a = zope.app.file.image.Image(b)
container['temp'] = a

(html)
<img src="container/temp">

получил ошибку:

File "/usr/local/www/Zope3/lib/python/zope/app/file/file.py", line
152, in _setData
seek = data.seek
AttributeError: Binary instance has no attribute 'seek'

Jorje Escobar

unread,
Aug 6, 2008, 4:03:50 AM8/6/08
to zope...@googlegroups.com
для объекта, в виде которого планируется показывать картинку можно написать траверсер:

class CaptchaTraverser(ContainerTraverser):
    """ """
    def publishTraverse(self, request, name):
        """See zope.publisher.interfaces.IPublishTraverse"""
        subob = self.context.get(name, None)
        if subob is None:
            view = queryMultiAdapter((self.context, request), name=name)
            if view is not None:
                return view
            else:
                 try:
                  image_factory = getUtility(IFactory, name="captcha.CaptchaImageFactory")
                    return image_factory(name)
                 except: pass

            raise NotFound(self.context, name, request)
        return subob

<view
    for="captcha.interfaces.ICaptchable"
    type="zope.publisher.interfaces.browser.IBrowserRequest"
    factory=".traverser.CaptchaTraverser"
    provides="zope.publisher.interfaces.browser.IBrowserPublisher"
    permission="zope.View"
    allowed_interface="zope.publisher.interfaces.browser.IBrowserPublisher"
/>


Здесь CaptchaImageFactory- утилита, которая создает объект IImage. В вашем случае, она получает его из xml-rpc.

class CaptchaImageFactory(object):
    implements(IFactory)
    def __call__(self,name):
        data = ... xml-rpc дергает там чего-то по имени name...
         image = CaptchaImage(data, 'image/png')
         return image

Объект zope.app.file.image.Image - персистентный. Соотв. надо написать свой:

class ICaptchaImage(IImage):
    pass

class CaptchaImage(object):
    implements(ICaptchaImage)
    def __init__(self, data='', contentType=''):
        self.data = data
        self.contentType, self._width, self._height = getImageInfo(data)
    def getImageSize(self):
        return (self._width, self._height)
    def getSize(self):
        return self.getImageSize()
у себя я добавлял еше     def write(self,data) def seek(self,offset) def tell(self) т.к. делал картинку PIL`ом

в итоге, в виде объекта, который реализует ICaptchable можно писать <img src="context/ имя, которое ждет xml-rpc"/>

Dmitry Vasiliev

unread,
Aug 6, 2008, 4:32:16 AM8/6/08
to zope...@googlegroups.com

Если URL для изображения статический и нужно просто менять само
изображение, то можно сделать так:

----- configure.zcml -----

<configure
xmlns="http://namespaces.zope.org/browser">

<page
for="zope.app.container.interfaces.IContainer"
name="image.jpg"
class=".views.ImageView"
permission="zope.View"
/>

</configure>

---------------------------

------ views.py -----

from zope.publisher.browser import BrowserView


class ImageView(BrowserView):

def __call__(self):
self.request.response.setHeader("Content-Type", "image/jpg")
return self.getRawImageData()

------------------------

Потом изображение можно запросить для любой папки как image.jpg,
например: http://localhost/image.jpg

Если нужно генерировать и разные имена картинок, то лучше всего делать
траверсер как здесь уже писали.

--
Dmitry Vasiliev (dima at hlabs.spb.ru)
http://hlabs.spb.ru

signature.asc

Valentin

unread,
Aug 6, 2008, 4:56:54 AM8/6/08
to Russian Zope3 group

> Если URL для изображения статический и нужно просто менять само
> изображение, то можно сделать так:

Спасибо Вами и Jorje Escobar за подробные ответы. К сожалению,
картинка не статичная.
Вот здесь:
http://old.itconnection.ru/pipermail/zopyrus/2002-August/065258.html
описан подход к решению аналогичной проблемы.
Он мне показался более простым, хотя его реализация тоже не совсем
ясна.
Можете прокомментировать ссылочку?

Dmitry Vasiliev

unread,
Aug 6, 2008, 8:52:21 AM8/6/08
to zope...@googlegroups.com

Там много сообщений, но что-то похожее на ответ только в одном как я
понял? :-) Предлагается сделать <img src="/show_pic?id=id_записи_в_БД">?
Можно сделать так, в этом случае нужно просто определить метод который
будет брать передаваемый id и в итоге возвращать данные изображения и
соответствующий тип контента как и в моем примере. Т.е если поменять
метод __call__ на вот такой:

def __call__(self, id):
content_type = self.getImageContentType(id)
self.request.response.setHeader("Content-Type", content_type)
return self.getRawImageData(id)

то можно будет запрашивать картинки вот так: :-)

http://localhost/image.jpg?id=image_id

Но на мой взгляд время URL в виде /скрипт?id=идентификатор_в_базе уже
ушло и намного удобнее и правильнее делать в виде
/идентификатор_в_базе.тип, тем более если используется компонентная
архитектура. Вот для этого в Z3 лучше всего использовать траверсер
который будет перехватывать запрос дочернего объекта по имени. Например,
если есть объект со списком пользователей красивее хранить картинки
пользователей привязанными к нему, чем привязанными к скрипту.

В целом это конечно вопрос компромисса между удобством для пользователя
и разработчика. URL вида peoples/getimage?id=id проще сделать, но он
менее красивый, в тоже время peoples/id.jpg красивее, но сделать чуть
сложнее. :-)

signature.asc

Jorje Escobar

unread,
Aug 6, 2008, 9:24:45 AM8/6/08
to zope...@googlegroups.com
получил ошибку:

 File "/usr/local/www/Zope3/lib/python/zope/app/file/file.py", line
152, in _setData
   seek = data.seek
AttributeError: Binary instance has no attribute 'seek'


Загляните в этот самый /usr/local/www/Zope3/lib/python/zope/app/file/file.py

  def _setData(self, data) :

        # Handle case when data is a string
        if isinstance(data, unicode):
            data = data.encode('UTF-8')

        if isinstance(data, str):
            self._data, self._size = FileChunk(data), len(data)
            return

        # Handle case when data is None
        if data is None:
            raise TypeError('Cannot set None data on a file.')

        # Handle case when data is already a FileChunk
        if isinstance(data, FileChunk):
            size = len(data)
            self._data, self._size = data, size
            return

        # Handle case when data is a file object
        seek = data.seek

Что то странное вы ему подсовываете.


 

Valentin

unread,
Aug 6, 2008, 9:38:11 AM8/6/08
to Russian Zope3 group

On 6 авг, 16:24, "Jorje Escobar" <tret...@gmail.com> wrote:
> > получил ошибку:
>
> >  File "/usr/local/www/Zope3/lib/python/zope/app/file/file.py", line
> > 152, in _setData
> >    seek = data.seek
> > AttributeError: Binary instance has no attribute 'seek'
>
> Загляните в этот самый /usr/local/www/Zope3/lib/python/zope/app/file/file.py
> Что то странное вы ему подсовываете.

В том-то и дело, что подсовывается ему туда вполне корректный бинарный
контент.
Если я его сохраняю в файл - получаю полноценный png, который можно
открыть.

Jorje Escobar

unread,
Aug 6, 2008, 9:47:40 AM8/6/08
to zope...@googlegroups.com


2008/8/6 Valentin <pos...@pop3.ru>:
такой?

11.22.4 Binary Objects
This class may be initialized from string data (which may include NULs). The primary access to the content of a Binary object is provided by an attribute:

data
The binary data encapsulated by the Binary instance. The data is provided as an 8-bit string.
Binary objects have the following methods, supported mainly for internal use by the marshalling/unmarshalling code:
 
decode(    string)     
Accept a base64 string and decode it as the instance's new data.
 
encode(    out)     
Write the XML-RPC base 64 encoding of this binary item to the out stream object.
It also supports certain of Python's built-in operators through a __cmp__() method.

Valentin

unread,
Aug 6, 2008, 10:00:22 AM8/6/08
to Russian Zope3 group

On 6 авг, 16:47, "Jorje Escobar" <tret...@gmail.com> wrote:
> 2008/8/6 Valentin <pos...@pop3.ru>:
> 11.22.4 Binary Objects
> This class may be initialized from string data (which may include NULs). The
> primary access to the content of a Binary object is provided by an
> attribute:
>
> data
> decode(    string)
> encode(    out)

Я прошу быть снисходительнее - Zope не является моим постоянным
инструментом.
Не могли бы вы более конкретно сказать, что я делаю не так?

Jorje Escobar

unread,
Aug 6, 2008, 10:10:31 AM8/6/08
to zope...@googlegroups.com
Это, по правде говоря, и не мой профиль. Но по моему все очевидно: zope.app.file.File жует либо str, либо unicode, либо FileChunk а вы запихиваете ему Binary.
(Binary instance has no attribute 'seek')

попробуйте
a = zope.app.file.image.Image(b.data)

2008/8/6 Valentin <pos...@pop3.ru>:

Valentin

unread,
Aug 6, 2008, 10:13:51 AM8/6/08
to Russian Zope3 group

On 6 авг, 17:10, "Jorje Escobar" <tret...@gmail.com> wrote:
> попробуйте
> a = zope.app.file.image.Image(b.data)

Если вы об этом, то я подобную форму уже пробовал.
Ошибки не возникает, но изображение не показывается.

Jorje Escobar

unread,
Aug 6, 2008, 10:29:24 AM8/6/08
to zope...@googlegroups.com


2008/8/6 Valentin <pos...@pop3.ru>:


если не увидите, посмотрите так:
http://localhost:8080/имя_контейнера/имя_картинки/@@introspector.html

ваша b.data долна быть там, под всевдонимом data (type: str)

Valentin

unread,
Aug 6, 2008, 2:05:45 PM8/6/08
to Russian Zope3 group

Большое спасибо Dmitry Vasiliev - его вариант решения оказался
полностью работоспособен.
Возможно, остальные предложения были не хуже, но то, что мне было
нужно - при минимальных трудозатратах
отобразить содержимое параметризуемого динамически генерирующегося
изображения - достигнуто.
Спасибо за сотрудничество и помощь.
Reply all
Reply to author
Forward
0 new messages