oqtane / oqtane.framework

CMS & Application Framework for Blazor & .NET MAUI
http://www.oqtane.org
MIT License
1.9k stars 547 forks source link

[ENH] Image Resizing and Manipulation with Query String #4692

Closed mdmontesinos closed 1 month ago

mdmontesinos commented 1 month ago

Oqtane Info

Version - 5.2.3 Render Mode - Static Interactivity - Server Database - SQL Server

Describe the enhancement

Similar to how images can be resized and manipulated with the File API endpoint by id and route parameters (i.e):

api/file/image/1010/1500/1500/crop/center/transparent/0/false

It would interesting for some use cases when the id is not available to be able to achieve the same, retrieving the image by its path and with a query string. This is the way most libraries and websites I've seen work:

files/folder/subfolder/myImage.jpg?w=1500&h=1500&mode=crop&position=center&background=transparent&rotate=0&recreate=false

This should be updated in the GET action in the Files Page. Also, the generated image should be cachable with the ETAG, or another mechanism, to avoid regenerating it multiple times and reducing CPU and memory consumption.

Anything else?

tvatavuk commented 1 month ago

We've been using an Imageflow-based extension for Oqtane in our 2sxc module to handle image resizing and manipulation via query strings. Imageflow is an outstanding solution—it's extremely optimized, super fast, and packed with features.

The extension can also be installed as a standalone module in Oqtane, making it versatile for various use cases.

Here are some resources you might find helpful:

mdmontesinos commented 1 month ago

@tvatavuk Thanks for the info about the Imageflow-based Oqtane module! Is it free for commercial use or do I need to purchase an imageflow license? Is it compatible with Oqtane > 5? (the last commit was on May)

Also, I still believe there should be an in-framework solution, as Oqtane already bundles with SixLabors.ImageSharp and provides the functionality, just in a different format. In this way, there's no need for extra dependencies or modules.

Although it seems that imageflow is more optimized and provides cache systems out of the box.

tvatavuk commented 1 month ago

If you're able to comply with the terms of the AGPLv3, then you can use Imageflow for free, including for commercial use.

Imageflow is 100% Open Source Software. You can use it freely under the terms of the AGPLv3. AGPLv3 requires that if you distribute the software (including making it available as a service), you must also make the complete source code of your application publicly available under an AGPLv3-compatible license. They also offer commercial licenses if you do not wish to use the AGPLv3.

It works with the latest Oqtane (as it did with previous versions). We are heavily using it in 2sxc all the time, and it is part of the 2sxc installation.

image

mdmontesinos commented 1 month ago

@sbwalker I've seen that SixLabors.ImageSharp has another package called ImageSharp.Web that provides the middleware to allow processing and caching image requests with a query string. As Oqtane already includes the base ImageSharp package, does its license also allow including this middleware package?

sbwalker commented 1 month ago

@mdmontesinos please describe a scenario where the FileId is not available

mdmontesinos commented 1 month ago

@sbwalker Firstly, using the full path instead of the Id improves the readability of the url (similar to using a url slug instead of a numerical id for a blog post or news article), although that's not critical.

However, the specific use case I've encountered is when migrating content from other CMS. For example, a table with news articles that includes a column with the image url from their file management system (i.e. /myfiles/news/oqtane.jpg). To migrate it, I've designed a script that goes through all the records, stores the original url in a text file and rewrites it to match my file system (i.e. /images/oqtane.jpg). After that, I downloaded all the images from "/myfiles/news" as a zip, uploaded it to the Oqtane folder "/images" and used the new unzip functionality.

In this way, all original image files are migrated to the Oqtane file system and the urls in the database and rewritten to accomodate this. However, by using the process of uploading the images through the unzip functionality, I don't get the FileId of each of them.

sbwalker commented 1 month ago

I think its a good suggestion to incorporate this functionality into the existing "files/" page, as that file server already supports mapping the path to a folder, eTags, etc....

sbwalker commented 1 month ago

the other benefit of having this integrated in the framework is that Oqtane is able to automatically cleanup the resized images when a file is deleted or moved to a different folder

mdmontesinos commented 1 month ago

the other benefit of having this integrated in the framework is that Oqtane is able to automatically cleanup the resized images when a file is deleted or moved to a different folder

Then, I assume that the resized/manipulated images would be cached into disk and there would be a mechanism to recover them if the same query is received, right?

And perhaps an expiration mechanism should also be set into place, as a maliciuous user could generate thousands of variations to saturate the disk capacity.

