惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cisco Talos Blog
Cisco Talos Blog
量子位
小众软件
小众软件
Microsoft Azure Blog
Microsoft Azure Blog
V
Visual Studio Blog
I
InfoQ
Jina AI
Jina AI
The Cloudflare Blog
Recorded Future
Recorded Future
Recent Announcements
Recent Announcements
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
G
Google Developers Blog
Stack Overflow Blog
Stack Overflow Blog
阮一峰的网络日志
阮一峰的网络日志
Microsoft Security Blog
Microsoft Security Blog
美团技术团队
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Martin Fowler
Martin Fowler
T
Tailwind CSS Blog
博客园 - Franky
酷 壳 – CoolShell
酷 壳 – CoolShell
F
Fortinet All Blogs
WordPress大学
WordPress大学
P
Proofpoint News Feed
D
DataBreaches.Net
爱范儿
爱范儿
雷峰网
雷峰网
D
Docker
B
Blog
Engineering at Meta
Engineering at Meta
腾讯CDC
N
Netflix TechBlog - Medium
C
Check Point Blog
博客园 - 【当耐特】
Apple Machine Learning Research
Apple Machine Learning Research
T
Tenable Blog
GbyAI
GbyAI
Security Archives - TechRepublic
Security Archives - TechRepublic
博客园 - 三生石上(FineUI控件)
T
The Blog of Author Tim Ferriss
博客园 - 聂微东
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
SecWiki News
SecWiki News
S
Security @ Cisco Blogs
S
Security Affairs
V
V2EX
Application and Cybersecurity Blog
Application and Cybersecurity Blog
云风的 BLOG
云风的 BLOG
C
CERT Recently Published Vulnerability Notes
Y
Y Combinator Blog

Stonecharioteer on Tech

