[GRASS-dev] python data object graphic output?

With the revamp of the GRASS graphic driver output system, I’m wondering about the feasibility of having a driver that creates a Python data object rather than a disk file. While this might not create noticeable speed improvements in rendering displays in a Python canvas, it could considerably simplify coding for overlaying and rendering multiple geospatial data layers–especially if we can do the compositing and rendering with Python tools rather than g.pnmcomp.

Michael


C. Michael Barton, Professor of Anthropology
Director of Graduate Studies
School of Human Evolution & Social Change
Center for Social Dynamics & Complexity
Arizona State University

Phone: 480-965-6262
Fax: 480-965-7671
www: <www.public.asu.edu/~cmbarton>

Michael Barton wrote:

With the revamp of the GRASS graphic driver output system, I'm
wondering about the feasibility of having a driver that creates a
Python data object rather than a disk file.

Can you elaborate?

Specifically, how is the data supposed to be transferred from the d.*
command to the GUI?

While this might not
create noticeable speed improvements in rendering displays in a Python
canvas, it could considerably simplify coding for overlaying and
rendering multiple geospatial data layers--especially if we can do the
compositing and rendering with Python tools rather than g.pnmcomp.

Even with the modules writing image files, the compositing step really
should be performed within Python, rather than using an external
process (g.pnmcomp). This would mean that enabling or disabling layers
or changing the translucency level would happen instantly.

