-
-
Notifications
You must be signed in to change notification settings - Fork 362
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added Dynamic Conversion of JPEG-XL, JPEG 2000, HEIF and AVIF to JPG when the browser does not support them. #3141
Conversation
Fixed test and benchmark DI. Point docker-build to another hub Edit dockerfile and include jxl package.
1. Supported Image Formats came in the accept flag from the browser. 2. If jxl (or future formats, ie browser not supported AVIF, HEIF, etc) are not supported, Kavita will convert it to a suitable display format via conversion providers. 3. if it supported it will return the image as is, no conversion needed. 4. Thumbnails are always converted.
This reverts commit 7f6db24.
This reverts commit 9d48664.
1. Supported Image Formats came in the accept flag from the browser. 2. If jxl (or future formats, ie browser not supported AVIF, HEIF, etc) are not supported, Kavita will convert it to a suitable display format via conversion providers. 3. if it supported it will return the image as is, no conversion needed. 4. Thumbnails are always converted.
…gick. Rollback IOsInfo.cs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked over the code and provided comments.
I'm not ecstatic about ImageMagick. I'm not sure if it supports ARM deployments as well, so I would need confirmation. Likewise, changing the docker file base image.
I would also need to test this locally to see if it's worth it to add support for transcoding on the fly and if the performance difference is worth it or not.
I personally haven't added JXL because it's DOA with support from the browsers. Jpeg2000 is also quite rare. Owning the maintenance of this code for flavors of formats that aren't common doesn't make much sense to me.
Since you're opening the PR out of nowhere, please provide justification or any supporting Feature Requests.
API/Controllers/ReaderController.cs
Outdated
@@ -23,6 +23,7 @@ | |||
using Microsoft.Extensions.Logging; | |||
using Microsoft.IdentityModel.Tokens; | |||
using MimeTypes; | |||
using Org.BouncyCastle.Ocsp; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can only blame Resharper on this ;)
Wil do
{ | ||
// Add jxl format | ||
format = format.ToLowerInvariant(); | ||
if (format == ".jxl") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return on the same line please
if (string.IsNullOrEmpty(extension)) | ||
return; | ||
if (!extensions.Contains(extension)) | ||
extensions.Add(extension); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please always use {} whenever using any if statement that isn't a direct control flow (continue/break/return).
For any control flow jump logic, they need to be on the same line as the if else use {}
{ | ||
if (string.IsNullOrEmpty(extension)) | ||
return; | ||
if (!extensions.Contains(extension)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Newline before the if statement to help keep the code clear
List<string> supportedExtensions = new List<string>(); | ||
|
||
//Add default extensions supported by all browsers. | ||
supportedExtensions.Add("jpeg"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use the extensions in Parser so this is all colocated in case we ever add more formats in the future?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For sure, will do, also all the coding styles referenced.
/// <inheritdoc/> | ||
public Stream ConvertStream(string filename, Stream source) | ||
{ | ||
IImageConverterProvider provider = _converters.FirstOrDefault(a => a.IsSupported(filename)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do you control the order of these?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since, two Converters cannot support the same extension, there is no ordering needed.
@@ -14,15 +14,15 @@ RUN /copy_runtime.sh | |||
RUN chmod +x /Kavita/Kavita | |||
|
|||
#Production image | |||
FROM ubuntu:focal | |||
FROM ubuntu:oracular |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move to oracular because the include JPEG-XL in there, focal, requires custom build the support. Docker worked really fine. But didn't test ARM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, adding MagicK was the last thing I wanted to do, problem is, while vips supports all the image formats, netvips binding and libraries are boundled with the standard version, not the ALL version.
Will test on ARM, tested on X64 docker, and windows without an issue. git said, every flavor is supported, but, yes, testing will be needed for ARM.
I'm not going to enter the browser war, or format war, just adding the capability of supporting multiple formats and be dynamic about it, independent of the browser, seems the way to go. And since, from my own testing JPEG-XL seems to be a techincal marvel.
The filename it is trying to open doesn't exist in the archive. The file inside |
@DieselTech WIll fix. In that case, the file need to be created in a temp directory. Viewer works fine in your machine? |
Fix GetCoverImage, trying to create a temporary image in current directory, and rename the parameter field name, that generates a wrong asumption.
@DieselTech Please retry, thanks in advance. Seems fixed, but the devil never rests. For completion's sake I'll add two TODO to my list.
|
Preface: These comments are before your latest commit. I am seeing the images in the browser. However it seems like it's trying to call the image endpoint twice, once with the proper image number and a second time that is using page # 1000000
One thing I would like to see is a log entry for the conversion. Not everyone runs these servers on powerful hardware, and it will become necessary when troubleshooting with them why their page loads are taking 5 seconds. That way we can point directly to the conversion task. |
Totally agree on slow servers, on/off flag? The delay exists, mostly, because there is frontend caching, client will try to get multiple images, and Kavita will trigger the conversion of them all. Also, the transcoding only happens once. IDK about the page 1000000. I can add a stopwatch. |
Joe will have to answer this one. There are some things that we do give the user a choice in, but otherwise it's opinionated in order to make the compromise of not layering complexity over and over. I would likely say that IF the image does get converted, to output its duration. If it doesn't get converted, then do not log it.
Honestly I couldn't see a delay at all. The image API responded within 10ms and the page loads felt instant to me. I had to double check to see if it was even working correctly. But using my workstation as a testbed is an unfair comparison with how much power it has. That is why I thought about the log entry so we can know the time taken.
Okay so they should stay around until the users cleanup tasks kick in, which defaults to daily. That said, you sent this PR right as the lead dev is going away for a little bit. This will need to sit until he gets back and looks more in-depth into it. If you have discord you are welcome to join our server and we can communicate in real time there. |
No problemo, will resolve the remaining issues and add some timings to the logging. Will join you guys in discord, tomorrow. |
Optimize Cover Creation
Is this ready for a proper review? If so, I can get it scheduled. I'm still not 100% sure I want to merge this in, but i do want to give it a fair test and also see if there is potential to remove NetVips and ImageSharp altogether, because that could allow for Kavita to run on CPUs that don't have SSE4.2. |
Define proper ;) |
Haha proper means, me pulling everything down, testing, polishing the code for actual inclusion. Yeah, I recently added that attention type of scaling, which helps when users need covers with webtoons, which are long strip format. That is a feature we might see if we can build with ImageMagick.NET. |
maxpiva/kavita:nightly if you want to test the docker. x64/armv7/arm64 (It has your lastest changes). (Release version). Build and debug from windows works as expected. On my machines :) Let'me sit a little with the code, I'll see if we can remove both dependencies.... After that you can take the decision or not to merge. |
@majora2007 I have a new branch on my fork. https://github.com/maxpiva/Kavita/tree/RemoveSixLaborsAndNetVips This one, removes all dependencies on NetVips and ImageSharp and replaces it with ImageMagick. Only differences so far:
Of course, the above fork includes the (JP2, JPX, HEIF, AVIF) transcoding depending on what the browser supports. On iOS per example, all is served directly. The docker image is updated to this fork. |
Awesome, I'm wrapping up some work on the scanner and while I collect testing from the community, I'm planning to give this a run, especially the new fork. If needed, we could leave ImageSharp to help with the matrix math. NetVips is what brings the CPU dependency on the project. I'm hoping for favorable results to bring more support to the project and to more people. |
Updated, instead of using netvips attention, using a direct replacement ported to C#. from https://github.com/muesli/smartcrop So far so good. Docker is also updated. |
I have officially started testing the full NetVips removal branch. |
Nice, probably a refactor will be needed afterwards. We have salted image conversion, thumbnails, and image processing, maybe we can join everything into a service/interface, and use ImageMagick as the first implementation, in that way, if you want to swap motors, another implementation can be created. |
Yeah that's a good idea. I was also looking that jpg was selected as default image format. We might want to think about making it a server setting or even choosing png/webp. Given that Kavita supports major 2 browsers and webp is now supported across the browsers nowadays. I def think we can likely remove the conversion service and move it within the Image service and refactor quite a bit to streamline the code. |
Okay I'm good to move forward with your NetVips removal branch. Let's clean up the code then I'll do another pass on it myself and we can move this into the nightly. We will need more documentation on the methods as well to cover our bases in case something breaks down the line. |
You want me to refactor the Image Service or, and create documentation about the new methods before merging, I think Image Service is a little bloated, maybe a secondary service, that handles image operations. Yes currently, if the format is not supported, it'll be converted into jpg with 99 quality. Same for covers. I could do a PR from the other branch. |
Yeah, let's close this PR and recreate a new one from the other branch. Let's add documentation and refactor the code to be more streamlined. Let's make the format a const in ImageService (jpg or png) so we don't have magic strings. I think png/webp could be good targets or even having some sort of tier like webp then png depending accept response headers could be good. Once that's done, I'll merge into a branch here, then do a round of cleanup to make sure the style is just as I like it and we can finally merge into develop to get into the hands of nightly testers. |
This is not correct. The NetVips bindings does support JPEG XL, JPEG 2000, HEIC and AVIF. However, except for AVIF, the pre-built binaries (i.e. With the update of $ sudo apt-get install libvips --no-install-recommends |
Good call @kleisauke. I was unable to make it work on Windows. Since we need to create a custom native and maintain it, correct? @majora2007 has some secondary concerns related to Netvips, and some CPU limitation that brings to the table on docker. Anyway, since the current image processing implementation is decoupled into an interface and a ImageMagick is an implementation, we could create another implementation supporting NetVips. The question is, we want to? This PR, got overseeded by this one: |
For Windows, you could use the
The CPU concerns only applies to the pre-built Linux binaries provided by NetVips, see: #1423 (comment). |
My 2 cents is if we can keep NetVips without any CPU dependency, I would like that. NetVips is MUCH faster than ImageMagik. |
@kleisauke I was unable to make it work on Windows, do you have a way to use the net bindings with that vips-dev, i was unable to make it work without the netvips native nugets. Including copying the libraries manually. I agree that netvips is faster than ImageMagick, but mantaning our custom netvips.native will be probably a lots of pain. I could also make some defines what is enabled with #define at build time. if we solve the issue with netvips. for netvips to work. We need to:
Addtional, I'l add the capability of having netvips implementation ready inside kavita. In that way, we can actually by putting a conditional define in the build, we can create with one or another.... This will open the possibility to create a docker image/layer using netvips, and other using ImageMagick. If the CPU limitations are still an issue. |
Hmm, that should work without issues; I regularly test the I won't distribute the
|
@kleisauke Thanks. Will start testing again. @majora2007. Could you ask @kleisauke about the docker CPU issues, how we can bypass that? @majora2007 Leme try this out, initially since the native nuget couldn't be used in this case, will try to add a download/unzip or include a custom tool in the normal build pipeline (no docker), and for the docker pipeline do, what @kleisauke recommended. |
Added
Missing