I have searched for all existing open AND closed issues and discussions for similar requests. I have found none that is comparable to my request.
Verify Feature Scope
I have read through and understood the scope definition for feature requests in the Issues section. I believe my feature request meets the definition and belongs in the Issues section instead of the Discussions.
Problem Description
OWUI preprocess PDF using various backend to convert it to text. We should be able to convert a pdf to images (or img + text) for new VL models (e.g qwen 3.5).
Desired Solution you'd like
Add an option to process pdf as images if the model can read images.
DPI (image quality) should be a parameter.
Alternatives Considered
No response
Additional Context
No response
Originally created by @ccdv-ai on GitHub (Mar 12, 2026).
Original GitHub issue: https://github.com/open-webui/open-webui/issues/22601
### Check Existing Issues
- [x] I have searched for all existing **open AND closed** issues and discussions for similar requests. I have found none that is comparable to my request.
### Verify Feature Scope
- [x] I have read through and understood the scope definition for feature requests in the Issues section. I believe my feature request meets the definition and belongs in the Issues section instead of the Discussions.
### Problem Description
OWUI preprocess PDF using various backend to convert it to text. We should be able to convert a pdf to images (or img + text) for new VL models (e.g qwen 3.5).
### Desired Solution you'd like
Add an option to process pdf as images if the model can read images.
DPI (image quality) should be a parameter.
### Alternatives Considered
_No response_
### Additional Context
_No response_
You can also use a function/tool similar to this:
"""
name: PDF to Image Converter Tool
description: Convert PDF pages to images for vision model analysis
authos: rgaricano _00_ (I∀I)
version: 0.1.0
required_open_webui_version:
"""
import os
import tempfile
import base64
from typing import List, Dict, Any
from pathlib import Path
from pydantic import BaseModel, Field
import pdf2image
from PIL import Image
import io
class Valves(BaseModel):
"""Admin-configurable settings for the tool"""
dpi: int = Field(default=200, description="DPI for image conversion")
image_format: str = Field(default="PNG", description="Image format (PNG, JPEG)")
max_pages: int = Field(default=10, description="Maximum pages to convert")
class UserValves(BaseModel):
"""User-configurable settings"""
include_text: bool = Field(default=True, description="Include extracted text with images")
def convert_pdf_to_images(
pdf_path: str,
dpi: int = 200,
image_format: str = "PNG",
max_pages: int = 10
) -> List[Dict[str, Any]]:
"""
Convert PDF pages to images with metadata.
Args:
pdf_path: Path to the PDF file
dpi: Resolution for converted images
image_format: Output image format
max_pages: Maximum number of pages to convert
Returns:
List of dictionaries containing image data and metadata
"""
try:
# Convert PDF pages to images
images = pdf2image.convert_from_path(
pdf_path,
dpi=dpi,
fmt=image_format.lower(),
last_page=max_pages
)
result = []
for i, image in enumerate(images):
# Convert image to base64 for transmission
buffered = io.BytesIO()
image.save(buffered, format=image_format)
img_str = base64.b64encode(buffered.getvalue()).decode()
result.append({
"page_number": i + 1,
"image_data": img_str,
"image_format": image_format.lower(),
"mime_type": f"image/{image_format.lower()}",
"width": image.width,
"height": image.height
})
return result
except Exception as e:
raise Exception(f"Error converting PDF to images: {str(e)}")
def pdf_to_image_converter(
pdf_file: str = Field(..., description="Path to the PDF file to convert"),
__user__: Dict[str, Any] = Field(default_factory=dict, description="User context"),
__id__: str = Field(default="", description="Tool ID"),
__event_emitter__: Any = Field(default=None, description="Event emitter for progress updates")
) -> Dict[str, Any]:
"""
Convert PDF pages to images for vision model analysis.
This tool takes a PDF file and converts each page into a high-quality image
that can be processed by vision-capable AI models. Each image includes metadata
about the page dimensions and format.
Args:
pdf_file: Path to the PDF file to convert
Returns:
Dictionary containing converted images and metadata
"""
# Get user valves
user_valves = __user__.get("valves", {})
include_text = user_valves.get("include_text", True)
# Get admin valves (tool configuration)
# Note: In a real implementation, you'd access these through the tool module
dpi = 200 # Default, would come from Valves
image_format = "PNG" # Default, would come from Valves
max_pages = 10 # Default, would come from Valves
# Emit progress update
if __event_emitter__:
__event_emitter__({
"type": "status",
"data": {"description": "Starting PDF conversion...", "done": False}
})
try:
# Convert PDF to images
images = convert_pdf_to_images(pdf_file, dpi, image_format, max_pages)
# Emit completion status
if __event_emitter__:
__event_emitter__({
"type": "status",
"data": {"description": f"Converted {len(images)} pages to images", "done": True}
})
return {
"success": True,
"total_pages": len(images),
"images": images,
"message": f"Successfully converted {len(images)} PDF pages to images"
}
except Exception as e:
if __event_emitter__:
__event_emitter__({
"type": "error",
"data": {"description": f"Error: {str(e)}"}
})
return {
"success": False,
"error": str(e),
"message": f"Failed to convert PDF: {str(e)}"
}
<!-- gh-comment-id:4045070187 -->
@rgaricano commented on GitHub (Mar 12, 2026):
You can also use a function/tool similar to this:
```
"""
name: PDF to Image Converter Tool
description: Convert PDF pages to images for vision model analysis
authos: rgaricano _00_ (I∀I)
version: 0.1.0
required_open_webui_version:
"""
import os
import tempfile
import base64
from typing import List, Dict, Any
from pathlib import Path
from pydantic import BaseModel, Field
import pdf2image
from PIL import Image
import io
class Valves(BaseModel):
"""Admin-configurable settings for the tool"""
dpi: int = Field(default=200, description="DPI for image conversion")
image_format: str = Field(default="PNG", description="Image format (PNG, JPEG)")
max_pages: int = Field(default=10, description="Maximum pages to convert")
class UserValves(BaseModel):
"""User-configurable settings"""
include_text: bool = Field(default=True, description="Include extracted text with images")
def convert_pdf_to_images(
pdf_path: str,
dpi: int = 200,
image_format: str = "PNG",
max_pages: int = 10
) -> List[Dict[str, Any]]:
"""
Convert PDF pages to images with metadata.
Args:
pdf_path: Path to the PDF file
dpi: Resolution for converted images
image_format: Output image format
max_pages: Maximum number of pages to convert
Returns:
List of dictionaries containing image data and metadata
"""
try:
# Convert PDF pages to images
images = pdf2image.convert_from_path(
pdf_path,
dpi=dpi,
fmt=image_format.lower(),
last_page=max_pages
)
result = []
for i, image in enumerate(images):
# Convert image to base64 for transmission
buffered = io.BytesIO()
image.save(buffered, format=image_format)
img_str = base64.b64encode(buffered.getvalue()).decode()
result.append({
"page_number": i + 1,
"image_data": img_str,
"image_format": image_format.lower(),
"mime_type": f"image/{image_format.lower()}",
"width": image.width,
"height": image.height
})
return result
except Exception as e:
raise Exception(f"Error converting PDF to images: {str(e)}")
def pdf_to_image_converter(
pdf_file: str = Field(..., description="Path to the PDF file to convert"),
__user__: Dict[str, Any] = Field(default_factory=dict, description="User context"),
__id__: str = Field(default="", description="Tool ID"),
__event_emitter__: Any = Field(default=None, description="Event emitter for progress updates")
) -> Dict[str, Any]:
"""
Convert PDF pages to images for vision model analysis.
This tool takes a PDF file and converts each page into a high-quality image
that can be processed by vision-capable AI models. Each image includes metadata
about the page dimensions and format.
Args:
pdf_file: Path to the PDF file to convert
Returns:
Dictionary containing converted images and metadata
"""
# Get user valves
user_valves = __user__.get("valves", {})
include_text = user_valves.get("include_text", True)
# Get admin valves (tool configuration)
# Note: In a real implementation, you'd access these through the tool module
dpi = 200 # Default, would come from Valves
image_format = "PNG" # Default, would come from Valves
max_pages = 10 # Default, would come from Valves
# Emit progress update
if __event_emitter__:
__event_emitter__({
"type": "status",
"data": {"description": "Starting PDF conversion...", "done": False}
})
try:
# Convert PDF to images
images = convert_pdf_to_images(pdf_file, dpi, image_format, max_pages)
# Emit completion status
if __event_emitter__:
__event_emitter__({
"type": "status",
"data": {"description": f"Converted {len(images)} pages to images", "done": True}
})
return {
"success": True,
"total_pages": len(images),
"images": images,
"message": f"Successfully converted {len(images)} PDF pages to images"
}
except Exception as e:
if __event_emitter__:
__event_emitter__({
"type": "error",
"data": {"description": f"Error: {str(e)}"}
})
return {
"success": False,
"error": str(e),
"message": f"Failed to convert PDF: {str(e)}"
}
```
Thank you.
I'm wondering if it is possible to intercept the file and process it with a filter before the conversion. But Im pretty sure the conversion to text cannot be skiped and will be added to prompt anyway.
<!-- gh-comment-id:4045312817 -->
@ccdv-ai commented on GitHub (Mar 12, 2026):
Thank you.
I'm wondering if it is possible to intercept the file and process it with a filter before the conversion. But Im pretty sure the conversion to text cannot be skiped and will be added to prompt anyway.
@ccdv-ai
For skip the openwebui file processing core, set the file_handler = True flag (it enables custom file processing)
With a Filter Function:
"""
title: PDF to Image Filter Function
author: rgaricano _00_ (I∀I)
version: 0.1.0
"""
import os
import tempfile
import base64
from typing import Optional, Dict, Any
from pydantic import BaseModel, Field
import pdf2image
from PIL import Image
import io
class Filter:
class Valves(BaseModel):
"""Admin-configurable settings"""
enabled: bool = Field(default=True, description="Enable PDF to image conversion")
dpi: int = Field(default=200, description="DPI for image conversion")
image_format: str = Field(default="PNG", description="Image format (PNG, JPEG)")
max_pages: int = Field(default=10, description="Maximum pages to convert")
class UserValves(BaseModel):
"""User-configurable settings"""
auto_convert: bool = Field(default=True, description="Automatically convert PDFs to images")
def __init__(self):
self.valves = self.Valves()
# Enable custom file handling to intercept files
self.file_handler = True
def inlet(self, body: dict, __user__: Optional[dict] = None) -> dict:
"""Intercept and process PDF files before content extraction"""
if not self.valves.enabled:
return body
user_valves = __user__.get("valves", {}) if __user__ else {}
if not user_valves.get("auto_convert", True):
return body
# Check if there are files in the request
files = body.get("files", [])
if not files:
return body
processed_files = []
added_images = []
for file_info in files:
# Process PDF files
if file_info.get("type") == "application/pdf":
try:
# Convert PDF pages to images
images = self._convert_pdf_to_images(file_info)
# Add images to the files list
for img_data in images:
processed_files.append({
"name": f"{file_info['name']}_page_{img_data['page_number']}.{img_data['format']}",
"type": f"image/{img_data['format']}",
"data": img_data["base64_data"],
"size": len(img_data["base64_data"])
})
added_images.append(f"Page {img_data['page_number']}")
# Keep the original PDF for text extraction
processed_files.append(file_info)
except Exception as e:
# If conversion fails, keep original file
processed_files.append(file_info)
else:
processed_files.append(file_info)
# Update the body with processed files
body["files"] = processed_files
# Add a message about the conversion
if added_images:
messages = body.get("messages", [])
if messages:
last_message = messages[-1]
if last_message.get("role") == "user":
content = last_message.get("content", "")
content += f"\n\n📄 PDF converted to images: {', '.join(added_images)}"
last_message["content"] = content
return body
def _convert_pdf_to_images(self, file_info: dict) -> list:
"""Convert PDF file to images"""
# Decode base64 file data
file_data = base64.b64decode(file_info["data"].split(",")[1])
# Save to temporary file
with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp_file:
tmp_file.write(file_data)
tmp_path = tmp_file.name
try:
# Convert PDF to images
images = pdf2image.convert_from_path(
tmp_path,
dpi=self.valves.dpi,
fmt=self.valves.image_format.lower(),
last_page=self.valves.max_pages
)
result = []
for i, image in enumerate(images):
# Convert image to base64
buffered = io.BytesIO()
image.save(buffered, format=self.valves.image_format)
img_str = base64.b64encode(buffered.getvalue()).decode()
result.append({
"page_number": i + 1,
"format": self.valves.image_format.lower(),
"base64_data": f"data:image/{self.valves.image_format.lower()};base64,{img_str}"
})
return result
finally:
# Clean up temporary file
os.unlink(tmp_path)
def outlet(self, body: dict, __user__: Optional[dict] = None) -> dict:
"""Post-process response if needed"""
return body
<!-- gh-comment-id:4047430178 -->
@rgaricano commented on GitHub (Mar 12, 2026):
@ccdv-ai
For skip the openwebui file processing core, set the `file_handler = True` flag (it enables custom file processing)
With a Filter Function:
```
"""
title: PDF to Image Filter Function
author: rgaricano _00_ (I∀I)
version: 0.1.0
"""
import os
import tempfile
import base64
from typing import Optional, Dict, Any
from pydantic import BaseModel, Field
import pdf2image
from PIL import Image
import io
class Filter:
class Valves(BaseModel):
"""Admin-configurable settings"""
enabled: bool = Field(default=True, description="Enable PDF to image conversion")
dpi: int = Field(default=200, description="DPI for image conversion")
image_format: str = Field(default="PNG", description="Image format (PNG, JPEG)")
max_pages: int = Field(default=10, description="Maximum pages to convert")
class UserValves(BaseModel):
"""User-configurable settings"""
auto_convert: bool = Field(default=True, description="Automatically convert PDFs to images")
def __init__(self):
self.valves = self.Valves()
# Enable custom file handling to intercept files
self.file_handler = True
def inlet(self, body: dict, __user__: Optional[dict] = None) -> dict:
"""Intercept and process PDF files before content extraction"""
if not self.valves.enabled:
return body
user_valves = __user__.get("valves", {}) if __user__ else {}
if not user_valves.get("auto_convert", True):
return body
# Check if there are files in the request
files = body.get("files", [])
if not files:
return body
processed_files = []
added_images = []
for file_info in files:
# Process PDF files
if file_info.get("type") == "application/pdf":
try:
# Convert PDF pages to images
images = self._convert_pdf_to_images(file_info)
# Add images to the files list
for img_data in images:
processed_files.append({
"name": f"{file_info['name']}_page_{img_data['page_number']}.{img_data['format']}",
"type": f"image/{img_data['format']}",
"data": img_data["base64_data"],
"size": len(img_data["base64_data"])
})
added_images.append(f"Page {img_data['page_number']}")
# Keep the original PDF for text extraction
processed_files.append(file_info)
except Exception as e:
# If conversion fails, keep original file
processed_files.append(file_info)
else:
processed_files.append(file_info)
# Update the body with processed files
body["files"] = processed_files
# Add a message about the conversion
if added_images:
messages = body.get("messages", [])
if messages:
last_message = messages[-1]
if last_message.get("role") == "user":
content = last_message.get("content", "")
content += f"\n\n📄 PDF converted to images: {', '.join(added_images)}"
last_message["content"] = content
return body
def _convert_pdf_to_images(self, file_info: dict) -> list:
"""Convert PDF file to images"""
# Decode base64 file data
file_data = base64.b64decode(file_info["data"].split(",")[1])
# Save to temporary file
with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp_file:
tmp_file.write(file_data)
tmp_path = tmp_file.name
try:
# Convert PDF to images
images = pdf2image.convert_from_path(
tmp_path,
dpi=self.valves.dpi,
fmt=self.valves.image_format.lower(),
last_page=self.valves.max_pages
)
result = []
for i, image in enumerate(images):
# Convert image to base64
buffered = io.BytesIO()
image.save(buffered, format=self.valves.image_format)
img_str = base64.b64encode(buffered.getvalue()).decode()
result.append({
"page_number": i + 1,
"format": self.valves.image_format.lower(),
"base64_data": f"data:image/{self.valves.image_format.lower()};base64,{img_str}"
})
return result
finally:
# Clean up temporary file
os.unlink(tmp_path)
def outlet(self, body: dict, __user__: Optional[dict] = None) -> dict:
"""Post-process response if needed"""
return body
```
I can pick this up. The PDF processing logic lives in the retrieval pipeline where documents get chunked and embedded — we'd need to add a rendering path using something like pdf2image (poppler-based) to convert each page into a base64-encoded image before passing it to the chat completion payload. The DPI parameter could slot into the document settings alongside the existing chunk size/overlap config. I'll put together a PR.
<!-- gh-comment-id:4051546902 -->
@JiwaniZakir commented on GitHub (Mar 13, 2026):
I can pick this up. The PDF processing logic lives in the retrieval pipeline where documents get chunked and embedded — we'd need to add a rendering path using something like pdf2image (poppler-based) to convert each page into a base64-encoded image before passing it to the chat completion payload. The DPI parameter could slot into the document settings alongside the existing chunk size/overlap config. I'll put together a PR.
@ccdv-ai,
I debugged & made some changes, tested and working with qwen3.5_9b
"""
title: PDF to Image Filter Function
author: rgaricano _00_ (I∀I)
version: 0.1.1
OpenWebUI version: 0.8.10
"""
import os
import tempfile
import base64
from typing import Optional, Dict, Any
from pydantic import BaseModel, Field
import pdf2image
from PIL import Image
import io
class Filter:
class Valves(BaseModel):
"""Admin-configurable settings"""
enabled: bool = Field(
default=True, description="Enable PDF to image conversion"
)
dpi: int = Field(default=200, description="DPI for image conversion")
image_format: str = Field(default="PNG", description="Image format (PNG, JPEG)")
max_pages: int = Field(default=10, description="Maximum pages to convert")
class UserValves(BaseModel):
"""User-configurable settings"""
auto_convert: bool = Field(
default=True, description="Automatically convert PDFs to images"
)
def __init__(self):
self.valves = self.Valves()
# Enable custom file handling to intercept files
# self.file_handler = True
def inlet(
self, body: dict, __user__: Optional[dict] = None, __event_emitter__: Any = None
) -> dict:
"""Intercept and process PDF files before content extraction"""
print(f"[PDF2IMG] Filter inlet called")
if not self.valves.enabled:
return body
user_valves = __user__.get("valves") if __user__ else None
if user_valves and not user_valves.auto_convert:
return body
files = body.get("files", [])
if not files:
return body
processed_files = []
added_images = []
for file_info in files:
if file_info.get("content_type") == "application/pdf":
try:
print(f"[PDF2IMG] Processing PDF: {file_info.get('name')}")
# Convert PDF to images
images = self._convert_pdf_to_images(file_info)
# Add images to the files list
for img_data in images:
processed_files.append(
{
"name": f"{file_info['name']}_page_{img_data['page_number']}.{img_data['format']}",
"type": f"image/{img_data['format']}",
"data": img_data["base64_data"],
"size": len(img_data["base64_data"]),
}
)
added_images.append(f"Page {img_data['page_number']}")
# Keep the original PDF for text extraction
processed_files.append(file_info)
except Exception as e:
print(f"[PDF2IMG] Error converting PDF: {str(e)}")
processed_files.append(file_info)
else:
processed_files.append(file_info)
# Update the body with processed files
body["files"] = processed_files
# CRITICAL: Add images to message content for vision model
if added_images:
messages = body.get("messages", [])
if messages:
last_message = messages[-1]
if last_message.get("role") == "user":
content = last_message.get("content", "")
# Convert content to list format if needed
if isinstance(content, str):
content = [{"type": "text", "text": content}]
elif not isinstance(content, list):
content = [{"type": "text", "text": str(content)}]
# Add image URLs to content
for file_info in processed_files:
if file_info.get("type", "").startswith("image/"):
content.append(
{
"type": "image_url",
"image_url": {"url": file_info["data"]},
}
)
last_message["content"] = content
# Add text notification
if content and content[0].get("type") == "text":
content[0][
"text"
] += (
f"\n\n📄 PDF converted to images: {', '.join(added_images)}"
)
return body
def _convert_pdf_to_images(
self, file_info: dict, __event_emitter__: Any = None
) -> list:
"""Convert PDF file to images"""
print(f"[PDF2IMG] Starting conversion for {file_info.get('name')}")
# FIXED: Read file directly from disk instead of decoding base64
file_path = file_info["file"]["path"]
try:
# Convert PDF to images
images = pdf2image.convert_from_path(
file_path,
dpi=self.valves.dpi,
fmt=self.valves.image_format.lower(),
last_page=self.valves.max_pages,
)
print(f"[PDF2IMG] Converted {len(images)} pages to images")
result = []
for i, image in enumerate(images):
# Emit progress for each page
if __event_emitter__:
__event_emitter__(
{
"type": "status",
"data": {
"description": f"Processing page {i+1}/{len(images)}",
"done": False,
},
}
)
# Convert image to base64
buffered = io.BytesIO()
image.save(buffered, format=self.valves.image_format)
img_str = base64.b64encode(buffered.getvalue()).decode()
result.append(
{
"page_number": i + 1,
"format": self.valves.image_format.lower(),
"base64_data": f"data:image/{self.valves.image_format.lower()};base64,{img_str}",
}
)
return result
except Exception as e:
print(f"[PDF2IMG] Error in pdf2image conversion: {str(e)}")
raise
def outlet(
self, body: dict, __user__: Optional[dict] = None, __event_emitter__: Any = None
) -> dict:
"""Post-process response if needed"""
print(f"[PDF2IMG] Filter outlet called")
return body
<!-- gh-comment-id:4054974960 -->
@rgaricano commented on GitHub (Mar 13, 2026):
@ccdv-ai,
I debugged & made some changes, tested and working with qwen3.5_9b
```
"""
title: PDF to Image Filter Function
author: rgaricano _00_ (I∀I)
version: 0.1.1
OpenWebUI version: 0.8.10
"""
import os
import tempfile
import base64
from typing import Optional, Dict, Any
from pydantic import BaseModel, Field
import pdf2image
from PIL import Image
import io
class Filter:
class Valves(BaseModel):
"""Admin-configurable settings"""
enabled: bool = Field(
default=True, description="Enable PDF to image conversion"
)
dpi: int = Field(default=200, description="DPI for image conversion")
image_format: str = Field(default="PNG", description="Image format (PNG, JPEG)")
max_pages: int = Field(default=10, description="Maximum pages to convert")
class UserValves(BaseModel):
"""User-configurable settings"""
auto_convert: bool = Field(
default=True, description="Automatically convert PDFs to images"
)
def __init__(self):
self.valves = self.Valves()
# Enable custom file handling to intercept files
# self.file_handler = True
def inlet(
self, body: dict, __user__: Optional[dict] = None, __event_emitter__: Any = None
) -> dict:
"""Intercept and process PDF files before content extraction"""
print(f"[PDF2IMG] Filter inlet called")
if not self.valves.enabled:
return body
user_valves = __user__.get("valves") if __user__ else None
if user_valves and not user_valves.auto_convert:
return body
files = body.get("files", [])
if not files:
return body
processed_files = []
added_images = []
for file_info in files:
if file_info.get("content_type") == "application/pdf":
try:
print(f"[PDF2IMG] Processing PDF: {file_info.get('name')}")
# Convert PDF to images
images = self._convert_pdf_to_images(file_info)
# Add images to the files list
for img_data in images:
processed_files.append(
{
"name": f"{file_info['name']}_page_{img_data['page_number']}.{img_data['format']}",
"type": f"image/{img_data['format']}",
"data": img_data["base64_data"],
"size": len(img_data["base64_data"]),
}
)
added_images.append(f"Page {img_data['page_number']}")
# Keep the original PDF for text extraction
processed_files.append(file_info)
except Exception as e:
print(f"[PDF2IMG] Error converting PDF: {str(e)}")
processed_files.append(file_info)
else:
processed_files.append(file_info)
# Update the body with processed files
body["files"] = processed_files
# CRITICAL: Add images to message content for vision model
if added_images:
messages = body.get("messages", [])
if messages:
last_message = messages[-1]
if last_message.get("role") == "user":
content = last_message.get("content", "")
# Convert content to list format if needed
if isinstance(content, str):
content = [{"type": "text", "text": content}]
elif not isinstance(content, list):
content = [{"type": "text", "text": str(content)}]
# Add image URLs to content
for file_info in processed_files:
if file_info.get("type", "").startswith("image/"):
content.append(
{
"type": "image_url",
"image_url": {"url": file_info["data"]},
}
)
last_message["content"] = content
# Add text notification
if content and content[0].get("type") == "text":
content[0][
"text"
] += (
f"\n\n📄 PDF converted to images: {', '.join(added_images)}"
)
return body
def _convert_pdf_to_images(
self, file_info: dict, __event_emitter__: Any = None
) -> list:
"""Convert PDF file to images"""
print(f"[PDF2IMG] Starting conversion for {file_info.get('name')}")
# FIXED: Read file directly from disk instead of decoding base64
file_path = file_info["file"]["path"]
try:
# Convert PDF to images
images = pdf2image.convert_from_path(
file_path,
dpi=self.valves.dpi,
fmt=self.valves.image_format.lower(),
last_page=self.valves.max_pages,
)
print(f"[PDF2IMG] Converted {len(images)} pages to images")
result = []
for i, image in enumerate(images):
# Emit progress for each page
if __event_emitter__:
__event_emitter__(
{
"type": "status",
"data": {
"description": f"Processing page {i+1}/{len(images)}",
"done": False,
},
}
)
# Convert image to base64
buffered = io.BytesIO()
image.save(buffered, format=self.valves.image_format)
img_str = base64.b64encode(buffered.getvalue()).decode()
result.append(
{
"page_number": i + 1,
"format": self.valves.image_format.lower(),
"base64_data": f"data:image/{self.valves.image_format.lower()};base64,{img_str}",
}
)
return result
except Exception as e:
print(f"[PDF2IMG] Error in pdf2image conversion: {str(e)}")
raise
def outlet(
self, body: dict, __user__: Optional[dict] = None, __event_emitter__: Any = None
) -> dict:
"""Post-process response if needed"""
print(f"[PDF2IMG] Filter outlet called")
return body
```
@frenzybiscuit commented on GitHub (Mar 13, 2026):
Though, the tools above likely work fine. It would still be nice to see native support.
<!-- gh-comment-id:4055718677 -->
@frenzybiscuit commented on GitHub (Mar 13, 2026):
Though, the tools above likely work fine. It would still be nice to see native support.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Originally created by @ccdv-ai on GitHub (Mar 12, 2026).
Original GitHub issue: https://github.com/open-webui/open-webui/issues/22601
Check Existing Issues
Verify Feature Scope
Problem Description
OWUI preprocess PDF using various backend to convert it to text. We should be able to convert a pdf to images (or img + text) for new VL models (e.g qwen 3.5).
Desired Solution you'd like
Add an option to process pdf as images if the model can read images.
DPI (image quality) should be a parameter.
Alternatives Considered
No response
Additional Context
No response
@rgaricano commented on GitHub (Mar 12, 2026):
You can also use a function/tool similar to this:
@ccdv-ai commented on GitHub (Mar 12, 2026):
Thank you.
I'm wondering if it is possible to intercept the file and process it with a filter before the conversion. But Im pretty sure the conversion to text cannot be skiped and will be added to prompt anyway.
@rgaricano commented on GitHub (Mar 12, 2026):
@ccdv-ai
For skip the openwebui file processing core, set the
file_handler = Trueflag (it enables custom file processing)With a Filter Function:
@JiwaniZakir commented on GitHub (Mar 13, 2026):
I can pick this up. The PDF processing logic lives in the retrieval pipeline where documents get chunked and embedded — we'd need to add a rendering path using something like pdf2image (poppler-based) to convert each page into a base64-encoded image before passing it to the chat completion payload. The DPI parameter could slot into the document settings alongside the existing chunk size/overlap config. I'll put together a PR.
@rgaricano commented on GitHub (Mar 13, 2026):
@ccdv-ai,
I debugged & made some changes, tested and working with qwen3.5_9b
@frenzybiscuit commented on GitHub (Mar 13, 2026):
I'd also like to see this natively supported in OWUI.
@frenzybiscuit commented on GitHub (Mar 13, 2026):
Though, the tools above likely work fine. It would still be nice to see native support.