mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-05-23 11:42:14 +00:00
Merge pull request #728 from mrandhawa14/fix/cover-decode-resize
perf(library): decode covers at thumbnail resolution to cut image-cache RAM (refs #609)
This commit is contained in:
commit
2d9eebe94e
3 changed files with 49 additions and 7 deletions
|
|
@ -6,19 +6,21 @@ import 'package:mangayomi/modules/library/providers/library_filter_provider.dart
|
|||
import 'package:mangayomi/modules/library/providers/library_state_provider.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/modules/manga/detail/providers/state_providers.dart';
|
||||
import 'package:mangayomi/modules/widgets/custom_extended_image_provider.dart';
|
||||
import 'package:mangayomi/modules/widgets/manga_image_card_widget.dart';
|
||||
import 'package:mangayomi/utils/cached_network.dart';
|
||||
import 'package:mangayomi/utils/constant.dart';
|
||||
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
|
||||
import 'package:mangayomi/utils/headers.dart';
|
||||
|
||||
/// Resolves the correct [ImageProvider] for a manga entry, preferring a custom
|
||||
/// local cover over the remote URL.
|
||||
/// local cover over the remote URL. Remote covers are wrapped in
|
||||
/// [coverProvider] so they decode at thumbnail resolution rather than the
|
||||
/// source resolution — see refs #609.
|
||||
ImageProvider resolveCoverImage(Manga entry, WidgetRef ref) {
|
||||
if (entry.customCoverImage != null) {
|
||||
return MemoryImage(entry.customCoverImage as Uint8List);
|
||||
}
|
||||
return CustomExtendedNetworkImageProvider(
|
||||
return coverProvider(
|
||||
toImgUrl(entry.customCoverFromTracker ?? entry.imageUrl ?? ''),
|
||||
headers: (entry.isLocalArchive ?? false)
|
||||
? null
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import 'package:mangayomi/models/manga.dart';
|
|||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/modules/manga/detail/manga_detail_main.dart';
|
||||
import 'package:mangayomi/modules/widgets/custom_extended_image_provider.dart';
|
||||
import 'package:mangayomi/utils/cached_network.dart';
|
||||
import 'package:mangayomi/router/router.dart';
|
||||
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
|
||||
import 'package:mangayomi/utils/constant.dart';
|
||||
|
|
@ -46,7 +46,7 @@ class MangaImageCardWidget extends ConsumerWidget {
|
|||
image: hasData && libraryManga!.customCoverImage != null
|
||||
? MemoryImage(libraryManga!.customCoverImage as Uint8List)
|
||||
as ImageProvider
|
||||
: CustomExtendedNetworkImageProvider(
|
||||
: coverProvider(
|
||||
toImgUrl(
|
||||
hasData
|
||||
? libraryManga!.customCoverFromTracker ??
|
||||
|
|
@ -61,7 +61,6 @@ class MangaImageCardWidget extends ConsumerWidget {
|
|||
sourceId: source.id,
|
||||
),
|
||||
),
|
||||
cache: true,
|
||||
cacheMaxAge: const Duration(days: 7),
|
||||
),
|
||||
onTap: () => _toMangaRdD(ref, context, false),
|
||||
|
|
@ -138,7 +137,7 @@ class MangaImageCardListTileWidget extends ConsumerWidget {
|
|||
final image = hasData && libraryManga!.customCoverImage != null
|
||||
? MemoryImage(libraryManga!.customCoverImage as Uint8List)
|
||||
as ImageProvider
|
||||
: CustomExtendedNetworkImageProvider(
|
||||
: coverProvider(
|
||||
toImgUrl(
|
||||
hasData
|
||||
? libraryManga!.customCoverFromTracker ??
|
||||
|
|
|
|||
|
|
@ -2,6 +2,47 @@ import 'package:extended_image/extended_image.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:mangayomi/modules/widgets/custom_extended_image_provider.dart';
|
||||
|
||||
/// Default upper bound on the encoded byte size of a thumbnail-sized cover
|
||||
/// after `ExtendedResizeImage` resamples. 200 KB roughly maps to a 400x600
|
||||
/// JPEG / WebP — sharp enough at typical grid / list display sizes on
|
||||
/// high-DPR screens, while keeping the *decoded* RAM footprint small (the
|
||||
/// resampled image goes into Flutter's `imageCache` decoded, where every
|
||||
/// saved KB matters).
|
||||
const int _coverMaxBytes = 200 << 10;
|
||||
|
||||
/// Returns an `ImageProvider` for a manga / anime cover URL that decodes at
|
||||
/// thumbnail resolution rather than the source resolution.
|
||||
///
|
||||
/// Source covers are commonly 720x1080 or larger (~3 MB decoded RGBA per
|
||||
/// cover). When used directly in a library grid or list, every visible
|
||||
/// thumbnail fills `imageCache` with a 3 MB blob even though it renders at
|
||||
/// ~150x220 logical pixels. Wrapping the provider in `ExtendedResizeImage`
|
||||
/// instructs the decoder to resample to a much smaller bitmap before it
|
||||
/// hits the cache, so the same in-memory budget holds far more thumbnails
|
||||
/// and scrolling stops thrashing.
|
||||
///
|
||||
/// Use this for thumbnail call sites (library grid / list, browse search
|
||||
/// cards, tracker results, calendar, etc.). Do *not* use it for large hero
|
||||
/// covers (manga detail page) or for reader pages, which need full
|
||||
/// resolution.
|
||||
ImageProvider coverProvider(
|
||||
String url, {
|
||||
Map<String, String>? headers,
|
||||
int maxBytes = _coverMaxBytes,
|
||||
bool cache = true,
|
||||
Duration? cacheMaxAge,
|
||||
}) {
|
||||
return ExtendedResizeImage(
|
||||
CustomExtendedNetworkImageProvider(
|
||||
url,
|
||||
headers: headers,
|
||||
cache: cache,
|
||||
cacheMaxAge: cacheMaxAge,
|
||||
),
|
||||
maxBytes: maxBytes,
|
||||
);
|
||||
}
|
||||
|
||||
Widget cachedNetworkImage({
|
||||
Map<String, String>? headers,
|
||||
required String imageUrl,
|
||||
|
|
|
|||
Loading…
Reference in a new issue