Skip to main content

InstaResizerBot — Telegram Image Resizer for Instagram Aspect Ratios

Fit non-square portrait and landscape photos onto Instagram-ready canvases with solid white, black, transparent RGBA, or Gaussian-blurred backdrops directly inside Telegram via @InstaResizerBot.

InstaResizerBot Telegram Interface


Technical Architecture: Reverse-Engineering @InstaResizerBot​

When sharing non-square photos on Instagram, the platform crops portrait or landscape compositions. I engineered @InstaResizerBot as a stateless, event-driven service using python-telegram-bot and Pillow (PIL). Raw image payloads are streamed into memory, processed inside io.BytesIO buffers, and returned directly to Telegram without touching disk.

[ User Action ]
│
├──> 1. Select Mode via Callback ('/white', '/black', '/blur', '/transparent')
│ └── Store in context.user_data['action']
│
└──> 2. Send Image (Compressed Photo or Uncompressed Document File)
│
▼
[ Telegram Dispatcher ] ──> Handled by instaresizerbot_handle_message
│
├──> Download as Bytearray in Memory (io.BytesIO)
├──> Call core.process_image(file_bytes, command)
│ ├── Calculate 1.01 Aspect Ratio Bounds & Dynamic Canvas
│ ├── Apply Background Transformation (Solid Color, Gaussian Blur, RGBA)
│ └── Center-paste Original Media Matrix
│
└──> Return BytesIO stream direct to Telegram API (reply_photo)

Image Processing & Canvas Engineering​

The core transformation logic resides in instaresizerbot/core.py. To prevent Instagram's automated cropping algorithms from clipping edges while keeping the original image intact, a 1.01 dynamic offset expands the primary axis before centering the original photo.

1. Dynamic Aspect Ratio Bounds & Scaling Math​

from io import BytesIO
from PIL import Image, ImageFilter

def process_image(image_bytes: bytes, background_command: str) -> BytesIO:
original_image = Image.open(BytesIO(image_bytes))

# Calculate target bounding box dimensions
width, height = original_image.size
new_size = max(width, height)
if int(width) > int(height):
new_width = int(new_size * 1.01)
new_height = new_size
else:
new_height = int(new_size * 1.01)
new_width = new_size

# Resize image matrix to expanded canvas bounds
resized_image = original_image.resize((new_width, new_height))

2. Background Generation Algorithms​

Depending on the callback mode stored in context.user_data['action'], the canvas background is synthesized using one of four strategies:

if background_command == '/white':
final_image = Image.new('RGB', resized_image.size, (255, 255, 255))
elif background_command == '/black':
final_image = Image.new('RGB', resized_image.size, (0, 0, 0))
elif background_command == '/blur':
blurred_image = resized_image.filter(ImageFilter.GaussianBlur(radius=10))
final_image = Image.new('RGB', blurred_image.size)
if blurred_image.mode == 'RGBA':
final_image.paste(blurred_image, (0, 0), blurred_image)
else:
final_image.paste(blurred_image, (0, 0))
elif background_command == '/transparent':
final_image = Image.new('RGBA', resized_image.size, (0, 0, 0, 0))

3. Centering and Alpha Channel Handling​

The original image is centered on the generated canvas using mid-point offset coordinates:

paste_x = floor((new_width - width) / 2)
paste_y = floor((new_height - height) / 2)

If the incoming image contains an alpha channel (mode == 'RGBA'), it is composited using itself as an alpha mask to prevent black halo artifacts around transparent edges:

paste_x = int((new_width - width) / 2)
paste_y = int((new_height - height) / 2)

if original_image.mode == 'RGBA':
final_image.paste(original_image, (paste_x, paste_y), original_image)
else:
final_image.paste(original_image, (paste_x, paste_y))

output_buffer = BytesIO()
if background_command == '/transparent':
final_image.save(output_buffer, format="PNG")
else:
final_image.save(output_buffer, format="JPEG")

output_buffer.seek(0)
return output_buffer

Telegram Handler & Upload Modes​

In instaresizerbot/handlers.py, the bot inspects both compressed Telegram photo arrays (update.message.photo[-1]) and uncompressed document uploads (update.message.document) so photographers can preserve full resolution:

def register_instaresizerbot_handlers(dispatcher):
dispatcher.add_handler(CommandHandler('start', instaresizerbot_handle_start_message))
dispatcher.add_handler(CallbackQueryHandler(instaresizerbot_transform_callback, pass_user_data=True))
dispatcher.add_handler(MessageHandler(Filters.text, instaresizerbot_dontunderstand, pass_user_data=True, pass_chat_data=True))
dispatcher.add_handler(MessageHandler(Filters.photo | Filters.document, instaresizerbot_handle_message, pass_user_data=True, pass_chat_data=True))
dispatcher.add_handler(ChatMemberHandler(user_left, ChatMemberHandler.MY_CHAT_MEMBER))

Backdrop Modes Reference Table​

Command / CallbackCanvas Color SpaceBackground SynthesisOutput Format
/whiteRGB (255, 255, 255)Solid white matte borderJPEG
/blackRGB (0, 0, 0)Solid black matte borderJPEG
/blurRGBImageFilter.GaussianBlur(radius=10) of scaled sourceJPEG
/transparentRGBA (0, 0, 0, 0)Alpha-transparent margin paddingPNG

Memory Management and Security Guarantees​

  • Zero Disk Persistence: All byte streams operate within transient RAM allocations (io.BytesIO). Explicit output_buffer.close() calls inside finally blocks ensure immediate buffer reclamation.
  • Strict Extension Whitelisting: Document uploads validate against .jpg, .jpeg, .png, .bmp, .heic, .heif, .tiff, and .webp before downloading bytes from Telegram servers.
  • Isolated User State: Background mode selections are scoped to context.user_data, preventing cross-talk across concurrent chat sessions.

Get notified about updates to this tool

No spam. Just high-quality updates about new features and guides.