165 lines
5.8 KiB
Python
165 lines
5.8 KiB
Python
# ----------------------------------------------------------------------------
|
|
# pyglet
|
|
# Copyright (c) 2006-2008 Alex Holkner
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
#
|
|
# * Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# * Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in
|
|
# the documentation and/or other materials provided with the
|
|
# distribution.
|
|
# * Neither the name of pyglet nor the names of its
|
|
# contributors may be used to endorse or promote products
|
|
# derived from this software without specific prior written
|
|
# permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
# ----------------------------------------------------------------------------
|
|
|
|
'''
|
|
'''
|
|
|
|
__docformat__ = 'restructuredtext'
|
|
__version__ = '$Id: gdkpixbuf2.py 1939 2008-03-21 11:48:12Z Alex.Holkner $'
|
|
|
|
from ctypes import *
|
|
|
|
from pyglet.gl import *
|
|
from pyglet.image import *
|
|
from pyglet.image.codecs import *
|
|
from pyglet.image.codecs import gif
|
|
|
|
import pyglet.lib
|
|
import pyglet.window
|
|
|
|
gdk = pyglet.lib.load_library('gdk-x11-2.0')
|
|
gdkpixbuf = pyglet.lib.load_library('gdk_pixbuf-2.0')
|
|
|
|
GdkPixbufLoader = c_void_p
|
|
GdkPixbuf = c_void_p
|
|
gdkpixbuf.gdk_pixbuf_loader_new.restype = GdkPixbufLoader
|
|
gdkpixbuf.gdk_pixbuf_loader_get_pixbuf.restype = GdkPixbuf
|
|
gdkpixbuf.gdk_pixbuf_get_pixels.restype = c_void_p
|
|
gdkpixbuf.gdk_pixbuf_loader_get_animation.restype = c_void_p
|
|
gdkpixbuf.gdk_pixbuf_animation_get_iter.restype = c_void_p
|
|
gdkpixbuf.gdk_pixbuf_animation_iter_get_pixbuf.restype = GdkPixbuf
|
|
|
|
class GTimeVal(Structure):
|
|
_fields_ = [
|
|
('tv_sec', c_long),
|
|
('tv_usec', c_long)
|
|
]
|
|
|
|
class GdkPixbuf2ImageDecoder(ImageDecoder):
|
|
def get_file_extensions(self):
|
|
return ['.png', '.xpm', '.jpg', '.jpeg', '.tif', '.tiff', '.pnm',
|
|
'.ras', '.bmp', '.gif']
|
|
|
|
def get_animation_file_extensions(self):
|
|
return ['.gif', '.ani']
|
|
|
|
def _load(self, file, filename, load_func):
|
|
data = file.read()
|
|
err = c_int()
|
|
loader = gdkpixbuf.gdk_pixbuf_loader_new()
|
|
gdkpixbuf.gdk_pixbuf_loader_write(loader, data, len(data), byref(err))
|
|
result = load_func(loader)
|
|
if not gdkpixbuf.gdk_pixbuf_loader_close(loader, byref(err)):
|
|
raise ImageDecodeException(filename)
|
|
if not result:
|
|
raise ImageDecodeException('Unable to load: %s' % filename)
|
|
return result
|
|
|
|
def _pixbuf_to_image(self, pixbuf):
|
|
# Get format and dimensions
|
|
width = gdkpixbuf.gdk_pixbuf_get_width(pixbuf)
|
|
height = gdkpixbuf.gdk_pixbuf_get_height(pixbuf)
|
|
channels = gdkpixbuf.gdk_pixbuf_get_n_channels(pixbuf)
|
|
rowstride = gdkpixbuf.gdk_pixbuf_get_rowstride(pixbuf)
|
|
has_alpha = gdkpixbuf.gdk_pixbuf_get_has_alpha(pixbuf)
|
|
pixels = gdkpixbuf.gdk_pixbuf_get_pixels(pixbuf)
|
|
|
|
# Copy pixel data.
|
|
buffer = (c_ubyte * (rowstride * height))()
|
|
memmove(buffer, pixels, rowstride * (height - 1) + width * channels)
|
|
|
|
# Release pixbuf
|
|
gdk.g_object_unref(pixbuf)
|
|
|
|
# Determine appropriate GL type
|
|
if channels == 3:
|
|
format = 'RGB'
|
|
else:
|
|
format = 'RGBA'
|
|
|
|
return ImageData(width, height, format, buffer, -rowstride)
|
|
|
|
def decode(self, file, filename):
|
|
pixbuf = self._load(file, filename,
|
|
gdkpixbuf.gdk_pixbuf_loader_get_pixbuf)
|
|
|
|
return self._pixbuf_to_image(pixbuf)
|
|
|
|
def decode_animation(self, file, filename):
|
|
# Extract GIF control data. If it's not a GIF, this method will
|
|
# raise.
|
|
gif_stream = gif.read(file)
|
|
delays = [image.delay for image in gif_stream.images]
|
|
|
|
# Get GDK animation iterator
|
|
file.seek(0)
|
|
anim = self._load(file, filename,
|
|
gdkpixbuf.gdk_pixbuf_loader_get_animation)
|
|
time = GTimeVal(0, 0)
|
|
iter = gdkpixbuf.gdk_pixbuf_animation_get_iter(anim, byref(time))
|
|
|
|
frames = []
|
|
|
|
# Extract each image
|
|
for control_delay in delays:
|
|
pixbuf = gdkpixbuf.gdk_pixbuf_animation_iter_get_pixbuf(iter)
|
|
image = self._pixbuf_to_image(pixbuf)
|
|
frames.append(AnimationFrame(image, control_delay))
|
|
|
|
gdk_delay = gdkpixbuf.gdk_pixbuf_animation_iter_get_delay_time(iter)
|
|
gdk_delay *= 1000 # milliseconds to microseconds
|
|
# Compare gdk_delay to control_delay for interest only.
|
|
#print control_delay, gdk_delay / 1000000.
|
|
|
|
if gdk_delay == -1:
|
|
break
|
|
|
|
us = time.tv_usec + gdk_delay
|
|
time.tv_sec += us // 1000000
|
|
time.tv_usec = us % 1000000
|
|
gdkpixbuf.gdk_pixbuf_animation_iter_advance(iter, byref(time))
|
|
|
|
return Animation(frames)
|
|
|
|
def get_decoders():
|
|
return [GdkPixbuf2ImageDecoder()]
|
|
|
|
def get_encoders():
|
|
return []
|
|
|
|
def init():
|
|
gdk.g_type_init()
|
|
|
|
init()
|
|
|