Skip to content
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

Add EXIF thumbnail support for JPEG files #1234

Merged
merged 1 commit into from
Mar 29, 2021

Conversation

adrium
Copy link
Contributor

@adrium adrium commented Jan 6, 2021

Description
Compact implementation to support EXIF thumbnails. Listing a directory with a lot of thumbnails will be a lot faster. The following was recorded with the master branch and with the feature proposed here. The app runs on a Raspberry Pi 4b accessing files on a hard disk.

  • requesting to pull a topic/feature/bugfix branch
  • pull request against the master branch
  • File Browser can be successfully built
  • no issues are opened in other repositories
  • continuous integration build passed

@adrium
Copy link
Contributor Author

adrium commented Jan 7, 2021

img/service.go:226:11: ineffectual assignment to `err` (ineffassign)
					thm, err = index.RootIfd.NextIfd().Thumbnail()
					     ^
img/service.go:161:7: shadow: declaration of "err" shadows declaration at line 143 (govet)
			_, err := out.Write(thm)
			   ^
img/service.go:221:8: shadow: declaration of "err" shadows declaration at line 202 (govet)
			im, err := exifcommon.NewIfdMappingWithStandard()
			    ^

Those assignments are actually effective...

img/service.go:14: File is not `goimports`-ed with -local github.com/filebrowser/filebrowser (goimports)
	"github.com/dsoprea/go-exif/v3/common"

How can I fix the import error?

@adrium adrium force-pushed the fast-thumbnails branch 2 times, most recently from 7968bb3 to c7c2439 Compare January 7, 2021 15:16
@adrium
Copy link
Contributor Author

adrium commented Jan 7, 2021

Fixed CI, all set 🚀

@adrium adrium force-pushed the fast-thumbnails branch 2 times, most recently from 45d08f8 to 2bcfb3b Compare January 9, 2021 10:12
@adrium
Copy link
Contributor Author

adrium commented Jan 9, 2021

Latest updated includes a fix for thumbnail distortion. object-fit: cover is added to stylesheet.
Also rebased to latest master.

@niubility000
Copy link
Contributor

It's pretty cool. very very fast and smooth!
But for some pics, it just didn't show the thumbnails. Would you please fix that. Maybe in this situation, just allow the filebrowser to generate the thumknails for those pics. Here 's the screenshot and some that kind of pics.
TMP.zip

@adrium adrium force-pushed the fast-thumbnails branch 2 times, most recently from 3d12d2b to f22c4eb Compare February 2, 2021 22:16
@adrium
Copy link
Contributor Author

adrium commented Feb 2, 2021

Thanks for reporting. Reason was because EXIF exists, but does not contain a thumbnail in the files provided.

This is fixed in the newest version of the pull request. Additionally, it was rebased onto master and added the feat: prefix to the commit message.

@niubility000
Copy link
Contributor

Wow, I checked it. Perfect!! very fast! especially for the folder with tons of pics. and it 's pretty cool for the low-end server!

@niubility000
Copy link
Contributor

Oops, I just found a small bug. For some pictures, It looks like the thumbnails are broken, only shows half of them. Would you please check out these pics?
temp.zip

@adrium
Copy link
Contributor Author

adrium commented Feb 5, 2021

Hi niubility, thanks for testing this PR so thoroughly.
Let's hope it will make into the master branch eventually.

The thumbnails in your files were larger than the preloaded size of 32k.
In the examples I had, a lot of thumbnails were around 16k that's why I chose the value of 32k.

Theoretically, Exif data (including the thumbnails) must fit in the APP1 marker and all JPEG markers can be max 64k.
The preload size is now 0xffff and it will be hopefully be sufficiently large.

@adrium
Copy link
Contributor Author

adrium commented Feb 5, 2021

Improved code style

@niubility000
Copy link
Contributor

niubility000 commented Feb 6, 2021

