Handling Image Downloads in brenia
The Breniapp project recently addressed an issue with image downloads in its content generation feature. Instead of directly downloading images, the application was opening them in a new tab when the html2canvas library failed due to Cross-Origin Resource Sharing (CORS) restrictions. This behavior was not ideal for user experience, so a solution was implemented to ensure proper downloading.
The Problem
When generating content, the application relies on html2canvas to render images. However, when CORS issues arise, html2canvas may fail, causing a fallback to window.open(). This resulted in images opening in a new tab instead of being downloaded as intended.
The Solution
To address this, a multi-faceted approach was implemented:
- Fetch-as-Blob Fallback: Instead of directly using
window.open(), the application now attempts to fetch the image as a blob using thefetchAPI. This allows for more control over the download process. - Server-Side Proxy Route: As a last resort, a server-side proxy route was introduced. This route fetches the image from the original source and forces a
Content-Disposition: attachmentheader. This ensures that the browser treats the response as a file download, regardless of CORS restrictions.
Here's an illustrative example of how a server-side proxy can be implemented in PHP using Laravel:
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Http;
use Symfony\Component\HttpFoundation\StreamedResponse;
class ImageProxyController extends Controller
{
public function download(string $url)
{
$response = Http::get($url);
return new StreamedResponse(
function () use ($response) {
echo $response->body();
},
200,
[
'Content-Type' => $response->header('Content-Type'),
'Content-Disposition' => 'attachment; filename="image.jpg"',
]
);
}
}
In this example, the download method takes an image URL as input. It uses Laravel's HTTP client to fetch the image. A StreamedResponse is then returned, which streams the image content to the client with the appropriate Content-Type and Content-Disposition headers. The Content-Disposition header tells the browser to download the content as a file.
Key Takeaway
When dealing with CORS issues and image downloads, implementing a server-side proxy with the correct Content-Disposition header can ensure consistent download behavior, even when client-side solutions fail.