I Traced My Traffic Through a Home Tailscale Exit Node What Was I Reading Last? In Three Not-So-Easy Pieces Dogfooding Is Hard Code blocks in your books, finally GoForGo v0.9.0 Merrilin - We built an app to read books I use a Macbook now Data Structures & Algorithms - Preparing for Interviews Using a local DNS namespace for local service discovery Direction KOllector - Publishing KOReader Highlights gbt: branches touched in the last 24 hours A Soiree into Symbols in Ruby Some Smalltalk about Ruby Loops Ruby Blocks Returning from Ruby Blocks, Procs and Lambdas My Linux Laptop Finally Works: How Claude Helped Me Fix Years of Annoyances TIL: Watchexec - Modern File Watching for Development Workflows A Less Busy Mind GoForGo - Learn Go through live examples Migrating My Old Blog to Hugo with Claude The Qtile Window Manager: A Python-Powered Tiling Experience Read the RFCs that Built the Internet Py-x-Protobuf - Or How I Learned to Stop Worrying and Love Protocol Buffers Python Reverse a List New Beginnings Leaving ChainSafe Systems Screen Lock for Cinnamon Desktop using Zenity and Terminal Commands Crews Not Teams A System for Getting Better at LeetCode So Far So Rust Retrying HTTP Requests with Rust A Primer on Control Charts Learning Rust Explicit is Better than Implicit: Rust for Pythonistas Using Custom Delimiters in Jinja Templates TIL: Creating Fixed Length Iterables in Python Documentation Without Assumption Vagrant Python - A Reflection in 2022 Learning Golang No, A Virtual Machine Is Not Enough: Why Developers Need Native Linux Empathy in Tech For Those Who Came in Late A Weekend With PostgreSQL TIL: Gooey and Python Fire for Quick GUIs and CLIs TIL: 2ality - Dr. Axel Rauschmayer's JavaScript Blog TIL: MassDNS - High-Performance Bulk DNS Lookups TIL: Matomo Analytics, Google Tech Writing, Memory Programming, and NES TV Signals TIL: MontyDB - MongoDB Implemented in Python Returning to the Craft of Programming TIL: CPUFetch, OneFetch, and Learn CSS TIL: DNS Performance Testing and Pi-hole with Unbound TIL: Eli Bendersky's Blog, Awesome By Example, NoCoDB, and Martin Kleppmann TIL: CRDTs, Extreme HTTP Performance, and BYTEPATH Game TIL: AutoInvent, ASGI, Python Packaging, RAPIDS GPU Computing, and FlaskCon TIL: MangaDesk - Terminal Client for MangaDex TIL: McFly - Smart Shell History Search TIL: Siege Load Testing and Awesome FastAPI Resources TIL: Ventoy Bootable USB and Justniffer Network Analysis TIL: CLI Code Review, Git Split Diffs, and Internal Combustion Engine TIL: Benford's Law, Web Security Headers, Event Sourcing, and Mozilla Security Guidelines How to Write Documentation - The README.md File The Importance of Documentation TIL: NNgroup UX Research, SponsorBlock, and Labella Python Library TIL: The Little Book of Rust Macros and Rust Performance Book TIL: Git-Bug Distributed Issue Tracker and Omni Kubernetes Monitoring TIL: Zellij - Modern Terminal Multiplexer TIL: How Discord Handles 2.5 Million Concurrent Voice Users TIL: Volumio - The Audiophile Music Player TIL: Areopagitica - Milton's Defense of Free Speech TIL: Fast Node Manager, Zoxide Smart CD, Technical Writing, PyO3, and Qubes OS TIL: Slurm Workload Manager for HPC Clusters TIL: Data Visualization Guide and Oso Authorization Academy TIL: CORS Deep Dive, Piku Tiny PaaS, Rust Strings, and Deno Standard Library TIL: Raspberry Pi OS Development, Vim Beginner Guide, Password Management, and QueryBook TIL: uBlock Origin Performance Optimization on Firefox TIL: Breaking PostgreSQL at Scale and LeetCode Problem Patterns TIL: Awesome Tmux Resources for Terminal Multiplexing TIL: Grit - A Multitree-Based Personal Task Manager TIL: Lens 4.2 Kubernetes IDE, Shell Scripting Guide, and Dark HTTP Server Do The Job You Hate So You Won't Hate The Job You Love TIL: Innernet VPN Solution and NoteCalc Calculator App TIL: Argo CD for GitOps and Lens Kubernetes IDE TIL: Modern Rust CLI Tools - System Monitoring, HTTP Requests, and DNS TIL: tz - A Time Zone Helper Tool TIL: Distributed Systems Education, Fallacies, and Self-Hosted Internet Archiving TIL: Real-Time Voice Cloning Technology TIL: ChartMuseum for Helm, AMD's Corporate Journey, and Kubernetes Pod Scaling TIL: Docker and Kubernetes Tools - Whaler, Descheduler, and Dive TIL: Post-Mortem Collection, Terminal Plotting, and Technical Twitter TIL: Dark Mode Toggle Web Component by Google Chrome Labs TIL: Python eval(), exec(), and compile() Functions TIL: Camelot PDF Tables, PostgreSQL Row Level Security, Zerodha Varsity, and Write Yourself a Git TIL: fuser Command for Process and File Investigation TIL: i Hate Regex - The Ultimate Regex Cheat Sheet TIL: Dolt - Git for Data and Database Version Control TIL: x86 Assembly Programming and SafeEyes Break Reminder TIL: Comprehensive Distributed Systems Reading List TIL: Cosmopolitan C Library, Distributed Systems Book, High Performance Browser Networking, and Rust Roguelike Tutorial
Leonardo - Generating Product Unique Specification Images Using Python
2018-11-15 · via Stonecharioteer on Tech

Legal Notice

The images used here are the property of Flipkart, and their respective brands. They are used here only in an educational/informative vein.

When I was at Flipkart in the Content Team, my manager brought up an interesting project for the Graphic Designers in our team. He said Flipkart was going to invest in the creation of product images that would replace content. It was going to be an image where a prospective buyer could see the key specifications of the project arrayed around the product image in a neat fashion.

He was talking about doing this manually for a few hundred thousand products.

The Python Opportunity

When people talk about how they use Python at work, they’re usually talking about data munging, visualization or automation. A different subset uses it for Django or Flask.

I started with Python to help the team collate information related to content written by them, and prevent rewriting duplicates.

I was still a greenhorn when it came to Python in those days, but I’d learnt how useful image processing libraries could be. I used to watermark images using IrfanView, and I’d seen that Gimp had Python plugins. I wondered if I could use that to help my team out.

Could Python be used to generate images?

I offered to try and do something to automate the grunt work: selecting the product image, getting the specifications and selecting appropriate icons, choosing what images to place and placing them exactly in the center, ensuring that the product brand logo and the Flipkart brand logo would appear at the top left corner, and that the Flipkart logo would always be just a little larger than the product brand logo, for instance.

He said I should try doing this. Frankly, I wondered if I was in over my head. I keep doing this to myself.

Building the Canvas

The first step was generating a canvas. I needed something with a 9:14 resolution, according to the requirement.

I defined a custom class for this image: the USPImage class.

One of the methods, named prepareCanvas, would then take the aspect ratio provided to it, and the width, and, as if the name was not obvious, prepare the canvas.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
def prepareCanvas(self, aspect_ratio, image_width):
    """Prepares a canvas for plotting the image.
    This canvas's size is the limiting factor
    for the entire image.

    Args:
        aspect_ratio: list    [w,l]
        image_width: int      w
    """
    image_height = math.ceil(
            image_width*aspect_ratio[1]/aspect_ratio[0])
    canvas_size = (int(image_width), int(image_height))
    self.canvas = Image.new("RGBA", canvas_size, (255,255,255,255))

The Image class comes from the PIL Python library. That’s a handy library that made this entire project possible. It provides an abstraction for images as matrixes of RGBA values at each row x column intersection. But it doesn’t offer any of the readymade tools provided in image processing software such as Photoshop or Gimp.

But it does provide you the highest degree of control you could want.

Using a canvas size of 1800, I could instantiate an image canvas just by using self.prepareCanvas((9,14),1800).

The Joy of a Blank Canvas

I wonder if Leonardo Da Vinci felt this way, staring at a blank canvas with glee.

I had a canvas!

Coordinate Geometry in Practice

Now I had a problem I hadn’t encountered in many years. One of co-ordinate geometry. I was pleased that I could use the stuff I learnt not only in high-school, but also in my undergraduate program, studying mechanical engineering, to good use.

I had to place objects on the canvas, in an organized fashion.

The first image I had to place was the product image. And I had another problem.

I didn’t have access to the image repository at Flipkart. I didn’t quite have the time to ask my manager if I could tap into the CDN, so I just wrote a method to download the images off the website.

What I didn’t realize was that I’d have a tough time cleaning the images.

Image Processing Challenges

A simple “remove all white pixels” seemed like the obvious answer, but soon, I realized that was quite naive. Instead, I had to work on a different algorithm. And I had another problem, since the background color wasn’t quite uniform across product images.

To solve this, I had to sweep through the edges of the images, allowing my code to make an educated guess about the background colour. Once the code identified the colour, it swept through the image row by row, from left to right. It stopped whenever it encountered a drastic change in colours. “There,” I told myself," is the product."

Obviously, I had to redo this from right to left. I checked the results once the code completed, and I realized where I had been wrong. There were products where there were “hollow-points.” The space between headphones, for instance. Or the space between the legs of a TV. So I had the code redo this operation from top to bottom, and bottom to top. And then, I had a repository of images to take the product from.

Precise Placement Logic

Once I had the image, it was back to the canvas for me. I had to place the image at the very center, according to the brand’s guidelines.

Pillow’s Image class allows easy placement of another Image object at a given x,y location. However, it doesn’t really place them at the center.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
def getParentImageCoords(
                base_image_size, parent_image_size,
                parent_image_positioning):
    """Returns the coordinates for the parent/product image.
    Args:

        base_image_size: tuple (w,h)
        parent_image_size: tuple (w,h)
        parent_image_positioning: tuple (x_pos, y_pos)
        These are in factors from 0-1.0, indicating
        where the image should be placed on the canvas.    """
    base_width, base_height = base_image_size
    parent_width, parent_height = parent_image_size
    x_pos_factor, y_pos_factor = parent_image_positioning
    x_pos = int((base_width-parent_width)*x_pos_factor)
    y_pos = int((base_height-parent_height)*y_pos_factor)
    return (x_pos, y_pos)

