OLD | NEW |
(Empty) | |
| 1 import os, sys, array, json, math, StringIO |
| 2 sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) |
| 3 import subresource |
| 4 |
| 5 class Image: |
| 6 """This class partially implements the interface of the PIL.Image.Image. |
| 7 One day in the future WPT might support the PIL module or another imaging |
| 8 library, so this hacky BMP implementation will no longer be required. |
| 9 """ |
| 10 def __init__(self, width, height): |
| 11 self.width = width |
| 12 self.height = height |
| 13 self.img = bytearray([0 for i in range(3 * width * height)]) |
| 14 |
| 15 @staticmethod |
| 16 def new(mode, size, color=0): |
| 17 return Image(size[0], size[1]) |
| 18 |
| 19 def _int_to_bytes(self, number): |
| 20 packed_bytes = [0, 0, 0, 0] |
| 21 for i in range(4): |
| 22 packed_bytes[i] = number & 0xFF |
| 23 number >>= 8 |
| 24 |
| 25 return packed_bytes |
| 26 |
| 27 def putdata(self, color_data): |
| 28 for y in range(self.height): |
| 29 for x in range(self.width): |
| 30 i = x + y * self.width |
| 31 if i > len(color_data) - 1: |
| 32 return |
| 33 |
| 34 self.img[i * 3: i * 3 + 3] = color_data[i][::-1] |
| 35 |
| 36 def save(self, f, type): |
| 37 assert type == "BMP" |
| 38 # 54 bytes of preambule + image color data. |
| 39 filesize = 54 + 3 * self.width * self.height; |
| 40 # 14 bytes of header. |
| 41 bmpfileheader = bytearray(['B', 'M'] + self._int_to_bytes(filesize) + |
| 42 [0, 0, 0, 0, 54, 0, 0, 0]) |
| 43 # 40 bytes of info. |
| 44 bmpinfoheader = bytearray([40, 0, 0, 0] + |
| 45 self._int_to_bytes(self.width) + |
| 46 self._int_to_bytes(self.height) + |
| 47 [1, 0, 24] + (25 * [0])) |
| 48 |
| 49 padlength = (4 - (self.width * 3) % 4) % 4 |
| 50 bmppad = bytearray([0, 0, 0]); |
| 51 padding = bmppad[0 : padlength] |
| 52 |
| 53 f.write(bmpfileheader) |
| 54 f.write(bmpinfoheader) |
| 55 |
| 56 for i in range(self.height): |
| 57 offset = self.width * (self.height - i - 1) * 3 |
| 58 f.write(self.img[offset : offset + 3 * self.width]) |
| 59 f.write(padding) |
| 60 |
| 61 def encode_string_as_bmp_image(string_data): |
| 62 data_bytes = array.array("B", string_data) |
| 63 num_bytes = len(data_bytes) |
| 64 |
| 65 # Convert data bytes to color data (RGB). |
| 66 color_data = [] |
| 67 num_components = 3 |
| 68 rgb = [0] * num_components |
| 69 i = 0 |
| 70 for byte in data_bytes: |
| 71 component_index = i % num_components |
| 72 rgb[component_index] = byte |
| 73 if component_index == (num_components - 1) or i == (num_bytes - 1): |
| 74 color_data.append(tuple(rgb)) |
| 75 rgb = [0] * num_components |
| 76 i += 1 |
| 77 |
| 78 # Render image. |
| 79 num_pixels = len(color_data) |
| 80 sqrt = int(math.ceil(math.sqrt(num_pixels))) |
| 81 img = Image.new("RGB", (sqrt, sqrt), "black") |
| 82 img.putdata(color_data) |
| 83 |
| 84 # Flush image to string. |
| 85 f = StringIO.StringIO() |
| 86 img.save(f, "BMP") |
| 87 f.seek(0) |
| 88 |
| 89 return f.read() |
| 90 |
| 91 def generate_payload(server_data): |
| 92 data = ('{"headers": %(headers)s}') % server_data |
| 93 return encode_string_as_bmp_image(data) |
| 94 |
| 95 def main(request, response): |
| 96 subresource.respond(request, |
| 97 response, |
| 98 payload_generator = generate_payload, |
| 99 content_type = "image/bmp", |
| 100 access_control_allow_origin = "*") |
OLD | NEW |