Great! I have tried. It's wonderful!
and the file list's loading speed is amazing fast! I don't need to wait like half a minute for that anymore.

Copy link
Member

@o1egl o1egl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add tests

wrappedReader := io.MultiReader(buf, in)

offset := 0
offsets := []int{12, 30}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please explain why are you checking those offsets only?

Copy link
Contributor Author

@adrium adrium Mar 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those are the two most common offsets where the Exif starts in JPEG files. To avoid more complex parsing (and library dependencies), it only checks those offsets.

If no Exif is found, it will fall back to the downscaling method.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked that in the provided library the different approach is used https://github.com/dsoprea/go-exif/blob/d154f10435cc/v3/exif.go#L52

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. And that's the approach in the first (unpublished) attempt. That function tries to find an exif in brute-force fashion byte by byte scanning the whole file: https://github.com/dsoprea/go-exif/blob/d154f10435cc6ae4b64cd68eed04a1d005b73ec7/v3/exif.go#L150

It is more efficient by just checking the most common offsets for exif and there was a noticeable performance increase.

@adrium
Copy link
Contributor Author

adrium commented Mar 2, 2021

Writing tests will require quite some effort... I will look into it when I have time

go.mod Outdated
@@ -10,6 +10,7 @@ require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/disintegration/imaging v1.6.2
github.com/dsnet/compress v0.0.1 // indirect
github.com/dsoprea/go-exif/v3 v3.0.0-20201216222538-db167117f483 // indirect
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not stick to version v3.0.0?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly no clue. That was added by go get automatically...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix it, please

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked into this and tried to stick to the version number you mentioned. However, the library does not seem provide tagged releases:

:~/Code/filebrowser*master$ go get -d github.com/dsoprea/go-exif/v3@v3.0.0
go get: github.com/dsoprea/go-exif/v3@v3.0.0: invalid version: unknown revision v3.0.0

:~/Code/filebrowser*master$ go get -d github.com/dsoprea/go-exif/v3@3.0.0
go: downloading github.com/dsoprea/go-exif v0.0.0-20200711180620-208788de2815
go get: module github.com/dsoprea/go-exif@3.0.0 found (v0.0.0-20200711180620-208788de2815), but does not contain package github.com/dsoprea/go-exif/v3

The library is pulled as recommended. Other projects use the library in a similar way. Examples are PhotoPrism (listed on Awesome-Selfhosted) and other projects on GitHub:

As such, the dependency file should probably be kept as committed.

@adrium
Copy link
Contributor Author

adrium commented Mar 7, 2021

Please add tests

Constructing pictures programmatically requires a lot of code and is error-prone in itself.

On the other hand, the pictures provided by niubility000 are a very useful set and are "real" data.
I propose to use those pictures to create the tests (if the user agrees). The extracted thumbnails could be compared to the expected hash values.

Do you prefer a specific structure to check in the files?

@o1egl
Copy link
Member

o1egl commented Mar 8, 2021

@adrium I agree that using image files will be better for that. If you plan to add table tests, please look at https://github.com/filebrowser/filebrowser/blob/master/img/service_test.go for a reference.

@adrium
Copy link
Contributor Author

adrium commented Mar 9, 2021

@o1egl Thanks a lot for your feedback.

@niubility000 Do you agree to make use of the pictures you provided for testing and thereby checking them in into this repo?

@adrium
Copy link
Contributor Author

adrium commented Mar 29, 2021

Tests added. Image credits:

Copy link
Member

@o1egl o1egl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@o1egl o1egl merged commit 7dd5b34 into filebrowser:master Mar 29, 2021
@adrium adrium deleted the fast-thumbnails branch March 29, 2021 20:05
Alsan pushed a commit to Alsan/filebrowser that referenced this pull request Aug 25, 2021
@adrium adrium mentioned this pull request Jan 11, 2022
@niubility000
Copy link
Contributor

I just found a bug: #2137

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants