- Enforce allowed file extensions (PNG, JPG, JPEG) and intentionally reject GIFs because OpenCV’s decoder is unreliable for animated GIFs.
- Verify file contents using
imghdrand Pillow to prevent renamed non-image files from being accepted. - Require and validate a
qualityparameter (integer between 0 and 100). - Decode and re-encode images using OpenCV and return a validated JPEG binary response.
- Return structured JSON errors with appropriate HTTP status codes for each failure case.

Upload route: validation overview
The upload route should perform these checks, in order:- Confirm the
imagefile part exists and the filename is not empty. - Secure the filename and enforce allowed extensions:
png,jpg,jpeg. - Read the file bytes once, then verify content:
- Use
imghdrto detect the image signature in the bytes. - Use Pillow (
Image.verify()) for an additional sanity check.
- Use
- Require a
qualityform parameter and validate it as an integer in[0, 100]. - Decode the bytes with OpenCV, process and re-encode as JPEG with the requested
quality. - Validate the processed output with Pillow before returning it as
image/jpeg. - Return clear JSON errors and proper HTTP status codes for every failure branch.
If you must accept GIFs, decode them with Pillow (e.g., iterate frames) and convert a chosen frame(s) to an image OpenCV can process. OpenCV’s
imdecode is not suitable for animated GIF decoding.How to test
-
Postman (form-data)
- URL: POST
http://127.0.0.1:5000/upload - Body (form-data)
- Key:
image— File: DSC08804.JPG - Key:
quality— Text:100
- Key:
- URL: POST
- curl example (uploads a JPEG at quality 100):
Common test cases and expected responses
Additionally, the same JSON examples are shown here as sample responses:
- Missing file:
- Empty filename:
- Disallowed extension:
- Wrong file content:
- Missing or invalid quality parameter:
- Failed to decode with OpenCV:
Example server logs
Why multi-layer validation matters
- File extension checks provide a fast fail for obvious bad uploads.
imghdrinspects raw file bytes and prevents trivial bypass by renaming files.- Pillow’s
Image.verify()ensures the bytes represent a valid image file structure. - OpenCV is used for image processing and re-encoding, but it requires decodable bytes — hence the prior validations.
- Together, these layers improve security and robustness while producing deterministic failure responses for clients.
Next steps
With the backend validated and robust error handling in place, you can:- Build a React front-end to consume this API and show upload progress and errors.
- Add rate limiting and size limits to prevent abuse.
- Implement background processing (e.g., Celery) for heavy image transformations.
- If GIF support is required, use Pillow to extract frames and convert frames to an OpenCV-friendly format.
- Flask file upload docs
- Pillow (PIL Fork) documentation
- OpenCV Python tutorials
- imghdr — Determine file type of images
- Cursor course on KodeKloud