Placing a product image at the very center was the first step.

Placing the product at the center

Once I had this down, I had the next steps to solve. Placing icons around the product image. This was pretty straightforward.

Placing icons around the product image in a circle

However, there was something I did not consider. The specification icons were also going to have some text underneath. I had to make sure that the text would, in no circumstances, overlap with the other icons or any other text.

Sample Generated Images

The final results were impressive. Here are some examples of the specification images Leonardo generated:

Sample USP Image created using Python

Everything was customizable

Advanced Layout Challenges

This was quite harder to sort. So instead of just placing the icon and then placing the text, I ensured that I created the Icon object with text underneath, and then calculated what positions to place the icons in.

That simplified the problem, and ensured that the icons would be spaced apart.

With this first version I had only to refine the solution. I received additional instructions and directives, such as placing the Flipkart logo and the brand logo on the image, choosing a background image randomly from a repository of background images, changing the color of the icon to a suitable palette predetermined by the graphic designers, based on the background colors.

In all honesty, it was the most fun I had had with programming until that day.

The Moment of Truth

As I was doing this, my manager told me that the Catalog team was looking at outsourcing this work, to a graphics company that would charge us a bomb. Thanks to the additional pressure, I was able to finish the prototype tool, which I dubbed Leonardo (after both the artist and the Teenage Mutant Ninja Turtle).

On the day of reckoning, my manager told me that the inhouse artists could deliver 5 images per day. The external company was promising about 30 per day, at an exhorbitant price.

He asked me to show him what my tool could create.

He liked the quality of the work. It had some bugs to sort out, and I fixed the quality issues by increasing the DPI of the image. But he asked how much time one image takes to render.

I didn’t quite understand what he meant. I ran my program in front of him, using the icon pool that the graphics designers had created over the past few weeks and we timed it.

The Results

12,000 images in one hour.

What’s more, when he came back with some strange requirements for the logo, all I had to do was rerun the script with the new rules and we were set.

Technical Architecture

Leonardo used several key Python libraries:

Core Libraries

  • Python Pillow (PIL): Image processing and canvas manipulation
  • Beautiful Soup: Web scraping for product specifications
  • PyQt4: GUI interface for the tool
  • Requests: HTTP requests for image downloads

Key Features

  • Automated Product Extraction: Background removal and product isolation
  • Dynamic Layout Engine: Intelligent spacing of icons and text
  • Brand Compliance: Automatic logo placement and sizing
  • Batch Processing: Mass generation of thousands of images
  • Quality Control: DPI optimization and color palette management

Performance Characteristics

  • Speed: 12,000 images per hour
  • Consistency: Uniform layout and branding across all images
  • Flexibility: Easy rule changes and instant regeneration
  • Scalability: Handled hundreds of thousands of products

Lessons Learned

Doing this project made me realize what Python could be used for. I’m not sure I could understand it then. I was a poor programmer, and I didn’t know many things I probably should have. The application was used for a couple of months after I left, and then that project was scrapped.

However, it does answer a simple question:

Python can be used for graphic design.

And it should be, because there are so many things you can automate in that world.

Project Impact

Business Value

  • Cost Savings: Eliminated need for expensive external graphics company
  • Speed: From 30 images/day to 12,000 images/hour
  • Consistency: Perfect brand compliance across all images
  • Flexibility: Instant updates when requirements changed

Technical Learning

  • Image Processing: Deep dive into pixel manipulation and coordinate geometry
  • Automation: Real-world application of Python for creative tasks
  • Problem Solving: Complex algorithms for background removal and layout
  • Performance: Optimizing for large-scale batch processing

Career Growth

This project taught me that programming could be creative, not just analytical. It showed me how automation could solve real business problems and demonstrated the power of thinking outside conventional solutions.

The project was eventually discontinued, but it proved a crucial point: with the right approach, code can replace even creative manual work, and do it better, faster, and more consistently.

Reflection

Sometimes the best solutions come from asking “what if we could automate this?” instead of accepting that manual work is the only way.


The source code for Leonardo, while no longer maintained, demonstrated how Python could bridge the gap between technical automation and creative design work. It remains one of my favorite examples of solving real-world problems with code.