AFAICT, wx itself doesn't have code for this, although there may be
third-party libraries which do. GDK has compositing code which can use
SSE; it may be worth taking that (if someone hasn't already).

Better still, if you use cairo, it should be possible to have the
graphics hardware perform the compositing.

The cairo driver has support for using an X Pixmap for its output (via
GRASS_CAIRO_DRAWABLE and GRASS_CAIRO_VISUAL). Not only would this
eliminate the need to copy data to/from disk (or even between
processses), but the d.* command can use the graphics hardware.

--
Glynn Clements <glynn@gclements.plus.com>

On Aug 12, 2008, at 3:22 PM, Glynn Clements wrote:

Michael Barton wrote:

With the revamp of the GRASS graphic driver output system, I'm
wondering about the feasibility of having a driver that creates a
Python data object rather than a disk file.

Can you elaborate?

Specifically, how is the data supposed to be transferred from the d.*
command to the GUI?

A couple new modules seem promising in this regard:

BitmapFromBuffer:

"Two new wx.Bitmap factory functions allow you to create a wx.Bitmap directly from a data buffer. The the buffer can be any Python object that implements the buffer interface, or is convertable to a buffer, such as a string or an array. The new functions are:

wx.BitmapFromBuffer(width, height, dataBuffer, alphaBuffer=None): Creates the bitmap from a buffer of RGB bytes, optionally with a separate buffer of alpha bytes.

wx.BitmapFromBufferRGBA(width, height, dataBuffer): Creates the bitmap from a buffer containing RGBA bytes. "

ImageFromStream:

"At long last there is finally a way to load any supported image type
directly from any Python file-like object, such as a memory buffer
using StringIO."

Both seem to allow python data objects, rather than files to be the source of bitmaps for display

While this might not
create noticeable speed improvements in rendering displays in a Python
canvas, it could considerably simplify coding for overlaying and
rendering multiple geospatial data layers--especially if we can do the
compositing and rendering with Python tools rather than g.pnmcomp.

Even with the modules writing image files, the compositing step really
should be performed within Python, rather than using an external
process (g.pnmcomp). This would mean that enabling or disabling layers
or changing the translucency level would happen instantly.

AFAICT, wx itself doesn't have code for this, although there may be
third-party libraries which do. GDK has compositing code which can use
SSE; it may be worth taking that (if someone hasn't already).

It seems like the new GraphicContext does this:

"The new advanced 2D drawing API is implemented via the wx.GraphicsContext and wx.GraphicsPath classes. They wrap GDI+ on Windows, Cairo on wxGTK and CoreGraphics on OS X. They allow path-based drawing with alpha-blending and anti-aliasing, and use a floating point cooridnate system.
When viewing this sample pay attention to how the rounded edges are smoothed with anti-aliased drawing, and how the shapes on the lower half of the window are partially transparent, allowing you to see what was drawn before."

Better still, if you use cairo, it should be possible to have the
graphics hardware perform the compositing.

The cairo driver has support for using an X Pixmap for its output (via
GRASS_CAIRO_DRAWABLE and GRASS_CAIRO_VISUAL). Not only would this
eliminate the need to copy data to/from disk (or even between
processses), but the d.* command can use the graphics hardware.

This also sounds promising if it could be implemented from the Python GUI.

Michael

--
Glynn Clements <glynn@gclements.plus.com>

Michael Barton wrote:

>> With the revamp of the GRASS graphic driver output system, I'm
>> wondering about the feasibility of having a driver that creates a
>> Python data object rather than a disk file.
>
> Can you elaborate?
>
> Specifically, how is the data supposed to be transferred from the d.*
> command to the GUI?

A couple new modules seem promising in this regard:

BitmapFromBuffer:

"Two new wx.Bitmap factory functions allow you to create a wx.Bitmap
directly from a data buffer. The the buffer can be any Python object
that implements the buffer interface, or is convertable to a buffer,
such as a string or an array. The new functions are:

wx.BitmapFromBuffer(width, height, dataBuffer, alphaBuffer=None):
Creates the bitmap from a buffer of RGB bytes, optionally with a
separate buffer of alpha bytes.

wx.BitmapFromBufferRGBA(width, height, dataBuffer): Creates the bitmap
from a buffer containing RGBA bytes. "

ImageFromStream:

"At long last there is finally a way to load any supported image type
directly from any Python file-like object, such as a memory buffer
using StringIO."

Both seem to allow python data objects, rather than files to be the
source of bitmaps for display

That's all well and good, but how is the d.* command supposed to get
the data into the wxgui process if not through a file?

>> While this might not
>> create noticeable speed improvements in rendering displays in a
>> Python
>> canvas, it could considerably simplify coding for overlaying and
>> rendering multiple geospatial data layers--especially if we can do
>> the
>> compositing and rendering with Python tools rather than g.pnmcomp.
>
> Even with the modules writing image files, the compositing step really
> should be performed within Python, rather than using an external
> process (g.pnmcomp). This would mean that enabling or disabling layers
> or changing the translucency level would happen instantly.
>
> AFAICT, wx itself doesn't have code for this, although there may be
> third-party libraries which do. GDK has compositing code which can use
> SSE; it may be worth taking that (if someone hasn't already).

It seems like the new GraphicContext does this:

"The new advanced 2D drawing API is implemented via the
wx.GraphicsContext and wx.GraphicsPath classes. They wrap GDI+ on
Windows, Cairo on wxGTK and CoreGraphics on OS X. They allow path-
based drawing with alpha-blending and anti-aliasing, and use a
floating point cooridnate system.
When viewing this sample pay attention to how the rounded edges are
smoothed with anti-aliased drawing, and how the shapes on the lower
half of the window are partially transparent, allowing you to see what
was drawn before."

Well, drawing operations don't actually matter, as that is done within
the d.* command via cairo. The ability to perform blending internally
is the main issue.

> Better still, if you use cairo, it should be possible to have the
> graphics hardware perform the compositing.
>
> The cairo driver has support for using an X Pixmap for its output (via
> GRASS_CAIRO_DRAWABLE and GRASS_CAIRO_VISUAL). Not only would this
> eliminate the need to copy data to/from disk (or even between
> processses), but the d.* command can use the graphics hardware.

This also sounds promising if it could be implemented from the Python
GUI.

That depends upon whether wx allows you to use a Pixmap as the source
for blending operations. If it's a wrapper around cairo, it should
work. The main issue is that it needs to keep the data within the X
server (which will keep it in video memory if possible).

--
Glynn Clements <glynn@gclements.plus.com>

On Aug 12, 2008, at 10:24 PM, Glynn Clements wrote:

Michael Barton wrote:

With the revamp of the GRASS graphic driver output system, I'm
wondering about the feasibility of having a driver that creates a
Python data object rather than a disk file.

Can you elaborate?

Specifically, how is the data supposed to be transferred from the d.*
command to the GUI?

A couple new modules seem promising in this regard:

BitmapFromBuffer:

"Two new wx.Bitmap factory functions allow you to create a wx.Bitmap
directly from a data buffer. The the buffer can be any Python object
that implements the buffer interface, or is convertable to a buffer,
such as a string or an array. The new functions are:

wx.BitmapFromBuffer(width, height, dataBuffer, alphaBuffer=None):
Creates the bitmap from a buffer of RGB bytes, optionally with a
separate buffer of alpha bytes.

wx.BitmapFromBufferRGBA(width, height, dataBuffer): Creates the bitmap
from a buffer containing RGBA bytes. "

ImageFromStream:

"At long last there is finally a way to load any supported image type
directly from any Python file-like object, such as a memory buffer
using StringIO."

Both seem to allow python data objects, rather than files to be the
source of bitmaps for display

That's all well and good, but how is the d.* command supposed to get
the data into the wxgui process if not through a file?

p = subprocess.Popen(['d.rast', 'map=myraster'], stdout=subprocess.PIPE)
data = p.stdout

While this might not
create noticeable speed improvements in rendering displays in a
Python
canvas, it could considerably simplify coding for overlaying and
rendering multiple geospatial data layers--especially if we can do
the
compositing and rendering with Python tools rather than g.pnmcomp.

Even with the modules writing image files, the compositing step really
should be performed within Python, rather than using an external
process (g.pnmcomp). This would mean that enabling or disabling layers
or changing the translucency level would happen instantly.

AFAICT, wx itself doesn't have code for this, although there may be
third-party libraries which do. GDK has compositing code which can use
SSE; it may be worth taking that (if someone hasn't already).

It seems like the new GraphicContext does this:

"The new advanced 2D drawing API is implemented via the
wx.GraphicsContext and wx.GraphicsPath classes. They wrap GDI+ on
Windows, Cairo on wxGTK and CoreGraphics on OS X. They allow path-
based drawing with alpha-blending and anti-aliasing, and use a
floating point cooridnate system.
When viewing this sample pay attention to how the rounded edges are
smoothed with anti-aliased drawing, and how the shapes on the lower
half of the window are partially transparent, allowing you to see what
was drawn before."

Well, drawing operations don't actually matter, as that is done within
the d.* command via cairo. The ability to perform blending internally
is the main issue.

Normally the 'drawing' includes rendering raster images. Transparency is set via alpha values. There is no problem with 'drawing' overlayed images in Python. We already do it with the scale and legend.

Better still, if you use cairo, it should be possible to have the
graphics hardware perform the compositing.

The cairo driver has support for using an X Pixmap for its output (via
GRASS_CAIRO_DRAWABLE and GRASS_CAIRO_VISUAL). Not only would this
eliminate the need to copy data to/from disk (or even between
processses), but the d.* command can use the graphics hardware.

This also sounds promising if it could be implemented from the Python
GUI.

That depends upon whether wx allows you to use a Pixmap as the source
for blending operations. If it's a wrapper around cairo, it should
work. The main issue is that it needs to keep the data within the X
server (which will keep it in video memory if possible).

Is this relevant for Windows? Workable for Mac without running x11?

Michael

--
Glynn Clements <glynn@gclements.plus.com>

Michael Barton wrote:

> That's all well and good, but how is the d.* command supposed to get
> the data into the wxgui process if not through a file?

p = subprocess.Popen(['d.rast', 'map=myraster'], stdout=subprocess.PIPE)
data = p.stdout

A file will typically be quicker. With a pipe, unless the reader reads
it all in one go, you get a context switch for every PIPE_BUF bytes.

Also, the PNG and cairo drivers support using an mmap()ed BMP file as
the frame buffer; if both sides map the file, you eliminate a copy.

But the best case for speed will be keeping everything in video
memory, i.e. using pixmaps. If you use the GPU for rendering, the
output ends up in video memory, so if you want it anywhere else, you
have to copy it from there (reading video memory is often signficantly
slower than writing to it, or than reading from system memory).

>>> Better still, if you use cairo, it should be possible to have the
>>> graphics hardware perform the compositing.
>>>
>>> The cairo driver has support for using an X Pixmap for its output
>>> (via
>>> GRASS_CAIRO_DRAWABLE and GRASS_CAIRO_VISUAL). Not only would this
>>> eliminate the need to copy data to/from disk (or even between
>>> processses), but the d.* command can use the graphics hardware.
>>
>> This also sounds promising if it could be implemented from the Python
>> GUI.
>
> That depends upon whether wx allows you to use a Pixmap as the source
> for blending operations. If it's a wrapper around cairo, it should
> work. The main issue is that it needs to keep the data within the X
> server (which will keep it in video memory if possible).

Is this relevant for Windows? Workable for Mac without running x11?

I would assume that there are equivalents, but I don't know enough
about GDI/Quartz to say for sure. The main issue is determining how to
pass the surface handles between processes.

--
Glynn Clements <glynn@gclements.plus.com>

On Aug 13, 2008, at 12:47 AM, Glynn Clements wrote:

Michael Barton wrote:

That's all well and good, but how is the d.* command supposed to get
the data into the wxgui process if not through a file?

p = subprocess.Popen(['d.rast', 'map=myraster'], stdout=subprocess.PIPE)
data = p.stdout

A file will typically be quicker. With a pipe, unless the reader reads
it all in one go, you get a context switch for every PIPE_BUF bytes.

Also, the PNG and cairo drivers support using an mmap()ed BMP file as
the frame buffer; if both sides map the file, you eliminate a copy.

But the best case for speed will be keeping everything in video
memory, i.e. using pixmaps. If you use the GPU for rendering, the
output ends up in video memory, so if you want it anywhere else, you
have to copy it from there (reading video memory is often signficantly
slower than writing to it, or than reading from system memory).

Better still, if you use cairo, it should be possible to have the
graphics hardware perform the compositing.

The cairo driver has support for using an X Pixmap for its output
(via
GRASS_CAIRO_DRAWABLE and GRASS_CAIRO_VISUAL). Not only would this
eliminate the need to copy data to/from disk (or even between
processses), but the d.* command can use the graphics hardware.

This also sounds promising if it could be implemented from the Python
GUI.

That depends upon whether wx allows you to use a Pixmap as the source
for blending operations. If it's a wrapper around cairo, it should
work. The main issue is that it needs to keep the data within the X
server (which will keep it in video memory if possible).

Is this relevant for Windows? Workable for Mac without running x11?

I would assume that there are equivalents, but I don't know enough
about GDI/Quartz to say for sure. The main issue is determining how to
pass the surface handles between processes.

OK. These are very good points. We'll try to work with the new architecture as it develops.

Michael