Skip to content

Commit d320aad

Browse files
committed
Fix: Stuttering when decode big images (From sync decode to async when possible)
1 parent d9f94e7 commit d320aad

5 files changed

Lines changed: 105 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
3030
- Gamepad menus do not work correctly [`b997d6b`](https://github.com/ollm/OpenComic/commit/b997d6bb6e05c597306169cb4fbbe035a4ab12d1)
3131
- Sharp crashes on Arch Linux and other distributions [`d60620a`](https://github.com/ollm/OpenComic/commit/d60620a2d3a446fef51cd86eff2dc80b22ccf6ba)
3232
- Add cMap support for PDF.js [`3da7b8e`](https://github.com/ollm/OpenComic/commit/3da7b8ec651964209d1df04248dad2bb8ab693bd)
33-
- Page jumps during zoom animation in vertical reading
33+
- Page jumps during zoom animation in vertical reading [`d9f94e7`](https://github.com/ollm/OpenComic/commit/d9f94e7eb5e757a28c6b92f0c3a791fc3be61282)
34+
- Stuttering when decode big images (From sync decode to async when possible)
3435

3536
## [v1.4.1](https://github.com/ollm/OpenComic/releases/tag/v1.4.1) (08-02-2025)
3637

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@
110110
"webdav": "^5.8.0"
111111
},
112112
"devDependencies": {
113-
"electron": "^34.3.3",
113+
"electron": "^34.5.1",
114114
"electron-builder": "^26.0.12",
115115
"env-cmd": "^10.1.0",
116116
"node-abi": "^4.2.0",

scripts/reading/render.js

Lines changed: 97 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ async function setFile(_file, _scaleMagnifyingGlass = false, _renderType = 'canv
4444
if(renderImages)
4545
revokeAllObjectURL();
4646

47+
createObserver();
48+
4749
return;
4850
}
4951

@@ -495,24 +497,23 @@ async function render(index, _scale = false, magnifyingGlass = false)
495497
{
496498
console.error(error);
497499

498-
img.src = app.encodeSrcURI(app.shortWindowsPath(src, true));
499-
img.classList.remove('blobRendered', 'blobRender');
500-
img.style.imageRendering = '';
500+
await srcToImage(src, img)
501501
}
502502
}
503503
else
504504
{
505-
img.src = app.encodeSrcURI(app.shortWindowsPath(src, true));
506-
img.classList.remove('blobRendered', 'blobRender');
507-
img.style.imageRendering = '';
505+
await srcToImage(src, img)
508506
}
509507
}
510508
else
511509
{
512-
img.src = app.encodeSrcURI(app.shortWindowsPath(src, true));
513-
img.classList.remove('blobRendered', 'blobRender');
514-
img.style.imageRendering = '';
510+
await srcToImage(src, img)
515511
}
512+
513+
if((onRender && onRender.num > 0) || _scale)
514+
await decodeImage(img, true);
515+
else
516+
decodeImage(img, false);
516517
}
517518

518519
if(onRender)
@@ -542,6 +543,93 @@ async function render(index, _scale = false, magnifyingGlass = false)
542543
return;
543544
}
544545

546+
async function srcToImage(src, img)
547+
{
548+
img.src = app.encodeSrcURI(app.shortWindowsPath(src, true));
549+
img.classList.remove('blobRendered', 'blobRender');
550+
img.style.imageRendering = '';
551+
552+
return true;
553+
}
554+
555+
async function decodeImage(img, sync = false)
556+
{
557+
if(sync)
558+
{
559+
try
560+
{
561+
await img.decode();
562+
}
563+
catch(e){}
564+
}
565+
566+
observer.observe(img);
567+
}
568+
569+
var observer = false;
570+
571+
function createObserver()
572+
{
573+
if(observer)
574+
observer.disconnect();
575+
576+
observer = new IntersectionObserver(function(entries) {
577+
578+
for(let i = 0, len = entries.length; i < len; i++)
579+
{
580+
const entry = entries[i];
581+
582+
if(entry.isIntersecting || entry.intersectionRatio > 0)
583+
{
584+
try
585+
{
586+
entry.target.decode();
587+
}
588+
catch(e){}
589+
}
590+
}
591+
592+
}, {
593+
root: template._contentRight().firstElementChild,
594+
rootMargin: '4000px',
595+
threshold: 0,
596+
});
597+
}
598+
599+
/*function removeDecodeImageInCanvas(img, ocImg)
600+
{
601+
const canvas = ocImg.querySelector('canvas');
602+
if(canvas) canvas.remove();
603+
604+
img.style.display = '';
605+
}
606+
607+
async function decodeImageInCanvas(src, img, ocImg)
608+
{
609+
console.log(src);
610+
611+
const response = await fetch(app.shortWindowsPath(src, true));
612+
const buffer = await response.blob();
613+
const bitmap = await createImageBitmap(buffer);
614+
615+
let canvas = ocImg.querySelector('canvas');
616+
617+
if(!canvas)
618+
{
619+
canvas = document.createElement('canvas');
620+
canvas.className = 'originalSize imageInCanvas';
621+
canvas.width = bitmap.width;
622+
canvas.height = bitmap.height;
623+
ocImg.prepend(canvas);
624+
img.style.display = 'none';
625+
}
626+
627+
const ctx = canvas.getContext('2d');
628+
ctx.drawImage(bitmap, 0, 0);
629+
630+
return true;
631+
}*/
632+
545633
module.exports = {
546634
setFile: setFile,
547635
reset: reset,

templates/reading.content.right.images.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
{{else if ebook}}
2626
<!-- <iframe> -->
2727
{{else}}
28-
<img data-src="{{htmlQuote image}}" data-path="{{htmlQuote path}}" data-index="{{index}}">
28+
<img data-src="{{htmlQuote image}}" data-path="{{htmlQuote path}}" data-index="{{index}}" decoding="async">
2929
{{/if}}
3030
</oc-img>
3131
{{/if}}

0 commit comments

Comments
 (0)