mirror of
https://github.com/immich-app/immich
synced 2026-08-15 13:03:57 +00:00
fix(mobile): decode remote thumbnails at displayed size (#29965)
* fix(mobile): decode remote thumbnails at displayed size * use nullable decode size and reuse the tapped thumbnail in the viewer * clean up decode size naming and guards
This commit is contained in:
parent
c52bf9995b
commit
9862e50aab
18 changed files with 386 additions and 71 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:async';
|
||||
import 'dart:ffi';
|
||||
import 'dart:math' as math;
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
|
@ -36,7 +37,11 @@ abstract class ImageRequest {
|
|||
|
||||
void _onCancelled();
|
||||
|
||||
Future<(ui.Codec, ui.ImageDescriptor)?> _codecFromEncodedPlatformImage(int address, int length) async {
|
||||
Future<(ui.Codec, ui.ImageDescriptor)?> _codecFromEncodedPlatformImage(
|
||||
int address,
|
||||
int length, {
|
||||
ui.Size? decodeSize,
|
||||
}) async {
|
||||
final pointer = Pointer<Uint8>.fromAddress(address);
|
||||
if (_isCancelled) {
|
||||
malloc.free(pointer);
|
||||
|
|
@ -62,7 +67,8 @@ abstract class ImageRequest {
|
|||
return null;
|
||||
}
|
||||
|
||||
final codec = await descriptor.instantiateCodec();
|
||||
final target = _targetSize(descriptor.width, descriptor.height, decodeSize);
|
||||
final codec = await descriptor.instantiateCodec(targetWidth: target?.$1, targetHeight: target?.$2);
|
||||
if (_isCancelled) {
|
||||
descriptor.dispose();
|
||||
codec.dispose();
|
||||
|
|
@ -72,8 +78,8 @@ abstract class ImageRequest {
|
|||
return (codec, descriptor);
|
||||
}
|
||||
|
||||
Future<ui.FrameInfo?> _fromEncodedPlatformImage(int address, int length) async {
|
||||
final result = await _codecFromEncodedPlatformImage(address, length);
|
||||
Future<ui.FrameInfo?> _fromEncodedPlatformImage(int address, int length, {ui.Size? decodeSize}) async {
|
||||
final result = await _codecFromEncodedPlatformImage(address, length, decodeSize: decodeSize);
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -96,6 +102,19 @@ abstract class ImageRequest {
|
|||
return frame;
|
||||
}
|
||||
|
||||
(int, int)? _targetSize(int width, int height, ui.Size? decodeSize) {
|
||||
if (width <= 0 || height <= 0 || decodeSize == null || decodeSize.width <= 0 || decodeSize.height <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final scale = math.max(decodeSize.width / width, decodeSize.height / height);
|
||||
if (scale >= 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ((width * scale).ceil(), (height * scale).ceil());
|
||||
}
|
||||
|
||||
Future<ui.FrameInfo?> _fromDecodedPlatformImage(int address, int width, int height, int rowBytes) async {
|
||||
final pointer = Pointer<Uint8>.fromAddress(address);
|
||||
if (_isCancelled) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,10 @@ part of 'image_request.dart';
|
|||
class RemoteImageRequest extends ImageRequest {
|
||||
final String uri;
|
||||
|
||||
RemoteImageRequest({required this.uri});
|
||||
/// Physical size to decode, or null for the source size.
|
||||
final ui.Size? decodeSize;
|
||||
|
||||
RemoteImageRequest({required this.uri, this.decodeSize});
|
||||
|
||||
@override
|
||||
Future<ImageInfo?> load(ImageDecoderCallback decode, {double scale = 1.0}) async {
|
||||
|
|
@ -11,10 +14,20 @@ class RemoteImageRequest extends ImageRequest {
|
|||
return null;
|
||||
}
|
||||
|
||||
final info = await remoteImageApi.requestImage(uri, requestId: requestId, preferEncoded: false);
|
||||
final info = await remoteImageApi.requestImage(
|
||||
uri,
|
||||
requestId: requestId,
|
||||
preferEncoded: false,
|
||||
width: decodeSize?.width.ceil(),
|
||||
height: decodeSize?.height.ceil(),
|
||||
);
|
||||
// Android falls back to encoded data if native decoding fails, so check for both shapes of the response.
|
||||
final frame = switch (info) {
|
||||
{'pointer': final int pointer, 'length': final int length} => await _fromEncodedPlatformImage(pointer, length),
|
||||
{'pointer': final int pointer, 'length': final int length} => await _fromEncodedPlatformImage(
|
||||
pointer,
|
||||
length,
|
||||
decodeSize: decodeSize,
|
||||
),
|
||||
{
|
||||
'pointer': final int pointer,
|
||||
'width': final int width,
|
||||
|
|
@ -33,7 +46,13 @@ class RemoteImageRequest extends ImageRequest {
|
|||
return null;
|
||||
}
|
||||
|
||||
final info = await remoteImageApi.requestImage(uri, requestId: requestId, preferEncoded: true);
|
||||
final info = await remoteImageApi.requestImage(
|
||||
uri,
|
||||
requestId: requestId,
|
||||
preferEncoded: true,
|
||||
width: null,
|
||||
height: null,
|
||||
);
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue