diff --git a/appinfo/routes.php b/appinfo/routes.php index 10330fdb..02425e10 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -75,7 +75,7 @@ return [ ['name' => 'Image#multipreview', 'url' => '/api/image/multipreview', 'verb' => 'POST'], ['name' => 'Image#info', 'url' => '/api/image/info/{id}', 'verb' => 'GET'], ['name' => 'Image#setExif', 'url' => '/api/image/set-exif/{id}', 'verb' => 'PATCH'], - ['name' => 'Image#jpeg', 'url' => '/api/image/jpeg/{id}', 'verb' => 'GET'], + ['name' => 'Image#decodable', 'url' => '/api/image/decodable/{id}', 'verb' => 'GET'], ['name' => 'Video#transcode', 'url' => '/api/video/transcode/{client}/{fileid}/{profile}', 'verb' => 'GET'], ['name' => 'Video#livephoto', 'url' => '/api/video/livephoto/{fileid}', 'verb' => 'GET'], diff --git a/lib/Controller/ImageController.php b/lib/Controller/ImageController.php index 14782093..a0757a16 100644 --- a/lib/Controller/ImageController.php +++ b/lib/Controller/ImageController.php @@ -264,30 +264,38 @@ class ImageController extends ApiBase * * @PublicPage * - * Get a full resolution JPEG for editing from a file. + * Get a full resolution decodable image for editing from a file. + * The returned image may be png / webp / jpeg. + * These formats are supported by all browsers. */ - public function jpeg(string $id) + public function decodable(string $id) { $file = $this->getUserFile((int) $id); if (!$file) { return new JSONResponse([], Http::STATUS_NOT_FOUND); } - // check if valid image + // Check if valid image $mimetype = $file->getMimeType(); if (!\in_array($mimetype, Application::IMAGE_MIMES, true)) { return new JSONResponse([], Http::STATUS_FORBIDDEN); } - // Get the image - $path = $file->getStorage()->getLocalFile($file->getInternalPath()); - $image = new \Imagick($path); - $image->setImageFormat('jpeg'); - $image->setImageCompressionQuality(95); - $blob = $image->getImageBlob(); + /** @var string Blob of image */ + $blob = $file->getContent(); + + // Convert image to JPEG if required + if (!\in_array($mimetype, ['image/png', 'image/webp', 'image/jpeg'], true)) { + $image = new \Imagick(); + $image->readImageBlob($blob); + $image->setImageFormat('jpeg'); + $image->setImageCompressionQuality(95); + $blob = $image->getImageBlob(); + $mimetype = $image->getImageMimeType(); + } // Return the image - $response = new Http\DataDisplayResponse($blob, Http::STATUS_OK, ['Content-Type' => $image->getImageMimeType()]); + $response = new Http\DataDisplayResponse($blob, Http::STATUS_OK, ['Content-Type' => $mimetype]); $response->cacheFor(3600 * 24, false, false); return $response; diff --git a/src/components/modal/ShareModal.vue b/src/components/modal/ShareModal.vue index bd70a025..6781de40 100644 --- a/src/components/modal/ShareModal.vue +++ b/src/components/modal/ShareModal.vue @@ -176,7 +176,7 @@ export default defineComponent({ const fileid = this.photo.fileid; const src = this.isVideo ? API.VIDEO_TRANSCODE(fileid, "max.mov") - : API.IMAGE_JPEG(fileid); + : API.IMAGE_DECODABLE(fileid, this.photo.etag); this.shareWithHref(src, !this.isVideo); }, diff --git a/src/components/viewer/ImageEditor.vue b/src/components/viewer/ImageEditor.vue index c156ac9f..4f1cb5d1 100644 --- a/src/components/viewer/ImageEditor.vue +++ b/src/components/viewer/ImageEditor.vue @@ -40,11 +40,11 @@ export default defineComponent({ type: Number, required: true, }, - mime: { + src: { type: String, required: true, }, - src: { + etag: { type: String, required: true, }, @@ -57,12 +57,7 @@ export default defineComponent({ computed: { config(): FilerobotImageEditorConfig & { theme: any } { - let src: string; - if (["image/png", "image/jpeg", "image/webp"].includes(this.mime)) { - src = this.src; - } else { - src = API.IMAGE_JPEG(this.fileid); - } + const src = API.IMAGE_DECODABLE(this.fileid, this.etag); return { source: src, diff --git a/src/components/viewer/Viewer.vue b/src/components/viewer/Viewer.vue index 3a992463..32da2ecf 100644 --- a/src/components/viewer/Viewer.vue +++ b/src/components/viewer/Viewer.vue @@ -9,7 +9,7 @@ > { + const _onFocusIn = this.photoswipe.keyboard["_onFocusIn"]; + this.photoswipe.keyboard["_onFocusIn"] = (e: FocusEvent) => { if (e.target instanceof HTMLElement) { if ( e.target.closest("aside.app-sidebar") || diff --git a/src/services/API.ts b/src/services/API.ts index b9c21c40..85a58a08 100644 --- a/src/services/API.ts +++ b/src/services/API.ts @@ -106,8 +106,8 @@ export class API { return gen(`${BASE}/image/set-exif/{id}`, { id }); } - static IMAGE_JPEG(id: number) { - return tok(gen(`${BASE}/image/jpeg/{id}`, { id })); + static IMAGE_DECODABLE(id: number, etag: string) { + return tok(API.Q(gen(`${BASE}/image/decodable/{id}`, { id }), { etag })); } static VIDEO_TRANSCODE(fileid: number, file = "index.m3u8") {