■ 🕑 1. GIF contrast adjustment
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
gifedit.py - Adjust contrast of a GIF by modifying its color palette.
Shouldn't touch anything but palette.
Usage:./gifedit.py input.gif contrast_factor
- input.gif: Path to the input GIF file.
- contrast_factor: Floating point number where 1.0 is identity,
>1.0 increases contrast, and <1.0 decreases contrast.
Output: A new GIF file with the contrast-adjusted palette, named after the input file with '_contrast_{factor}.gif' appended.
"""
import sys
import os
import struct
def adjust_contrast(rgb, factor):
"""
Apply contrast adjustment to a given RGB value.
:param rgb: The RGB value to adjust (as a tuple).
:param factor: Contrast factor (1.0 = no change, >1.0 increase, <1.0 decrease).
:return: Adjusted RGB value.
"""
r, g, b = rgb
r = int(((r / 255.0 - 0.5) * factor + 0.5) * 255.0)
g = int(((g / 255.0 - 0.5) * factor + 0.5) * 255.0)
b = int(((b / 255.0 - 0.5) * factor + 0.5) * 255.0)
return (max(0, min(255, r)), max(0, min(255, g)), max(0, min(255, b)))
def main():
if len(sys.argv)!= 3:
print("Usage:./gifedit.py input.gif contrast_factor")
sys.exit(1)
input_file = sys.argv[1]
try:
contrast_factor = float(sys.argv[2])
except ValueError:
print("Error: Contrast factor must be a floating point number.")
sys.exit(1)
if contrast_factor <= 0:
print("Warning: Contrast factor should be greater than zero. Proceeding with value:", contrast_factor)
# Load the GIF
try:
with open(input_file, 'rb') as f_in:
gif_data = f_in.read()
# Verify the GIF magic bytes
if gif_data[:6] not in [b'GIF87a', b'GIF89a']:
print("Error: Not a GIF file.")
sys.exit(1)
# Get the original file name without extension
filename, file_extension = os.path.splitext(input_file)
output_file = f"{filename}_contrast_{contrast_factor:.2f}{file_extension}"
# Determine the GCT size
gct_size_byte = gif_data[10] # 10th byte indicates GCT size (2^(N+1))
gct_size = 2 ** ((gct_size_byte & 0x07) + 1) # Extract the lower 3 bits
gct_start = 13 # GCT starts after the 12th byte (header + gct_size_byte)
gct_end = gct_start + gct_size * 3
# Extract and adjust the Global Color Table
gct = gif_data[gct_start:gct_end]
adjusted_gct = bytearray()
for i in range(0, len(gct), 3):
rgb = struct.unpack('<BBB', gct[i:i+3])
adjusted_rgb = adjust_contrast(rgb, contrast_factor)
adjusted_gct.extend(adjusted_rgb)
# Replace the original GCT with the adjusted one
gif_data = gif_data[:gct_start] + adjusted_gct + gif_data[gct_end:]
# Save the modified GIF data
with open(output_file, 'wb') as f_out:
f_out.write(gif_data)
print(f"Output saved to: {output_file}")
except IOError as e:
print(f"Error opening or processing the file: {e}")
if __name__ == "__main__":
main()