This document summarizes the comprehensive fixes implemented to resolve the issue where generated images were not visible in the web UI. The main problems identified were:
src/server.cpp)handleDownloadOutput)// Added comprehensive logging
std::cout << "Image download request: jobId=" << jobId << ", filename=" << filename
<< ", fullPath=" << fullPath << std::endl;
// Check for zero-byte files
auto fileSize = std::filesystem::file_size(fullPath);
if (fileSize == 0) {
std::cerr << "Output file is zero bytes: " << fullPath << std::endl;
sendErrorResponse(res, "Output file is empty (corrupted generation)", 500, "EMPTY_FILE", "");
return;
}
// Proper content type and CORS headers
res.set_header("Content-Type", contentType);
res.set_header("Content-Length", std::to_string(fileContent.length()));
res.set_header("Cache-Control", "public, max-age=3600");
res.set_header("Access-Control-Allow-Origin", "*");
src/generation_queue.cpp)saveImageToFile function// Validate image data integrity
const size_t expectedDataSize = static_cast<size_t>(image.width) * image.height * image.channels;
if (image.data.size() != expectedDataSize) {
std::cerr << "Image data size mismatch for " << requestId << "_" << index
<< ": expected=" << expectedDataSize
<< ", actual=" << image.data.size() << std::endl;
}
// Verify the file was created successfully
if (!std::filesystem::exists(filename)) {
std::cerr << "ERROR: stbi_write_png returned success but file does not exist: " << filename << std::endl;
return "";
}
auto fileSize = std::filesystem::file_size(filename);
if (fileSize == 0) {
std::cerr << "ERROR: stbi_write_png returned success but created zero-byte file: " << filename << std::endl;
return "";
}
webui/lib/api.ts)getImageUrl(): Generate authenticated URLs with cache-bustingdownloadImage(): Download images with proper authentication headers// Get authenticated image URL with cache-busting
getImageUrl(jobId: string, filename: string): string {
const { apiUrl, apiBase } = getApiConfig();
const baseUrl = `${apiUrl}${apiBase}`;
// Add cache-busting timestamp
const timestamp = Date.now();
const url = `${baseUrl}/queue/job/${jobId}/output/${filename}?t=${timestamp}`;
return url;
}
// Download image with authentication
async downloadImage(jobId: string, filename: string): Promise<Blob> {
const url = this.getImageUrl(jobId, filename);
// Add authentication headers based on auth method
const headers: Record<string, string> = {};
if (authMethod === 'unix' && unixUser) {
headers['X-Unix-User'] = unixUser;
} else if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const response = await fetch(url, { headers });
return response.blob();
}
webui/lib/utils.ts)downloadAuthenticatedImage(): Download images with authentication headerstext2img, img2img, upscaler)result.images) and new (outputs) response formatsif (status.status === 'completed') {
let imageUrls: string[] = [];
// Handle both old format (result.images) and new format (outputs)
if (status.outputs && status.outputs.length > 0) {
// New format: convert output URLs to authenticated image URLs with cache-busting
imageUrls = status.outputs.map((output: any) => {
const filename = output.filename;
return apiClient.getImageUrl(jobId, filename);
});
} else if (status.result?.images && status.result.images.length > 0) {
// Old format: convert image URLs to authenticated URLs
imageUrls = status.result.images.map((imageUrl: string) => {
// Extract filename from URL if it's already a full URL
if (imageUrl.includes('/output/')) {
const parts = imageUrl.split('/output/');
if (parts.length === 2) {
const filename = parts[1].split('?')[0]; // Remove query params
return apiClient.getImageUrl(jobId, filename);
}
}
// If it's just a filename, convert it directly
return apiClient.getImageUrl(jobId, imageUrl);
});
}
// Create a new array to trigger React re-render
setGeneratedImages([...imageUrls]);
setLoading(false);
}
To verify the fixes work correctly:
src/server.cpp - Enhanced download endpoint with better error handlingsrc/generation_queue.cpp - Improved image saving with detailed loggingwebui/lib/api.ts - Added authenticated image download methodswebui/lib/utils.ts - Added authenticated download utilitywebui/app/text2img/page.tsx - Updated polling and download logicwebui/app/img2img/page.tsx - Updated polling and download logicwebui/app/upscaler/page.tsx - Updated polling and download logicThe fixes maintain backward compatibility:
result.images format is still supportedThese comprehensive fixes address all the identified issues causing images to not be visible:
The implementation is robust, maintainable, and provides a good user experience with proper error reporting and fallback mechanisms.