How to Accept JPG and PNG Files in HTML File Inputs
Use the HTML accept attribute for JPG and PNG pickers, then validate files securely on the server.
Use the accept attribute on the file input:
<input type="file" accept=".jpg,.jpeg,.png">
You can also specify MIME types:
<input type="file" accept="image/jpeg,image/png">
Both forms tell the browser which files to highlight in the picker. They do not prove that the selected file is a real JPEG or PNG, so your server must validate every upload before processing or storing it.
1. Basic HTML form
<form method="post" action="/upload" enctype="multipart/form-data">
<label for="image">Choose a JPG or PNG image</label>
<input
id="image"
name="image"
type="file"
accept=".jpg,.jpeg,.png"
required
>
<button type="submit">Upload</button>
</form>
The multipart/form-data encoding is required for a browser to send file bytes. The name value is the field name your server reads. Add multiple only when selecting more than one image is intentional:
<input name="images" type="file" accept=".jpg,.jpeg,.png" multiple>
The HTML Standard defines accept as a user-agent hint. Valid tokens include dot-prefixed extensions and MIME types, separated by commas. Duplicate tokens should be avoided. See the HTML specification and MDN reference.
2. Extensions versus MIME types
| Syntax | What it expresses | Example |
|---|---|---|
| Extensions | Filename suffixes shown by the picker | .jpg,.jpeg,.png |
| MIME types | Declared media categories | image/jpeg,image/png |
| Wildcard | Any image format | image/* |
For this requirement, use .jpg,.jpeg,.png or image/jpeg,image/png. Include both .jpg and .jpeg because both filename extensions are common. The standard JPEG MIME type is image/jpeg; image/jpg is not the standard value. Avoid image/* when formats such as GIF, SVG, or WebP must be rejected.
3. What accept does and does not enforce
- It filters or prioritizes entries in the operating system’s file picker.
- Users may be able to override the filter or choose a renamed file.
- It does not inspect the file signature or decode the image.
- It does not protect an upload endpoint from forged requests.
Therefore treat accept as a usability feature, never as an authorization or security boundary.
4. Validate uploads on the server
Use a layered allowlist before saving or transforming a file. OWASP recommends checking the business-required extension, limiting size, avoiding trust in the submitted Content-Type, and inspecting the file signature together with other controls. See the OWASP File Upload Cheat Sheet.
- Require an upload and reject empty files.
- Apply a maximum size appropriate for your product.
- Normalize the filename and generate your own storage name.
- Check the extension against an allowlist:
jpg,jpeg,png. - Check the declared MIME type only as one signal.
- Read magic bytes or decode the image with a trusted image library.
- Store outside the executable web root, or serve through a controlled download route.
- Use authorization, malware scanning where appropriate, and rate limits.
For image-only products, decoding and rewriting the image can provide an additional content check and discard unexpected data. Keep the accepted formats tied to what your application actually supports.
Example validation logic
allowedExtensions = {"jpg", "jpeg", "png"}
allowedMimeTypes = {"image/jpeg", "image/png"}
maxBytes = 10 * 1024 * 1024
reject if file is missing or file.size == 0
reject if file.size > maxBytes
reject if lowercase(extension(file.name)) not in allowedExtensions
reject if file.contentType not in allowedMimeTypes
reject if detectedSignature(file.bytes) not in {JPEG, PNG}
reject if trustedImageDecoder cannot decode file
store with a generated name, never the user supplied name
5. Browser-side checks for faster feedback
Client-side checks improve the form experience but do not replace server validation:
const input = document.querySelector('#image');
const error = document.querySelector('#image-error');
input.addEventListener('change', () => {
const file = input.files[0];
if (!file) return;
const allowed = new Set(['image/jpeg', 'image/png']);
const maxBytes = 10 * 1024 * 1024;
if (!allowed.has(file.type)) {
input.value = '';
error.textContent = 'Choose a JPG or PNG image.';
return;
}
if (file.size > maxBytes) {
input.value = '';
error.textContent = 'The image is larger than 10 MB.';
return;
}
error.textContent = '';
});
file.type is also supplied by the client and can be empty or inaccurate. Use it only to provide immediate feedback.
6. Upload requests with cURL, Python, and Node.js
These examples send a multipart field named image to an endpoint you control. Replace the URL and file path with your own values.
curl -X POST https://example.com/upload \
-F "image=@photo.jpg;type=image/jpeg"
import requests
with open('photo.png', 'rb') as image:
response = requests.post(
'https://example.com/upload',
files={'image': ('photo.png', image, 'image/png')},
timeout=60,
)
response.raise_for_status()
print(response.json())
import { readFile } from 'node:fs/promises';
const bytes = await readFile('photo.jpg');
const form = new FormData();
form.append('image', new Blob([bytes], { type: 'image/jpeg' }), 'photo.jpg');
const response = await fetch('https://example.com/upload', {
method: 'POST',
body: form
});
if (!response.ok) throw new Error(`Upload failed: ${response.status}`);
console.log(await response.text());
7. Edge cases to handle
- Uppercase suffixes: compare extensions case-insensitively, so
PHOTO.JPGis handled consistently. - Double extensions:
photo.jpg.exemust not pass an extension check; inspect the final suffix and the decoded content. - Renamed files: a file named
photo.jpgmay contain another format. Signature and decoder checks catch this. - Large dimensions: pixel dimensions can exhaust memory even when byte size is small. Set width and height limits before transformations.
- Animated or malformed images: decide whether animation and progressive encoding are supported, then enforce that policy in the decoder.
- Multiple selection: validate each file independently and define whether one invalid file rejects the whole request.
- Mobile camera capture: camera images may be large or use metadata such as EXIF orientation. Normalize orientation during processing if needed.
- Empty cancellation: a user can open the picker and cancel; handle an empty
FileListwithout showing a server error.
8. Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Other formats appear in the picker | The operating system allows an override, or the filter is only a hint. | Keep server-side validation; do not rely on picker filtering. |
| JPEG files are rejected | Only .jpg was listed, or the MIME value is wrong. |
Allow .jpg,.jpeg and use image/jpeg. |
| File arrives as zero bytes | The form lacks enctype="multipart/form-data", or the request was built incorrectly. |
Add the encoding and inspect the multipart field name. |
| Renamed non-images pass | Validation trusts the filename or request MIME type. | Inspect signatures and decode with an image library. |
| Only the first file uploads | The input or server parser does not support multiple files. | Add multiple and iterate over all multipart parts. |
| Uploads fail intermittently | Request size, timeout, proxy, or rate-limit thresholds are too low. | Check server and proxy limits, use bounded retries, and return actionable error codes. |
9. Performance, reliability, and cost
- Reject oversized files before expensive decoding when possible.
- Decode once, then resize or rewrite in a bounded worker process.
- Set request, parser, and storage timeouts so abandoned uploads do not consume resources.
- Use streaming multipart parsers for large files and enforce limits while reading.
- Generate deterministic error responses so clients can distinguish type, size, authentication, and transient failures.
- Keep originals only when required; derived thumbnails reduce storage and delivery cost.
- For repeated browser captures or image generation workflows, cache results deliberately and define an invalidation policy.
10. Or skip the browser setup
If your workflow needs screenshots of web pages rather than user-uploaded images, ScreenshotNeo returns a PNG, JPEG, WebP, or PDF from one GET request. See the API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and the response identifies the verdict and billing status in headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000.
Create a free ScreenshotNeo account.
11. FAQ
Should I use extensions or MIME types?
Either is valid. Extensions cover common filename variations; MIME types express media categories. Many forms use .jpg,.jpeg,.png for an explicit picker filter.
Can accept prevent a user from uploading a PDF?
No. It can filter the picker, but a crafted request can bypass it. Validate the upload on the server.
Is image/jpg correct?
Use the standard image/jpeg MIME type for JPEG files.
Do I need multiple for one image?
No. Omit it when exactly one file should be selected.
Why not use image/*?
It allows image formats beyond JPG and PNG. Use it only when those additional formats are acceptable.


