"""A :class:`GBufferedImage` wraps an image and buffers its pixel data.
"""
import campy.datastructures.grid as _grid
import campy.graphics.gcolor as _gcolor
import campy.graphics.gtypes as _gtypes
import campy.private.platform as _platform
import campy.io.base64helper as _base64helper
GBUFFEREDIMAGE_DEFAULT_DIFF_PIXEL_COLOR = 0xdd00dd
# def _char_to_hex(ch):
# return ord('0') <= ch <= ord('9') ? (ch - ord('0')) : (ch - ord('a') + 10)
# TODO(sredmond): Why on earth is this an interactor?
# class GBufferedImage(_ginteractors.GInteractor):
[docs]class GBufferedImage:
WIDTH_HEIGHT_MAX = 65535
[docs] @classmethod
def load_from_file(cls, filename):
inst = cls()
inst.load(filename)
return inst
@property
def bounds(self):
return _gtypes.GRectangle(self.x, self.y, self.width, self.height)
[docs] def clear(self):
self.fill(self.bg_color)
[docs] def count_diff_pixels(self, other, bounds=None):
# TODO(sredmond): This API differs from the CPP lib.
# TODO(sredmond): Include bounds
min_width = min(self.width, other.width)
min_height = min(self.height, other.height)
overlap = min_width * min_height
diff_pixel_count = (self.width * self.height - overlap) + (other.width * other.height - overlap)
for y in range(min_height):
for x in range(min_width):
if self.pixels.get(y, x) != other.pixels.get(y, x):
diff_pixel_count += 1
return diff_pixel_count
[docs] def diff(self, other, diff_color=GBUFFEREDIMAGE_DEFAULT_DIFF_PIXEL_COLOR):
pass
[docs] def fill(self, color):
# color = _gcolor.normalize(color)
self.pixels.fill(color)
_platform.Platform().gbufferedimage_fill(self, color) # TODO(get rgb value)
pass
[docs] def fill_region(self, x, y, width, height, TODO):
pass
[docs] def from_grid(self, grid):
pass
[docs] def get_height(self):
pass
[docs] def get_rgb(self, x, y):
pass
[docs] def get_rgb_string(self, x, y):
pass
[docs] def get_width(self):
pass
[docs] def in_bounds(self, x, y):
pass
[docs] def load(self, filename):
# TODO(sredmond): Ensure file exists.
result = _platform.Platform().gbufferedimage_load(self, filename)
decoded = _base64helper.decode(result)
self._pixel_string_to_grid(decoded)
[docs] def resize(self, width, height, retain=True):
pass
[docs] def save(self, filename):
pass
[docs] def set_rgb(x, y, TODO):
pass
[docs] def to_grid(self):
pass
def _pixel_string_to_grid(self, decoded):
# Read width (2B) and height (2B)
# TODO(sredmond): Seriously check this bit fiddling
w = (decoded[0] << 8) | decoded[1];
h = (decoded[2] << 8) | decoded[3];
if w != self.pixels.width() or h != self.pixels.height():
self.pixels.resize(h, w, retain=False)
# Check that we received approximately the right length of bytes.
expected = (w * h * 3) + 4
actual = len(decoded)
if actual != decoded:
print('Expected {} but saw {} bytes'.format(expected, actual))
# TODO(sredmond): Abort abort
import sys
sys.exit(1)
pixels = []
for red, green, blue in zip(decoded[4::3], decoded[5::3], decoded[6::3]):
pixels.append(Pixel(red=red, green=green, blue=blue))
i = 0
for row in range(h):
for col in range(w):
self.pixels.set(row, col, pixels[i])
i += 1
self.width = pixels.width
self.height = pixels.height
# "Private" constructor, called by class method constructors.
def __init__(self, x=0, y=0, width=1, height=1, bg_color=0x000000):
self.x = x
self.y = y
self.width = width
self.height = height
self.bg_color = bg_color
self.pixels = _grid.Grid()
def __str__(self):
return 'GBufferedImage()'