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.

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 / Callback | Canvas Color Space | Background Synthesis | Output Format |
|---|---|---|---|
/white | RGB (255, 255, 255) | Solid white matte border | JPEG |
/black | RGB (0, 0, 0) | Solid black matte border | JPEG |
/blur | RGB | ImageFilter.GaussianBlur(radius=10) of scaled source | JPEG |
/transparent | RGBA (0, 0, 0, 0) | Alpha-transparent margin padding | PNG |
Memory Management and Security Guarantees
- Zero Disk Persistence: All byte streams operate within transient RAM allocations (
io.BytesIO). Explicitoutput_buffer.close()calls insidefinallyblocks ensure immediate buffer reclamation. - Strict Extension Whitelisting: Document uploads validate against
.jpg,.jpeg,.png,.bmp,.heic,.heif,.tiff, and.webpbefore 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.
Related Tools
Related Posts
Learn how to detect Google AdSense on any website using Python. Covers fast HTML scanning with BeautifulSoup, ads.txt validation, and headless Playwright automation to bypass bot protection and lazy loading.
Learn how to easily download YouTube video thumbnails using Python's requests library, without the need for heavy dependencies like Pytube. This guide covers extracting video IDs from various YouTube URL formats and fetching the highest quality thumbnail available.
This piece will introduce Make (formerly Integromat) as a direct competitor to n8n, highlighting its visual, diagram-like workflow builder. The comparison will focus on key differences in pricing models, UI/UX, and advanced features like branching logic, which are a major selling point for Make. Examples will show how to build the same complex workflow in both n8n and Make to illustrate their unique approaches.