heroes-renaissance/pyglet/image/codecs/gdkpixbuf2.py

166 lines
5.8 KiB
Python
Raw Permalink Normal View History

2008-11-23 20:07:47 +00:00
# ----------------------------------------------------------------------------
# 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()