Skip to content

Commit b741e52

Browse files
authored
Fix: Wrong size detection for animated AVIF images
1 parent 9ee3ccd commit b741e52

2 files changed

Lines changed: 134 additions & 138 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
4141
- Move zoom using cursor after turning a pages not working property [`3012715`](https://github.com/ollm/OpenComic/commit/30127150751b1de611f95069e748eab68fcd2f51)
4242
- Turn page forward in manga mode (Only on non-arrow keys) [`bdbc0dc`](https://github.com/ollm/OpenComic/commit/bdbc0dc31ab37bdfcef570bf8f2130e39c08861e)
4343
- Check if the file is written to disk when extracting using 7zip [`66d4897`](https://github.com/ollm/OpenComic/commit/66d48977b4ef33b320676d39656d48ea41aff653)
44+
- Wrong size detection for animated AVIF images
4445

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

scripts/image.js

Lines changed: 133 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -312,173 +312,168 @@ function loadImage(url, encode = false)
312312
});
313313
}
314314

315-
var threads = false, sizesCache = {};
315+
var sizesCache = {};
316316

317317
async function getSizes(images)
318318
{
319319
await loadSharp();
320-
if(threads === false) threads = os.cpus().length || 1;
321320

322321
const sizes = [];
322+
const promises = [];
323323
const len = images.length;
324324

325325
for(let i = 0; i < len; i++)
326326
{
327327
sizes.push(false);
328-
}
329328

330-
let promises = [];
331-
let index = 0;
329+
const image = images[i];
332330

333-
for(let i = 0; i < threads; i++)
334-
{
335-
promises.push(new Promise(async function(resolve) {
331+
if(!image.image || image.folder)
332+
continue;
333+
334+
const sha = image.sha || sha1(image.path);
336335

337-
toBreak:
338-
while(true)
336+
if(sizesCache[sha])
337+
{
338+
sizes[i] = sizesCache[sha];
339+
continue;
340+
}
341+
342+
promises.push(threads.job('getImageSizes', {useThreads: 1}, async function() {
343+
344+
let size = {
345+
width: 1,
346+
height: 1,
347+
};
348+
349+
try
339350
{
340-
const p = index++;
341-
const image = images[p];
351+
const extension = app.extname(image.image);
352+
353+
if(compatible.image.heic.has(extension))
354+
{
355+
if(heic === false)
356+
heic = require('heic-decode');
357+
358+
const buffer = await fsp.readFile(image.image);
359+
const images = await heic.all({buffer});
360+
const properties = images[0] || {width: 1, height: 1};
361+
362+
size = {
363+
width: properties.width,
364+
height: properties.height,
365+
};
366+
}
367+
else if(compatible.image.jp2.has(extension))
368+
{
369+
if(pdfjsDecoders === false)
370+
await loadPdfjsDecoders();
371+
372+
const buffer = await fsp.readFile(image.image);
373+
const properties = pdfjsDecoders.JpxImage.parseImageProperties(buffer);
374+
375+
size = {
376+
width: properties.width,
377+
height: properties.height,
378+
};
379+
}
380+
else if(compatible.image.jxl.has(extension))
381+
{
382+
if(JxlImage === false)
383+
await loadJxlImage();
342384

343-
if(image)
385+
const buffer = await fsp.readFile(image.image);
386+
387+
const jxlImage = new JxlImage();
388+
jxlImage.feedBytes(buffer);
389+
390+
if(!jxlImage.tryInit())
391+
throw new Error('Partial image, no frame data');
392+
393+
size = {
394+
width: jxlImage.width,
395+
height: jxlImage.height,
396+
};
397+
}
398+
else if(compatible.image.blob.has(extension))
399+
{
400+
if(imageSize === false)
401+
imageSize = require('image-size/fromFile').imageSizeFromFile;
402+
403+
try
404+
{
405+
const dimensions = await imageSize(image.image);
406+
407+
size = {
408+
width: dimensions.width,
409+
height: dimensions.height,
410+
};
411+
}
412+
catch(error)
413+
{
414+
const blob = await workers.convertImageToBlob(image.image);
415+
const buffer = await (await fetch(blob)).arrayBuffer();
416+
417+
const _sharp = sharp(buffer);
418+
const metadata = await _sharp.metadata();
419+
420+
size = {
421+
width: metadata.width,
422+
height: metadata.height,
423+
};
424+
}
425+
}
426+
else if(sharpSupportedFormat(image.image, extension))
344427
{
345-
if(image.image && !image.folder)
428+
try
346429
{
347-
const sha = image.sha || sha1(image.path);
348-
349-
if(sizesCache[sha])
350-
{
351-
sizes[p] = sizesCache[sha];
352-
}
353-
else
354-
{
355-
let size = {
356-
width: 1,
357-
height: 1,
358-
};
359-
360-
try
361-
{
362-
const extension = app.extname(image.image);
363-
364-
if(compatible.image.heic.has(extension))
365-
{
366-
if(heic === false)
367-
heic = require('heic-decode');
368-
369-
const buffer = await fsp.readFile(image.image);
370-
const images = await heic.all({buffer});
371-
const properties = images[0] || {width: 1, height: 1};
372-
373-
size = {
374-
width: properties.width,
375-
height: properties.height,
376-
};
377-
}
378-
else if(compatible.image.jp2.has(extension))
379-
{
380-
if(pdfjsDecoders === false)
381-
await loadPdfjsDecoders();
382-
383-
const buffer = await fsp.readFile(image.image);
384-
const properties = pdfjsDecoders.JpxImage.parseImageProperties(buffer);
385-
386-
size = {
387-
width: properties.width,
388-
height: properties.height,
389-
};
390-
}
391-
else if(compatible.image.jxl.has(extension))
392-
{
393-
if(JxlImage === false)
394-
await loadJxlImage();
395-
396-
const buffer = await fsp.readFile(image.image);
397-
398-
const jxlImage = new JxlImage();
399-
jxlImage.feedBytes(buffer);
400-
401-
if(!jxlImage.tryInit())
402-
throw new Error('Partial image, no frame data');
403-
404-
size = {
405-
width: jxlImage.width,
406-
height: jxlImage.height,
407-
};
408-
}
409-
else if(compatible.image.blob.has(extension))
410-
{
411-
if(imageSize === false)
412-
imageSize = require('image-size/fromFile').imageSizeFromFile;
413-
414-
try
415-
{
416-
const dimensions = await imageSize(image.image);
417-
418-
size = {
419-
width: dimensions.width,
420-
height: dimensions.height,
421-
};
422-
}
423-
catch(error)
424-
{
425-
const blob = await workers.convertImageToBlob(image.image);
426-
const buffer = await (await fetch(blob)).arrayBuffer();
427-
428-
const _sharp = sharp(buffer);
429-
const metadata = await _sharp.metadata();
430-
431-
size = {
432-
width: metadata.width,
433-
height: metadata.height,
434-
};
435-
}
436-
}
437-
else if(sharpSupportedFormat(image.image, extension))
438-
{
439-
fileManager.macosStartAccessingSecurityScopedResource(image.image);
440-
const _sharp = sharp(app.shortWindowsPath(image.image));
441-
const metadata = await _sharp.metadata();
442-
443-
size = {
444-
width: metadata.width,
445-
height: metadata.height,
446-
};
447-
}
448-
else
449-
{
450-
const img = new Image();
451-
img.src = image.image;
452-
await img.decode();
453-
454-
size = {
455-
width: img.naturalWidth,
456-
height: img.naturalHeight,
457-
};
458-
}
459-
}
460-
catch(error)
461-
{
462-
console.error(error);
463-
}
464-
465-
sizesCache[sha] = size;
466-
sizes[p] = size;
467-
}
430+
fileManager.macosStartAccessingSecurityScopedResource(image.image);
431+
const _sharp = sharp(app.shortWindowsPath(image.image));
432+
const metadata = await _sharp.metadata();
433+
434+
size = {
435+
width: metadata.width,
436+
height: metadata.height,
437+
};
438+
}
439+
catch(error)
440+
{
441+
const img = new Image();
442+
img.src = image.image;
443+
await img.decode();
444+
445+
size = {
446+
width: img.naturalWidth,
447+
height: img.naturalHeight,
448+
};
468449
}
469450
}
470451
else
471452
{
472-
break toBreak;
453+
const img = new Image();
454+
img.src = image.image;
455+
await img.decode();
456+
457+
size = {
458+
width: img.naturalWidth,
459+
height: img.naturalHeight,
460+
};
473461
}
474462
}
463+
catch(error)
464+
{
465+
console.error(error);
466+
}
467+
468+
sizesCache[sha] = size;
469+
sizes[i] = size;
475470

476-
resolve();
471+
return;
477472

478473
}));
479474
}
480475

481-
await Promise.all(promises)
476+
await Promise.all(promises);
482477

483478
return sizes;
484479
}

0 commit comments

Comments
 (0)