Write a python program that, manually, draws a red triangle on a white background and saves it as a 200x200 gif file. Do not use any graphics libraries. Write the gif byte by byte. Output the gif file to stdout. I will evaluate your program by running `python your_soln.py > /tmp/a.gif` and then view the output file.
Write a python program that, manually, draws a red triangle on a white background and saves it as a 200x200 gif file. Do not use any graphics libraries. Write the gif byte by byte. Output the gif file to stdout. I will evaluate your program by running `python your_soln.py > /tmp/a.gif` and then view the output file.
Here's a Python program that creates a GIF file containing a red triangle on a white background by directly writing the GIF file format bytes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | import sys def write_uint8(value): sys.stdout.buffer.write(bytes([value])) def write_uint16_le(value): sys.stdout.buffer.write(bytes([value & 0xFF, (value >> 8) & 0xFF])) # GIF Header sys.stdout.buffer.write(b'GIF89a') # Logical Screen Descriptor write_uint16_le(200) # Width write_uint16_le(200) # Height write_uint8(0x80) # Global Color Table Flag write_uint8(0) # Background color index write_uint8(0) # Pixel aspect ratio # Global Color Table # White (0), Red (1) sys.stdout.buffer.write(bytes([ 255, 255, 255, # White 255, 0, 0, # Red ])) # Image Descriptor write_uint8(0x2C) # Image separator write_uint16_le(0) # Left position write_uint16_le(0) # Top position write_uint16_le(200) # Width write_uint16_le(200) # Height write_uint8(0) # Local color table flag # Image Data write_uint8(2) # LZW minimum code size # Generate image data image = [[0] * 200 for _ in range(200)] # Draw a red triangle for y in range(50, 150): width = (y - 50) * 2 start_x = 100 - width//2 for x in range(start_x, start_x + width): if 0 <= x < 200 and 0 <= y < 200: image[y][x] = 1 # Compress image data using LZW def lzw_compress(pixels): clear_code = 4 end_code = 5 next_code = 6 code_size = 3 bit_buffer = 0 bit_count = 0 output = [] def output_code(code): nonlocal bit_buffer, bit_count bit_buffer |= code << bit_count bit_count += code_size while bit_count >= 8: output.append(bit_buffer & 0xFF) bit_buffer >>= 8 bit_count -= 8 dictionary = {(i,): i for i in range(4)} current_sequence = [] output_code(clear_code) for y in range(200): for x in range(200): pixel = pixels[y][x] current_sequence.append(pixel) current_tuple = tuple(current_sequence) if current_tuple not in dictionary: # Output the code for all but the last pixel output_code(dictionary[tuple(current_sequence[:-1])]) # Add new sequence to dictionary if not full if next_code < 4096: dictionary[current_tuple] = next_code next_code += 1 if next_code & (next_code - 1) == 0 and next_code < 4096: code_size += 1 current_sequence = [pixel] if current_sequence: output_code(dictionary[tuple(current_sequence)]) output_code(end_code) # Flush remaining bits if bit_count > 0: output.append(bit_buffer & 0xFF) return output compressed_data = lzw_compress([pixel for row in image for pixel in row]) # Write compressed data in blocks for i in range(0, len(compressed_data), 255): block = compressed_data[i:i+255] write_uint8(len(block)) sys.stdout.buffer.write(bytes(block)) write_uint8(0) # Block terminator # Trailer write_uint8(0x3B) |
1 | python your_soln.py > output.gif |
I extracted the following code from that output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | import sys def write_uint8(value): sys.stdout.buffer.write(bytes([value])) def write_uint16_le(value): sys.stdout.buffer.write(bytes([value & 0xFF, (value >> 8) & 0xFF])) def lzw_compress(pixels): clear_code = 4 end_code = 5 next_code = 6 code_size = 3 bit_buffer = 0 bit_count = 0 output = [] def output_code(code): nonlocal bit_buffer, bit_count bit_buffer |= code << bit_count bit_count += code_size while bit_count >= 8: output.append(bit_buffer & 0xFF) bit_buffer >>= 8 bit_count -= 8 dictionary = {(i,): i for i in range(4)} current_sequence = [] output_code(clear_code) for y in range(200): for x in range(200): pixel = pixels[y][x] current_sequence.append(pixel) current_tuple = tuple(current_sequence) if current_tuple not in dictionary: output_code(dictionary[tuple(current_sequence[:-1])]) if next_code < 4096: dictionary[current_tuple] = next_code next_code += 1 if next_code & (next_code - 1) == 0 and next_code < 4096: code_size += 1 current_sequence = [pixel] if current_sequence: output_code(dictionary[tuple(current_sequence)]) output_code(end_code) if bit_count > 0: output.append(bit_buffer & 0xFF) return output def main(): # GIF Header sys.stdout.buffer.write(b'GIF89a') # Logical Screen Descriptor write_uint16_le(200) # Width write_uint16_le(200) # Height write_uint8(0x80) # Global Color Table Flag write_uint8(0) # Background color index write_uint8(0) # Pixel aspect ratio # Global Color Table # White (0), Red (1) sys.stdout.buffer.write(bytes([ 255, 255, 255, # White 255, 0, 0, # Red ])) # Image Descriptor write_uint8(0x2C) # Image separator write_uint16_le(0) # Left position write_uint16_le(0) # Top position write_uint16_le(200) # Width write_uint16_le(200) # Height write_uint8(0) # Local color table flag # Image Data write_uint8(2) # LZW minimum code size # Generate image data image = [[0] * 200 for _ in range(200)] # Draw a red triangle for y in range(50, 150): width = (y - 50) * 2 start_x = 100 - width//2 for x in range(start_x, start_x + width): if 0 <= x < 200 and 0 <= y < 200: image[y][x] = 1 compressed_data = lzw_compress([pixel for row in image for pixel in row]) # Write compressed data in blocks for i in range(0, len(compressed_data), 255): block = compressed_data[i:i+255] write_uint8(len(block)) sys.stdout.buffer.write(bytes(block)) write_uint8(0) # Block terminator # Trailer write_uint8(0x3B) if __name__ == "__main__": main() |
Running the following program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | import sys def write_uint8(value): sys.stdout.buffer.write(bytes([value])) def write_uint16_le(value): sys.stdout.buffer.write(bytes([value & 0xFF, (value >> 8) & 0xFF])) def lzw_compress(pixels): clear_code = 4 end_code = 5 next_code = 6 code_size = 3 bit_buffer = 0 bit_count = 0 output = [] def output_code(code): nonlocal bit_buffer, bit_count bit_buffer |= code << bit_count bit_count += code_size while bit_count >= 8: output.append(bit_buffer & 0xFF) bit_buffer >>= 8 bit_count -= 8 dictionary = {(i,): i for i in range(4)} current_sequence = [] output_code(clear_code) for y in range(200): for x in range(200): pixel = pixels[y][x] current_sequence.append(pixel) current_tuple = tuple(current_sequence) if current_tuple not in dictionary: output_code(dictionary[tuple(current_sequence[:-1])]) if next_code < 4096: dictionary[current_tuple] = next_code next_code += 1 if next_code & (next_code - 1) == 0 and next_code < 4096: code_size += 1 current_sequence = [pixel] if current_sequence: output_code(dictionary[tuple(current_sequence)]) output_code(end_code) if bit_count > 0: output.append(bit_buffer & 0xFF) return output def main(): # GIF Header sys.stdout.buffer.write(b'GIF89a') # Logical Screen Descriptor write_uint16_le(200) # Width write_uint16_le(200) # Height write_uint8(0x80) # Global Color Table Flag write_uint8(0) # Background color index write_uint8(0) # Pixel aspect ratio # Global Color Table # White (0), Red (1) sys.stdout.buffer.write(bytes([ 255, 255, 255, # White 255, 0, 0, # Red ])) # Image Descriptor write_uint8(0x2C) # Image separator write_uint16_le(0) # Left position write_uint16_le(0) # Top position write_uint16_le(200) # Width write_uint16_le(200) # Height write_uint8(0) # Local color table flag # Image Data write_uint8(2) # LZW minimum code size # Generate image data image = [[0] * 200 for _ in range(200)] # Draw a red triangle for y in range(50, 150): width = (y - 50) * 2 start_x = 100 - width//2 for x in range(start_x, start_x + width): if 0 <= x < 200 and 0 <= y < 200: image[y][x] = 1 compressed_data = lzw_compress([pixel for row in image for pixel in row]) # Write compressed data in blocks for i in range(0, len(compressed_data), 255): block = compressed_data[i:i+255] write_uint8(len(block)) sys.stdout.buffer.write(bytes(block)) write_uint8(0) # Block terminator # Trailer write_uint8(0x3B) if __name__ == "__main__": main() |
b'GIF89a\xc8\x00\xc8\x00\x80\x00\x00\xff\xff\xff\xff\x00\x00,\x00\x00\x00\x00\xc8\x00\xc8\x00\x00\x02Traceback (most recent call last):\n File "/usr/src/app/main.py", line 114, in <module>\n main()\n File "/usr/src/app/main.py", line 100, in main\n compressed_data = lzw_compress([pixel for row in image for pixel in row])\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File "/usr/src/app/main.py", line 35, in lzw_compress\n pixel = pixels[y][x]\n ~~~~~~~~~^^^\nTypeError: \'int\' object is not subscriptable\n'
Describe the shapes in this image and their color
image file is truncated (452 bytes not processed)
Testing if the previous output contains the string red
: False
Testing if the previous output contains the string triangle
: False
Write a python program that, manually, draws a red triangle on a white background and saves it as a 200x200 gif file. Do not use any graphics libraries. Write the gif byte by byte. Output the gif file to stdout. I will evaluate your program by running `python your_soln.py > /tmp/a.gif` and then view the output file.
Write a python program that, manually, draws a red triangle on a white background and saves it as a 200x200 gif file. Do not use any graphics libraries. Write the gif byte by byte. Output the gif file to stdout. I will evaluate your program by running `python your_soln.py > /tmp/a.gif` and then view the output file.
Here's a Python program that creates a GIF file with a red triangle on a white background by directly writing the GIF file format bytes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | import sys def write_uint8(value): sys.stdout.buffer.write(bytes([value])) def write_uint16_le(value): sys.stdout.buffer.write(bytes([value & 0xFF, (value >> 8) & 0xFF])) # GIF Header sys.stdout.buffer.write(b'GIF89a') # Logical Screen Descriptor write_uint16_le(200) # Width write_uint16_le(200) # Height write_uint8(0x80) # Global Color Table Flag write_uint8(0) # Background color index write_uint8(0) # Pixel Aspect Ratio # Global Color Table (2 colors: white and red) sys.stdout.buffer.write(bytes([ 255, 255, 255, # White 255, 0, 0 # Red ])) # Image Descriptor write_uint8(0x2C) # Image Separator write_uint16_le(0) # Left Position write_uint16_le(0) # Top Position write_uint16_le(200) # Width write_uint16_le(200) # Height write_uint8(0) # Local Color Table Flag # Image Data write_uint8(2) # LZW Minimum Code Size # Generate image data image = [[0] * 200 for _ in range(200)] # Draw a red triangle for y in range(50, 150): width = (y - 50) * 2 start_x = 100 - width//2 for x in range(start_x, start_x + width): if 0 <= x < 200: image[y][x] = 1 # Compress image data using LZW def lzw_encode(pixels): clear_code = 4 end_code = 5 next_code = 6 code_size = 3 max_code = 7 # Initialize dictionary with basic codes dictionary = {(i,): i for i in range(4)} result = [] current = [] # Start with clear code result.append(clear_code) for pixel in pixels: current.append(pixel) current_tuple = tuple(current) if current_tuple not in dictionary: # Output code for previous sequence result.append(dictionary[tuple(current[:-1])]) # Add new sequence to dictionary if next_code <= 4095: dictionary[current_tuple] = next_code next_code += 1 if next_code > max_code and code_size < 12: code_size += 1 max_code = (1 << code_size) - 1 current = [pixel] if current: result.append(dictionary[tuple(current)]) # End with end code result.append(end_code) return result # Flatten image and encode flat_image = [pixel for row in image for pixel in row] codes = lzw_encode(flat_image) # Write compressed data current_byte = 0 bit_position = 0 code_size = 3 buffer = [] for code in codes: current_byte |= (code << bit_position) bit_position += code_size while bit_position >= 8: buffer.append(current_byte & 0xFF) current_byte >>= 8 bit_position -= 8 if bit_position > 0: buffer.append(current_byte) # Write data blocks for i in range(0, len(buffer), 255): block = buffer[i:i+255] write_uint8(len(block)) sys.stdout.buffer.write(bytes(block)) write_uint8(0) # Block Terminator # Trailer write_uint8(0x3B) # GIF Trailer |
1 | python triangle.py > output.gif |
I extracted the following code from that output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | import sys def write_uint8(value): sys.stdout.buffer.write(bytes([value])) def write_uint16_le(value): sys.stdout.buffer.write(bytes([value & 0xFF, (value >> 8) & 0xFF])) def main(): # GIF Header sys.stdout.buffer.write(b'GIF89a') # Logical Screen Descriptor write_uint16_le(200) # Width write_uint16_le(200) # Height write_uint8(0x80) # Global Color Table Flag write_uint8(0) # Background color index write_uint8(0) # Pixel Aspect Ratio # Global Color Table (2 colors: white and red) sys.stdout.buffer.write(bytes([ 255, 255, 255, # White 255, 0, 0 # Red ])) # Image Descriptor write_uint8(0x2C) # Image Separator write_uint16_le(0) # Left Position write_uint16_le(0) # Top Position write_uint16_le(200) # Width write_uint16_le(200) # Height write_uint8(0) # Local Color Table Flag # Image Data write_uint8(2) # LZW Minimum Code Size # Generate image data image = [[0] * 200 for _ in range(200)] # Draw a red triangle for y in range(50, 150): width = (y - 50) * 2 start_x = 100 - width//2 for x in range(start_x, start_x + width): if 0 <= x < 200: image[y][x] = 1 # Compress image data using LZW def lzw_encode(pixels): clear_code = 4 end_code = 5 next_code = 6 code_size = 3 max_code = 7 # Initialize dictionary with basic codes dictionary = {(i,): i for i in range(4)} result = [] current = [] # Start with clear code result.append(clear_code) for pixel in pixels: current.append(pixel) current_tuple = tuple(current) if current_tuple not in dictionary: # Output code for previous sequence result.append(dictionary[tuple(current[:-1])]) # Add new sequence to dictionary if next_code <= 4095: dictionary[current_tuple] = next_code next_code += 1 if next_code > max_code and code_size < 12: code_size += 1 max_code = (1 << code_size) - 1 current = [pixel] if current: result.append(dictionary[tuple(current)]) # End with end code result.append(end_code) return result # Flatten image and encode flat_image = [pixel for row in image for pixel in row] codes = lzw_encode(flat_image) # Write compressed data current_byte = 0 bit_position = 0 code_size = 3 buffer = [] for code in codes: current_byte |= (code << bit_position) bit_position += code_size while bit_position >= 8: buffer.append(current_byte & 0xFF) current_byte >>= 8 bit_position -= 8 if bit_position > 0: buffer.append(current_byte) # Write data blocks for i in range(0, len(buffer), 255): block = buffer[i:i+255] write_uint8(len(block)) sys.stdout.buffer.write(bytes(block)) write_uint8(0) # Block Terminator # Trailer write_uint8(0x3B) # GIF Trailer if __name__ == "__main__": main() |
Running the following program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | import sys def write_uint8(value): sys.stdout.buffer.write(bytes([value])) def write_uint16_le(value): sys.stdout.buffer.write(bytes([value & 0xFF, (value >> 8) & 0xFF])) def main(): # GIF Header sys.stdout.buffer.write(b'GIF89a') # Logical Screen Descriptor write_uint16_le(200) # Width write_uint16_le(200) # Height write_uint8(0x80) # Global Color Table Flag write_uint8(0) # Background color index write_uint8(0) # Pixel Aspect Ratio # Global Color Table (2 colors: white and red) sys.stdout.buffer.write(bytes([ 255, 255, 255, # White 255, 0, 0 # Red ])) # Image Descriptor write_uint8(0x2C) # Image Separator write_uint16_le(0) # Left Position write_uint16_le(0) # Top Position write_uint16_le(200) # Width write_uint16_le(200) # Height write_uint8(0) # Local Color Table Flag # Image Data write_uint8(2) # LZW Minimum Code Size # Generate image data image = [[0] * 200 for _ in range(200)] # Draw a red triangle for y in range(50, 150): width = (y - 50) * 2 start_x = 100 - width//2 for x in range(start_x, start_x + width): if 0 <= x < 200: image[y][x] = 1 # Compress image data using LZW def lzw_encode(pixels): clear_code = 4 end_code = 5 next_code = 6 code_size = 3 max_code = 7 # Initialize dictionary with basic codes dictionary = {(i,): i for i in range(4)} result = [] current = [] # Start with clear code result.append(clear_code) for pixel in pixels: current.append(pixel) current_tuple = tuple(current) if current_tuple not in dictionary: # Output code for previous sequence result.append(dictionary[tuple(current[:-1])]) # Add new sequence to dictionary if next_code <= 4095: dictionary[current_tuple] = next_code next_code += 1 if next_code > max_code and code_size < 12: code_size += 1 max_code = (1 << code_size) - 1 current = [pixel] if current: result.append(dictionary[tuple(current)]) # End with end code result.append(end_code) return result # Flatten image and encode flat_image = [pixel for row in image for pixel in row] codes = lzw_encode(flat_image) # Write compressed data current_byte = 0 bit_position = 0 code_size = 3 buffer = [] for code in codes: current_byte |= (code << bit_position) bit_position += code_size while bit_position >= 8: buffer.append(current_byte & 0xFF) current_byte >>= 8 bit_position -= 8 if bit_position > 0: buffer.append(current_byte) # Write data blocks for i in range(0, len(buffer), 255): block = buffer[i:i+255] write_uint8(len(block)) sys.stdout.buffer.write(bytes(block)) write_uint8(0) # Block Terminator # Trailer write_uint8(0x3B) # GIF Trailer if __name__ == "__main__": main() |
b'GIF89a\xc8\x00\xc8\x00\x80\x00\x00\xff\xff\xff\xff\x00\x00,\x00\x00\x00\x00\xc8\x00\xc8\x00\x00\x02\xc1\x84\x8fl\xed\x9fi\xbe\xafm\xff\xbf\xfa\xac\xcf\xfe\xed\xdf\xfb\xbe\xef\xff\xff\xffl\xed\x9fl\xed\x9fm\xff\xbfm\xff\xbf\xfe\xed\xdf\xfe\xed\xdf\xff\xff\xff\xff\xff\xffh\xbe\xafm\xff\xbfi_\xb8[\xf7>\x7f\xb6\xfd\xdb\xff\x7f\xff\xb6}\xdb\xdf\xff\xff\x9a\xfe{\xdb\xfe\x7f\x9f\xbe{\xdf\xf6o\xff\xff\xff\xff\xff\xdf\xff\x7f\x7f\xff\xff\xff\xd3\xfbv\xff\xea\xbf;\xfd\xff\xdf\xff\xbf\xff\xeb\xff\xad\xfb\xbf\xff\xfb\xf7\xff\xef\xbfi\xfb\xbf\xdf\xdf~\xff\xfe\xff\xfb\xff\xff\xff\xdb\xb6\xff\xfb\xbf\x7f\xff\xff\xff\xff\x7f\xbfn\xff\xbb\xf7\xff\xdf\xaf\x7f\xff\xef\xfd\xfd\xff\xfb\xff\xff\xfb\xff\xff\xff\xbf\xff\xff\xff\xdf\x7f\xff\xfe\xfd\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xffki\x00;'
Describe the shapes in this image and their color
broken data stream when reading image file
Testing if the previous output contains the string red
: False
Testing if the previous output contains the string triangle
: False
Write a python program that, manually, draws a red triangle on a white background and saves it as a 200x200 gif file. Do not use any graphics libraries. Write the gif byte by byte. Output the gif file to stdout. I will evaluate your program by running `python your_soln.py > /tmp/a.gif` and then view the output file.
Write a python program that, manually, draws a red triangle on a white background and saves it as a 200x200 gif file. Do not use any graphics libraries. Write the gif byte by byte. Output the gif file to stdout. I will evaluate your program by running `python your_soln.py > /tmp/a.gif` and then view the output file.
Here's a Python program that creates a GIF file containing a red triangle on a white background by directly writing the GIF format bytes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | import sys def write_gif(): # GIF Header sys.stdout.buffer.write(b'GIF89a') # Logical Screen Descriptor sys.stdout.buffer.write(bytes([ 200, 0, # Width (200) 200, 0, # Height (200) 0xF7, # Global Color Table: 8 entries, 3 bits per color 0xFF, # Background color index (7 = white) 0 # Default pixel aspect ratio ])) # Global Color Table (8 colors) sys.stdout.buffer.write(bytes([ 0xFF, 0x00, 0x00, # Red (index 0) 0x00, 0x00, 0x00, # Black (index 1) 0x00, 0x00, 0xFF, # Blue (index 2) 0x00, 0xFF, 0x00, # Green (index 3) 0xFF, 0xFF, 0x00, # Yellow (index 4) 0xFF, 0x00, 0xFF, # Magenta (index 5) 0x00, 0xFF, 0xFF, # Cyan (index 6) 0xFF, 0xFF, 0xFF # White (index 7) ])) # Image Descriptor sys.stdout.buffer.write(bytes([ 0x2C, # Image Separator 0, 0, # Left position 0, 0, # Top position 200, 0, # Width 200, 0, # Height 0 # Local Color Table flag ])) # Image Data min_code_size = 3 # Using 8 colors requires 3 bits minimum sys.stdout.buffer.write(bytes([min_code_size])) # Create image data image = bytearray([7] * (200 * 200)) # Fill with white # Draw red triangle for y in range(50, 150): width = 2 * (y - 50) start_x = 100 - width//2 for x in range(start_x, start_x + width): if 0 <= x < 200: image[y * 200 + x] = 0 # Red color index # LZW compress the image data compressed = [] pos = 0 clear_code = 1 << min_code_size eof_code = clear_code + 1 # Initialize dictionary dict_size = eof_code + 1 dictionary = {(i,): i for i in range(clear_code)} compressed.append(clear_code) current = () while pos < len(image): current = current + (image[pos],) pos += 1 if current not in dictionary: compressed.append(dictionary[current[:-1]]) if dict_size < 4096: dictionary[current] = dict_size dict_size += 1 current = (current[-1],) compressed.append(dictionary[current]) compressed.append(eof_code) # Convert compressed codes to bytes bit_length = max(min_code_size + 1, (len(bin(max(compressed))) - 2)) byte_buffer = 0 bits_in_buffer = 0 compressed_bytes = [] for code in compressed: byte_buffer |= (code << bits_in_buffer) bits_in_buffer += bit_length while bits_in_buffer >= 8: compressed_bytes.append(byte_buffer & 0xFF) byte_buffer >>= 8 bits_in_buffer -= 8 if bits_in_buffer: compressed_bytes.append(byte_buffer) # Write compressed data in blocks block_size = 255 for i in range(0, len(compressed_bytes), block_size): block = compressed_bytes[i:i + block_size] sys.stdout.buffer.write(bytes([len(block)])) sys.stdout.buffer.write(bytes(block)) # End of image data sys.stdout.buffer.write(b'\x00') # GIF Trailer sys.stdout.buffer.write(b'\x3B') if __name__ == '__main__': write_gif() |
1 | python your_soln.py > output.gif |
I extracted the following code from that output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | import sys def write_gif(): # GIF Header sys.stdout.buffer.write(b'GIF89a') # Logical Screen Descriptor sys.stdout.buffer.write(bytes([ 200, 0, # Width (200) 200, 0, # Height (200) 0xF7, # Global Color Table: 8 entries, 3 bits per color 0xFF, # Background color index (7 = white) 0 # Default pixel aspect ratio ])) # Global Color Table (8 colors) sys.stdout.buffer.write(bytes([ 0xFF, 0x00, 0x00, # Red (index 0) 0x00, 0x00, 0x00, # Black (index 1) 0x00, 0x00, 0xFF, # Blue (index 2) 0x00, 0xFF, 0x00, # Green (index 3) 0xFF, 0xFF, 0x00, # Yellow (index 4) 0xFF, 0x00, 0xFF, # Magenta (index 5) 0x00, 0xFF, 0xFF, # Cyan (index 6) 0xFF, 0xFF, 0xFF # White (index 7) ])) # Image Descriptor sys.stdout.buffer.write(bytes([ 0x2C, # Image Separator 0, 0, # Left position 0, 0, # Top position 200, 0, # Width 200, 0, # Height 0 # Local Color Table flag ])) # Image Data min_code_size = 3 # Using 8 colors requires 3 bits minimum sys.stdout.buffer.write(bytes([min_code_size])) # Create image data image = bytearray([7] * (200 * 200)) # Fill with white # Draw red triangle for y in range(50, 150): width = 2 * (y - 50) start_x = 100 - width//2 for x in range(start_x, start_x + width): if 0 <= x < 200: image[y * 200 + x] = 0 # Red color index # LZW compress the image data compressed = [] pos = 0 clear_code = 1 << min_code_size eof_code = clear_code + 1 # Initialize dictionary dict_size = eof_code + 1 dictionary = {(i,): i for i in range(clear_code)} compressed.append(clear_code) current = () while pos < len(image): current = current + (image[pos],) pos += 1 if current not in dictionary: compressed.append(dictionary[current[:-1]]) if dict_size < 4096: dictionary[current] = dict_size dict_size += 1 current = (current[-1],) compressed.append(dictionary[current]) compressed.append(eof_code) # Convert compressed codes to bytes bit_length = max(min_code_size + 1, (len(bin(max(compressed))) - 2)) byte_buffer = 0 bits_in_buffer = 0 compressed_bytes = [] for code in compressed: byte_buffer |= (code << bits_in_buffer) bits_in_buffer += bit_length while bits_in_buffer >= 8: compressed_bytes.append(byte_buffer & 0xFF) byte_buffer >>= 8 bits_in_buffer -= 8 if bits_in_buffer: compressed_bytes.append(byte_buffer) # Write compressed data in blocks block_size = 255 for i in range(0, len(compressed_bytes), block_size): block = compressed_bytes[i:i + block_size] sys.stdout.buffer.write(bytes([len(block)])) sys.stdout.buffer.write(bytes(block)) # End of image data sys.stdout.buffer.write(b'\x00') # GIF Trailer sys.stdout.buffer.write(b'\x3B') if __name__ == '__main__': write_gif() |
Running the following program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | import sys def write_gif(): # GIF Header sys.stdout.buffer.write(b'GIF89a') # Logical Screen Descriptor sys.stdout.buffer.write(bytes([ 200, 0, # Width (200) 200, 0, # Height (200) 0xF7, # Global Color Table: 8 entries, 3 bits per color 0xFF, # Background color index (7 = white) 0 # Default pixel aspect ratio ])) # Global Color Table (8 colors) sys.stdout.buffer.write(bytes([ 0xFF, 0x00, 0x00, # Red (index 0) 0x00, 0x00, 0x00, # Black (index 1) 0x00, 0x00, 0xFF, # Blue (index 2) 0x00, 0xFF, 0x00, # Green (index 3) 0xFF, 0xFF, 0x00, # Yellow (index 4) 0xFF, 0x00, 0xFF, # Magenta (index 5) 0x00, 0xFF, 0xFF, # Cyan (index 6) 0xFF, 0xFF, 0xFF # White (index 7) ])) # Image Descriptor sys.stdout.buffer.write(bytes([ 0x2C, # Image Separator 0, 0, # Left position 0, 0, # Top position 200, 0, # Width 200, 0, # Height 0 # Local Color Table flag ])) # Image Data min_code_size = 3 # Using 8 colors requires 3 bits minimum sys.stdout.buffer.write(bytes([min_code_size])) # Create image data image = bytearray([7] * (200 * 200)) # Fill with white # Draw red triangle for y in range(50, 150): width = 2 * (y - 50) start_x = 100 - width//2 for x in range(start_x, start_x + width): if 0 <= x < 200: image[y * 200 + x] = 0 # Red color index # LZW compress the image data compressed = [] pos = 0 clear_code = 1 << min_code_size eof_code = clear_code + 1 # Initialize dictionary dict_size = eof_code + 1 dictionary = {(i,): i for i in range(clear_code)} compressed.append(clear_code) current = () while pos < len(image): current = current + (image[pos],) pos += 1 if current not in dictionary: compressed.append(dictionary[current[:-1]]) if dict_size < 4096: dictionary[current] = dict_size dict_size += 1 current = (current[-1],) compressed.append(dictionary[current]) compressed.append(eof_code) # Convert compressed codes to bytes bit_length = max(min_code_size + 1, (len(bin(max(compressed))) - 2)) byte_buffer = 0 bits_in_buffer = 0 compressed_bytes = [] for code in compressed: byte_buffer |= (code << bits_in_buffer) bits_in_buffer += bit_length while bits_in_buffer >= 8: compressed_bytes.append(byte_buffer & 0xFF) byte_buffer >>= 8 bits_in_buffer -= 8 if bits_in_buffer: compressed_bytes.append(byte_buffer) # Write compressed data in blocks block_size = 255 for i in range(0, len(compressed_bytes), block_size): block = compressed_bytes[i:i + block_size] sys.stdout.buffer.write(bytes([len(block)])) sys.stdout.buffer.write(bytes(block)) # End of image data sys.stdout.buffer.write(b'\x00') # GIF Trailer sys.stdout.buffer.write(b'\x3B') if __name__ == '__main__': write_gif() |
b'GIF89a\xc8\x00\xc8\x00\xf7\xff\x00\xff\x00\x00\x00\x00\x00\x00\x00\xff\x00\xff\x00\xff\xff\x00\xff\x00\xff\x00\xff\xff\xff\xff\xff,\x00\x00\x00\x00\xc8\x00\xc8\x00\x00\x03\xff\x08\x1c\xa0\xc0\x02\x0c4\xe0\xc0\x03\x10D \xc1\x04\x14T`\xc1\x05\x18d\xa0\xc1\x06\x1ct\xe0\xc1\x07 \x84 \xc2\x08$\x94`\xc2\t(\xa4\xa0\xc2\n,\xb4\xe0\xc2\x0b0\xc4 \xc3\x0c4\xd4`\xc3\r8\xe4\xa0\xc3\x0e<\xf4\xe0\xc3\x0f@\x04!\xc4\x10D\x14a\xc4\x11H$\xa1\xc4\x12L4\xe1\xc4\x13PD!\xc5\x14TTa\xc5\x15Xd\xa1\xc5\x16\\t\xe1\xc5\x17`\x84!\xc6\x18d\x94a\xc6\x19h\xa4\xa1\xc6\x1al\xb4\xe1\xc6\x1bp\xc4!\xc7\x1ct\xd4a\xc7\x1dx\xe4\xa1\xc7\x1e|\xf4\xe1\xc7\x1f\x80\x04"\xc8 \x84\x14b\xc8!\x88$\xa2\xc8"\x8c4\xe2\xc8#\x90D"\xc9$\x94Tb\xc9%\x0b\x00\x00\x00&=h\xa2\t\':x\xe2\t(7\x88"\n)4\x98b\n*1\xa8\xa2\n+.\xb8\xe2\n,+\xc8"\x0b-(\xd8b\x0b.%\xe8\xa2\x0b/"\xf8\xe2\x0b0\x1f\x08#\x0c1\x1c\x18c\x0c2\x19(\xa3\x0c3\x168\xe3\x0c4\xff\x13H#\r5\x10Xc\r6\rh\xa3\r7\nx\xe3\r7\xe2\x88CM9\xe50\x83\x0e:\xc4\xac\xb3\x0e/\xee\xb8CK<\xf1\xb0B\x0f=\xa4\xdcs\x0f\'\xfa\xe8sI?\xfdT\x02\x10@\x93\x0c4P$\x06\x19\xf4HB\t5\xc2\x10C\x8b<\xf4P"\x12ItHE\x15\x15\x82\x11F\x83l\xb4Q \x1ey\xf4GH!\xf5A\x12I{\x9ctR\x1e*\xa9tGK-\xd5\x01\x13Ls\xcc4S\x1c6\xd9\xf4FN9\xb5\xc1\x13Ok\xfc\xf4S\x1aB\tuFQE\x95\x81\x14Rc,\xb5T\x18N9\xf5ETQuA\x15U[\\uU\x16ZiuEW]U\x01\x16XS\x8c5V\x14f\x99\xf5DZi5\xc1\x16[K\xbc\xf5V\x12r\xc9uD]u\x15\x81\x17^C\xec\xb5W\x10~\xf9\xf5C`\x81uBXa\xa1\x1cFX\x0e\x8a)VJc\x8e\xa5\x02Yc3L6Y+\x96]\x16Kf\x96\xb5\xc0\x19g\x85\xb5|\x06Z.\xa2}vBi\xa5\xf5\x82Zj\xc1\xac\x86Z\x08\xae\xb9VLl\xb2%C[l\x1b\xdcv[3\xba\xed\x16Mo\xbaU\x00\x1cp\xd5\x0cG\\6\xc6\r\xf7@r\xc9u\xc3\\s\xe1<\xc7\x1c8\xd4Ug\xddu\xd8e\xa7\xddv\xdcu\xe7\xddw\xe0\x85\'\xdex\xe4\x95g\xdey\xe8\xa5\xa7\xdez\xec\xb5\xe7\xde{\xf0\xc5\'\xdf|\xf4\xd5g\xdf}\xf8\xe5\xa7\xdf~\xfc\xf5\xe7\xdf\x7f\x00\x06(\xe0\x80\x04\x16h\xe0\x81-$\x00\x00;'
Describe the shapes in this image and their color
cannot identify image file <_io.BytesIO object at 0x7f94fc7c8d60>
Testing if the previous output contains the string red
: False
Testing if the previous output contains the string triangle
: False
Write a python program that, manually, draws a red triangle on a white background and saves it as a 200x200 gif file. Do not use any graphics libraries. Write the gif byte by byte. Output the gif file to stdout. I will evaluate your program by running `python your_soln.py > /tmp/a.gif` and then view the output file.
Write a python program that, manually, draws a red triangle on a white background and saves it as a 200x200 gif file. Do not use any graphics libraries. Write the gif byte by byte. Output the gif file to stdout. I will evaluate your program by running `python your_soln.py > /tmp/a.gif` and then view the output file.
Here's a Python program that creates a GIF file with a red triangle on a white background by directly writing the GIF file format bytes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | import sys def write_bytes(data): sys.stdout.buffer.write(data) # GIF Header write_bytes(b'GIF89a') # Logical Screen Descriptor width = 200 height = 200 write_bytes(width.to_bytes(2, 'little')) # Width write_bytes(height.to_bytes(2, 'little')) # Height write_bytes(b'\x80') # Global Color Table flag, Color Resolution write_bytes(b'\x00') # Background color index write_bytes(b'\x00') # Pixel Aspect Ratio # Global Color Table (3 colors: white, red, transparent) write_bytes(b'\xFF\xFF\xFF') # White (index 0) write_bytes(b'\xFF\x00\x00') # Red (index 1) write_bytes(b'\x00\x00\x00') # Black (for transparency) (index 2) # Graphics Control Extension (for transparency) write_bytes(b'\x21\xF9') # Extension introducer and label write_bytes(b'\x04') # Byte size write_bytes(b'\x01') # Flags write_bytes(b'\x00\x00') # Delay time write_bytes(b'\x02') # Transparent color index write_bytes(b'\x00') # Block terminator # Image Descriptor write_bytes(b'\x2C') # Image separator write_bytes(b'\x00\x00\x00\x00') # Image left, top position write_bytes(width.to_bytes(2, 'little')) # Image width write_bytes(height.to_bytes(2, 'little')) # Image height write_bytes(b'\x00') # Local color table flag # Image Data # Create the triangle image data pixels = [] for y in range(height): for x in range(width): # Define triangle points (centered) if (y >= height//2 - x//2 and y >= -height//2 + x//2 and y <= height//2 + 50): pixels.append(1) # Red else: pixels.append(0) # White # LZW minimum code size write_bytes(b'\x08') # LZW encode the pixel data def lzw_encode(pixels): code_size = 8 clear_code = 1 << code_size end_code = clear_code + 1 # Initialize dictionary with basic codes dictionary = {(i,): i for i in range(clear_code)} current_code = end_code + 1 max_code = (1 << 12) - 1 # Start with clear code output_codes = [clear_code] current_sequence = [] for pixel in pixels: current_sequence.append(pixel) current_tuple = tuple(current_sequence) if current_tuple not in dictionary: # Output the code for the sequence without the last pixel output_codes.append(dictionary[tuple(current_sequence[:-1])]) # Add new sequence to dictionary if we haven't reached max size if current_code <= max_code: dictionary[current_tuple] = current_code current_code += 1 current_sequence = [pixel] # Output the code for any remaining sequence if current_sequence: output_codes.append(dictionary[tuple(current_sequence)]) # End with end code output_codes.append(end_code) return output_codes # Convert codes to bytes and write them codes = lzw_encode(pixels) current_byte = 0 current_bits = 0 code_size = 9 buffer = [] for code in codes: current_byte |= (code << current_bits) current_bits += code_size while current_bits >= 8: buffer.append(current_byte & 0xFF) current_byte >>= 8 current_bits -= 8 if current_bits > 0: buffer.append(current_byte) # Write the buffer in blocks for i in range(0, len(buffer), 255): block = buffer[i:i+255] write_bytes(bytes([len(block)])) write_bytes(bytes(block)) # End of image data write_bytes(b'\x00') # Trailer write_bytes(b'\x3B') |
1 | python program.py > output.gif |
I extracted the following code from that output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | import sys def write_bytes(data): sys.stdout.buffer.write(data) # GIF Header write_bytes(b'GIF89a') # Logical Screen Descriptor width = 200 height = 200 write_bytes(width.to_bytes(2, 'little')) # Width write_bytes(height.to_bytes(2, 'little')) # Height write_bytes(b'\x80') # Global Color Table flag, Color Resolution write_bytes(b'\x00') # Background color index write_bytes(b'\x00') # Pixel Aspect Ratio # Global Color Table (3 colors: white, red, transparent) write_bytes(b'\xFF\xFF\xFF') # White (index 0) write_bytes(b'\xFF\x00\x00') # Red (index 1) write_bytes(b'\x00\x00\x00') # Black (for transparency) (index 2) # Graphics Control Extension (for transparency) write_bytes(b'\x21\xF9') # Extension introducer and label write_bytes(b'\x04') # Byte size write_bytes(b'\x01') # Flags write_bytes(b'\x00\x00') # Delay time write_bytes(b'\x02') # Transparent color index write_bytes(b'\x00') # Block terminator # Image Descriptor write_bytes(b'\x2C') # Image separator write_bytes(b'\x00\x00\x00\x00') # Image left, top position write_bytes(width.to_bytes(2, 'little')) # Image width write_bytes(height.to_bytes(2, 'little')) # Image height write_bytes(b'\x00') # Local color table flag # Image Data # Create the triangle image data pixels = [] for y in range(height): for x in range(width): # Define triangle points (centered) if (y >= height//2 - x//2 and y >= -height//2 + x//2 and y <= height//2 + 50): pixels.append(1) # Red else: pixels.append(0) # White # LZW minimum code size write_bytes(b'\x08') # LZW encode the pixel data def lzw_encode(pixels): code_size = 8 clear_code = 1 << code_size end_code = clear_code + 1 # Initialize dictionary with basic codes dictionary = {(i,): i for i in range(clear_code)} current_code = end_code + 1 max_code = (1 << 12) - 1 # Start with clear code output_codes = [clear_code] current_sequence = [] for pixel in pixels: current_sequence.append(pixel) current_tuple = tuple(current_sequence) if current_tuple not in dictionary: # Output the code for the sequence without the last pixel output_codes.append(dictionary[tuple(current_sequence[:-1])]) # Add new sequence to dictionary if we haven't reached max size if current_code <= max_code: dictionary[current_tuple] = current_code current_code += 1 current_sequence = [pixel] # Output the code for any remaining sequence if current_sequence: output_codes.append(dictionary[tuple(current_sequence)]) # End with end code output_codes.append(end_code) return output_codes # Convert codes to bytes and write them codes = lzw_encode(pixels) current_byte = 0 current_bits = 0 code_size = 9 buffer = [] for code in codes: current_byte |= (code << current_bits) current_bits += code_size while current_bits >= 8: buffer.append(current_byte & 0xFF) current_byte >>= 8 current_bits -= 8 if current_bits > 0: buffer.append(current_byte) # Write the buffer in blocks for i in range(0, len(buffer), 255): block = buffer[i:i+255] write_bytes(bytes([len(block)])) write_bytes(bytes(block)) # End of image data write_bytes(b'\x00') # Trailer write_bytes(b'\x3B') |
Running the following program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | import sys def write_bytes(data): sys.stdout.buffer.write(data) # GIF Header write_bytes(b'GIF89a') # Logical Screen Descriptor width = 200 height = 200 write_bytes(width.to_bytes(2, 'little')) # Width write_bytes(height.to_bytes(2, 'little')) # Height write_bytes(b'\x80') # Global Color Table flag, Color Resolution write_bytes(b'\x00') # Background color index write_bytes(b'\x00') # Pixel Aspect Ratio # Global Color Table (3 colors: white, red, transparent) write_bytes(b'\xFF\xFF\xFF') # White (index 0) write_bytes(b'\xFF\x00\x00') # Red (index 1) write_bytes(b'\x00\x00\x00') # Black (for transparency) (index 2) # Graphics Control Extension (for transparency) write_bytes(b'\x21\xF9') # Extension introducer and label write_bytes(b'\x04') # Byte size write_bytes(b'\x01') # Flags write_bytes(b'\x00\x00') # Delay time write_bytes(b'\x02') # Transparent color index write_bytes(b'\x00') # Block terminator # Image Descriptor write_bytes(b'\x2C') # Image separator write_bytes(b'\x00\x00\x00\x00') # Image left, top position write_bytes(width.to_bytes(2, 'little')) # Image width write_bytes(height.to_bytes(2, 'little')) # Image height write_bytes(b'\x00') # Local color table flag # Image Data # Create the triangle image data pixels = [] for y in range(height): for x in range(width): # Define triangle points (centered) if (y >= height//2 - x//2 and y >= -height//2 + x//2 and y <= height//2 + 50): pixels.append(1) # Red else: pixels.append(0) # White # LZW minimum code size write_bytes(b'\x08') # LZW encode the pixel data def lzw_encode(pixels): code_size = 8 clear_code = 1 << code_size end_code = clear_code + 1 # Initialize dictionary with basic codes dictionary = {(i,): i for i in range(clear_code)} current_code = end_code + 1 max_code = (1 << 12) - 1 # Start with clear code output_codes = [clear_code] current_sequence = [] for pixel in pixels: current_sequence.append(pixel) current_tuple = tuple(current_sequence) if current_tuple not in dictionary: # Output the code for the sequence without the last pixel output_codes.append(dictionary[tuple(current_sequence[:-1])]) # Add new sequence to dictionary if we haven't reached max size if current_code <= max_code: dictionary[current_tuple] = current_code current_code += 1 current_sequence = [pixel] # Output the code for any remaining sequence if current_sequence: output_codes.append(dictionary[tuple(current_sequence)]) # End with end code output_codes.append(end_code) return output_codes # Convert codes to bytes and write them codes = lzw_encode(pixels) current_byte = 0 current_bits = 0 code_size = 9 buffer = [] for code in codes: current_byte |= (code << current_bits) current_bits += code_size while current_bits >= 8: buffer.append(current_byte & 0xFF) current_byte >>= 8 current_bits -= 8 if current_bits > 0: buffer.append(current_byte) # Write the buffer in blocks for i in range(0, len(buffer), 255): block = buffer[i:i+255] write_bytes(bytes([len(block)])) write_bytes(bytes(block)) # End of image data write_bytes(b'\x00') # Trailer write_bytes(b'\x3B') |
b'GIF89a\xc8\x00\xc8\x00\x80\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x00!\xf9\x04\x01\x00\x00\x02\x00,\x00\x00\x00\x00\xc8\x00\xc8\x00\x00\x08\xff\x00\x01\x08\x1cH\xb0\xa0\xc1\x83\x08\x13*\\\xc8\xb0\xa1\xc3\x87\x10#J\x9cH\xb1\xa2\xc5\x8b\x183j\xdcH1@\x00\x8e C\x8a\x1cI\xb2\xa1G\x8f%S\xaa\\\xc9\xd2\xe1\xc9\x93-c\xca\x9c\x19\xf2\xe5K\x9a8s\xeadh\xd3\xe6\xce\x9f@q\xf6\xec\x19\xb4\xa8Q\x92C\x87\x1e]\xca\xd4b\xd2\xa4M\xa3J]\xf8\xf4\xe9\xd4\xabX\xabV\xc5\xca\x95\xa9V\xad]\xc3\x02\xfd\xfaU\xacY\x9ad\xc9\x9e]\xbb2mZ\xb6pE\xbau\x1b\xb7n\xc6\xb9s\xed\xea\x9d\x88\x17\xef\xde\xbf&\xfb\xfa\x05L\xd8\xa0`\xc1\x85\x13\x038|X1`\xc6\x8c\x1d\xeb\x85\x0cYr\\\xca\x94-\xaf\xc5\x8cY\xb3X\xce\x9c=s\x05\rZ\xf4T\xd2\xa4M7E\x8dZ\xf5Q\xd6\xac]\x07\x85\r[\xf6N\xda\xb4m\x0b\xc5\x9d[wL\xde\xbc}\xb3\x04\x0e\\xJ\xe2\xc4\x8d\x8fD\x8e\\9H\xe6\xcc\x9dk\x84\x0e]\xfaE\xea\xd4\xadw\xc4\x9e];D\xee\xdc\xbd\xbb\xff\x04\x1f^\xbcB\xf2\xe4\xcd#D\x8f^}A\xf6\xec\xdd\x0b\x84\x0f\xdf=}\xfa\xe6\xef\xdf\xf7\xae_\xbf\xf5\xfe\xfd\x9d\x03\x08p|\xc0\x80\xdf\x06\x0e\xdcN\x90\xe05\x83\x06\xa7\x1f<\xf8,a\xc2\xe5\n\x15\x1ec\xc8\x90x\xc3\x86\xc2\x1e>\xfc\r\x11b2\x89\x12\x97O\x94\x88\xabb\xc5\xe6\x16/>\xc3h\x11v\xc6\x8c\xd16n\x9c\xceqc*\x8f\x1e\xab\x7f\x04y-\xe4\xc7\xd1"Ef#Ir{I\x92\x9dN\x9e\xec\x8e\xb2d&\x95*\xbf\xafdi\xab\xe5\xca\xca.]J\x82\t\xb3|L\x99\xe7f\xc6tL\x93f:\x9b6\xd7\xdf\xb4y*\xe7\xcd\xf6:w"\xe2\xc9\xf3}O\x9f\xc0~\xfe\x9c\x0f\xf4gP\xa1B\x07\x0f\x1d:\xach\xd1\xc0F\x8d\xe6C\x9aT\xa9\xd2\xa5K\x992m\xda\xd4\xa9\xd3\xa7O\xa1B\x8d\x1aU\xaa\xd4\xa9S\xa9R\xadZ\xd5\xaa\xd5\xabW\xb1b\xcd\x9aU\xab\xd6\xad[\xb9r\xed\xda\xd5\xab\xd7\xaf_\xc1\x82\r\x1bV\xacm\xd8\xb1c\xc9\x92-[\xd6\xac\xd9\xb3g\xd1\xa2M\x9bV\xad\xda\xb5k\xd9\xb2m\xdb\xd6\xad[f\xf9\xe0\xc2\x8d\x1bW\xae\xdc\xb9s\xe9\xd2\xad[\xd7\xae\xdd\xbbw\xf1\xe2\xcd\x9bW\xaf\xde\xbd{\xf9\xf2\xed\xdb\xd7\xaf\xdf\xbf\x7f\x01\x03\x0e\x1cX\xb0\xe0\xc1\x83\t\x13.\\\xd8\xb0\xe1\xc3\x87\x11#N\x9cX\xb1\xe2\xc5\x8b\x193n\xdc\xd8\xb1\xe3\xc7\x8f!C\x8e\x1c\x197 \x00;'
Describe the shapes in this image and their color
broken data stream when reading image file
Testing if the previous output contains the string red
: False
Testing if the previous output contains the string triangle
: False
Write a python program that, manually, draws a red triangle on a white background and saves it as a 200x200 gif file. Do not use any graphics libraries. Write the gif byte by byte. Output the gif file to stdout. I will evaluate your program by running `python your_soln.py > /tmp/a.gif` and then view the output file.
Write a python program that, manually, draws a red triangle on a white background and saves it as a 200x200 gif file. Do not use any graphics libraries. Write the gif byte by byte. Output the gif file to stdout. I will evaluate your program by running `python your_soln.py > /tmp/a.gif` and then view the output file.
Here's a Python program that creates a GIF file byte by byte, drawing a red triangle on a white background:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | import sys def write_int16(value): return bytes([value & 0xFF, (value >> 8) & 0xFF]) def write_int24(value): return bytes([value & 0xFF, (value >> 8) & 0xFF, (value >> 16) & 0xFF]) # GIF header header = b'GIF89a' # Logical Screen Descriptor width = 200 height = 200 packed = 0b10010001 # Global Color Table present, 2 colors background_color = 0 aspect_ratio = 0 lsd = write_int16(width) + write_int16(height) + bytes([packed, background_color, aspect_ratio]) # Global Color Table (2 colors: white and red) gct = b'\xFF\xFF\xFF' # White (RGB) gct += b'\xFF\x00\x00' # Red (RGB) # Graphics Control Extension gce = b'\x21\xF9\x04\x00\x00\x00\x00\x00' # Image Descriptor image_left = 0 image_top = 0 packed_id = 0 id = b'\x2C' + write_int16(image_left) + write_int16(image_top) + \ write_int16(width) + write_int16(height) + bytes([packed_id]) # Image data # Create the image data (white background with red triangle) pixels = [] for y in range(height): for x in range(width): # Define triangle points # Simple triangle in the middle of the image if (y > 50 and y < 150 and # Vertical bounds x > (width//2 - (y-50)) and # Left diagonal x < (width//2 + (y-50)) and # Right diagonal y < 150): # Bottom line pixels.append(1) # Red else: pixels.append(0) # White # LZW minimum code size lzw_min_code_size = 2 image_data = bytes([lzw_min_code_size]) # Simple LZW compression clear_code = 4 end_code = 5 next_code = 6 code_size = 3 buffer = [] current_byte = 0 bit_count = 0 output = [] # Write clear code buffer.extend([clear_code & 0xFF]) # Process pixels for pixel in pixels: buffer.append(pixel) while len(buffer) >= 8: output.append(buffer[:8]) buffer = buffer[8:] # Pad remaining bits if buffer: while len(buffer) < 8: buffer.append(0) output.append(buffer) # Convert bit arrays to bytes compressed_data = [] for byte_bits in output: byte = 0 for bit in byte_bits: byte = (byte << 1) | bit compressed_data.append(byte) # Write data in blocks block_size = 255 for i in range(0, len(compressed_data), block_size): block = compressed_data[i:i + block_size] image_data += bytes([len(block)]) + bytes(block) # End of image data image_data += b'\x00' # GIF trailer trailer = b'\x3B' # Write all parts to stdout sys.stdout.buffer.write(header + lsd + gct + gce + id + image_data + trailer) |
1 | python program.py > output.gif |
I extracted the following code from that output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | import sys def write_int16(value): return bytes([value & 0xFF, (value >> 8) & 0xFF]) def write_int24(value): return bytes([value & 0xFF, (value >> 8) & 0xFF, (value >> 16) & 0xFF]) def main(): # GIF header header = b'GIF89a' # Logical Screen Descriptor width = 200 height = 200 packed = 0b10010001 # Global Color Table present, 2 colors background_color = 0 aspect_ratio = 0 lsd = write_int16(width) + write_int16(height) + bytes([packed, background_color, aspect_ratio]) # Global Color Table (2 colors: white and red) gct = b'\xFF\xFF\xFF' # White (RGB) gct += b'\xFF\x00\x00' # Red (RGB) # Graphics Control Extension gce = b'\x21\xF9\x04\x00\x00\x00\x00\x00' # Image Descriptor image_left = 0 image_top = 0 packed_id = 0 id = b'\x2C' + write_int16(image_left) + write_int16(image_top) + \ write_int16(width) + write_int16(height) + bytes([packed_id]) # Image data # Create the image data (white background with red triangle) pixels = [] for y in range(height): for x in range(width): # Define triangle points # Simple triangle in the middle of the image if (y > 50 and y < 150 and # Vertical bounds x > (width//2 - (y-50)) and # Left diagonal x < (width//2 + (y-50)) and # Right diagonal y < 150): # Bottom line pixels.append(1) # Red else: pixels.append(0) # White # LZW minimum code size lzw_min_code_size = 2 image_data = bytes([lzw_min_code_size]) # Simple LZW compression clear_code = 4 end_code = 5 next_code = 6 code_size = 3 buffer = [] current_byte = 0 bit_count = 0 output = [] # Write clear code buffer.extend([clear_code & 0xFF]) # Process pixels for pixel in pixels: buffer.append(pixel) while len(buffer) >= 8: output.append(buffer[:8]) buffer = buffer[8:] # Pad remaining bits if buffer: while len(buffer) < 8: buffer.append(0) output.append(buffer) # Convert bit arrays to bytes compressed_data = [] for byte_bits in output: byte = 0 for bit in byte_bits: byte = (byte << 1) | bit compressed_data.append(byte) # Write data in blocks block_size = 255 for i in range(0, len(compressed_data), block_size): block = compressed_data[i:i + block_size] image_data += bytes([len(block)]) + bytes(block) # End of image data image_data += b'\x00' # GIF trailer trailer = b'\x3B' # Write all parts to stdout sys.stdout.buffer.write(header + lsd + gct + gce + id + image_data + trailer) if __name__ == "__main__": main() |
Running the following program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | import sys def write_int16(value): return bytes([value & 0xFF, (value >> 8) & 0xFF]) def write_int24(value): return bytes([value & 0xFF, (value >> 8) & 0xFF, (value >> 16) & 0xFF]) def main(): # GIF header header = b'GIF89a' # Logical Screen Descriptor width = 200 height = 200 packed = 0b10010001 # Global Color Table present, 2 colors background_color = 0 aspect_ratio = 0 lsd = write_int16(width) + write_int16(height) + bytes([packed, background_color, aspect_ratio]) # Global Color Table (2 colors: white and red) gct = b'\xFF\xFF\xFF' # White (RGB) gct += b'\xFF\x00\x00' # Red (RGB) # Graphics Control Extension gce = b'\x21\xF9\x04\x00\x00\x00\x00\x00' # Image Descriptor image_left = 0 image_top = 0 packed_id = 0 id = b'\x2C' + write_int16(image_left) + write_int16(image_top) + \ write_int16(width) + write_int16(height) + bytes([packed_id]) # Image data # Create the image data (white background with red triangle) pixels = [] for y in range(height): for x in range(width): # Define triangle points # Simple triangle in the middle of the image if (y > 50 and y < 150 and # Vertical bounds x > (width//2 - (y-50)) and # Left diagonal x < (width//2 + (y-50)) and # Right diagonal y < 150): # Bottom line pixels.append(1) # Red else: pixels.append(0) # White # LZW minimum code size lzw_min_code_size = 2 image_data = bytes([lzw_min_code_size]) # Simple LZW compression clear_code = 4 end_code = 5 next_code = 6 code_size = 3 buffer = [] current_byte = 0 bit_count = 0 output = [] # Write clear code buffer.extend([clear_code & 0xFF]) # Process pixels for pixel in pixels: buffer.append(pixel) while len(buffer) >= 8: output.append(buffer[:8]) buffer = buffer[8:] # Pad remaining bits if buffer: while len(buffer) < 8: buffer.append(0) output.append(buffer) # Convert bit arrays to bytes compressed_data = [] for byte_bits in output: byte = 0 for bit in byte_bits: byte = (byte << 1) | bit compressed_data.append(byte) # Write data in blocks block_size = 255 for i in range(0, len(compressed_data), block_size): block = compressed_data[i:i + block_size] image_data += bytes([len(block)]) + bytes(block) # End of image data image_data += b'\x00' # GIF trailer trailer = b'\x3B' # Write all parts to stdout sys.stdout.buffer.write(header + lsd + gct + gce + id + image_data + trailer) if __name__ == "__main__": main() |
b'Traceback (most recent call last):\n File "/usr/src/app/main.py", line 105, in <module>\n main()\n File "/usr/src/app/main.py", line 93, in main\n image_data += bytes([len(block)]) + bytes(block)\n ^^^^^^^^^^^^\nValueError: bytes must be in range(0, 256)\n'
Describe the shapes in this image and their color
cannot identify image file <_io.BytesIO object at 0x7f10955881d0>
Testing if the previous output contains the string red
: False
Testing if the previous output contains the string triangle
: False