(or integrating ImageSharp.Web if that's a possibility)

sbwalker commented 1 month ago

"And perhaps an expiration mechanism should also be set into place, as a maliciuous user could generate thousands of variations to saturate the disk capacity."

This is already supported in Oqtane. You must configure the Folder to indicate the image sizes supported when resizing. By default Folders do not support resizing (to prevent the issue you described above).

image

The existing image generator also adheres to the Capacity limit for the folder (if specified).

sbwalker commented 1 month ago

I would prefer to avoid third party dependencies in Oqtane. But please feel free to use ImageSharp.Web in your own custom solution if it meets your needs.

mdmontesinos commented 1 month ago

I also prefer avoiding any extra dependencies (to reduce server load), that's why I was suggesting having an in-framework solution using the already included ImageSharp library.

This is already supported in Oqtane. You must configure the Folder to indicate the image sizes supported when resizing. By default Folders do not support resizing (to prevent the issue you described above).

Do you mean when using the api/file/image endpoint? Does it automatically generate the image sizes or it prevents me from calling the endpoint with a different size than the ones allowed?

sbwalker commented 1 month ago

If you do not enter specific image sizes or a wildcard ( ) for the Folder where the File resides, then the existing api/file/image endpoint prevents you from generating any images. This protects the system from the vulnerability you outlined above. And if you do provide specific image sizes or a wildcard ( ) for a Folder, images are never auto generated - they are always initially generated based on a request and they will only be generated if the parameters match the size criteria for the folder.

mdmontesinos commented 1 month ago

I'm going to start working on implementing this functionality (if no one is already on it), and try to submit a PR by the end of the week.

mdmontesinos commented 1 month ago

Submitted PR with a basic implementation for the issue described here (https://github.com/oqtane/oqtane.framework/pull/4723)

nicpitsch commented 1 month ago

@sbwalker Oqtane is using now ImageSharp version 3.1.5 although you mentioned in discussion https://github.com/oqtane/oqtane.framework/discussions/3274: the new license is not compatible with the Oqtane open source license. This means that we are locked to ImageSharp version 2.1.0. That is according to their pricing: ..company/individual with more than 1M USD annual gross revenue you must purchase a Six Labors Commercial License.

Why not take now the opportunity and move to a more permissive library like imageflow as mentioned above?

mdmontesinos commented 1 month ago

@nicpitsch I remember reading another discussion somewhere in which sbwalker mentioned that the ImageSharp creators allowed him to update to latest versions as long as Oqtane kept the open source license and it was used as a transitive dependency. Although I can't seem to find the discussion, so I might have just dreamt it.

nicpitsch commented 1 month ago

@mdmontesinos I meant rather the consequences for commercial projects/products based on Oqtane. And wouldn't using ImageSharp version >2.1.0 be an exception to it's MIT license?

mdmontesinos commented 1 month ago

@nicpitsch As far as I'm concerned, there's no need to purchase a license as long as it's being used as a transitive dependency Oqtane (i.e. I'm not developing new products based on ImageSharp). And yes, it's an exception to its MIT license. All this should be confirmed by @sbwalker, as I wasn't able to find the discussion were this was mentioned.

leigh-pointer commented 1 month ago

There is this https://github.com/oqtane/oqtane.framework/discussions/3274#discussion-5652554 But further I remember @sbwalker tell us that he was in discussion with Six Labors and had come up with a special case for Oqtane and any module built for Oqtane. Maybe @sbwalker can shed some more light on this case.

mdmontesinos commented 1 month ago

@leigh-pointer The https://github.com/oqtane/oqtane.framework/discussions/3274#discussion-5652554 discussion was already mentioned by @nicpitsch. The discussion I could not find is the one where @sbwalker explained that special case that I was describing previously, and that you also confirmed.

sbwalker commented 1 month ago

See #3966

I asked the owner of ImageSharp about the impact of upgrading Oqtane to ImageSharp 3.x and he provided the following explanation to me in an email:

"If a user downloads Oqtane, the version of ImageSharp bundled with Oqtane is licensed to the user under the terms of the Apache 2.0 license as that was the license Oqtane consumes the library under. This means their consumption is transitive ie. they have the right to use ImageSharp under the Apache 2.0 license as long as it is used in conjunction with Oqtane. If the user downloads a version of ImageSharp that replaces the version bundled with Oqtane then their consumption becomes direct and they are subject to the terms of the license. "

mdmontesinos commented 1 month ago

Thanks, that was the discussion I was mentioning.