diff --git a/index.html b/index.html index acd144e..1fcb5af 100644 --- a/index.html +++ b/index.html @@ -1588,10 +1588,10 @@ function processStandard(file) { bufReader.onload = e => { bufReader._bytes = new Uint8Array(e.target.result); - dataReader.readAsDataURL(file); }; bufReader.readAsArrayBuffer(file); + dataReader.readAsDataURL(file); } function extractExifFromJpegBuffer(bytes) { @@ -1704,6 +1704,27 @@ function buildMetaFromRaw(exif) { return { camera, lensModel, focalLength, aperture, shutter, iso, date }; } +function extractTiffStringTag(bytes, targetTag) { + if (bytes.length < 8) return null; + const le = bytes[0] === 0x49; + const r16 = o => le ? bytes[o]|(bytes[o+1]<<8) : (bytes[o]<<8)|bytes[o+1]; + const r32 = o => (le ? bytes[o]|(bytes[o+1]<<8)|(bytes[o+2]<<16)|(bytes[o+3]<<24) : (bytes[o]<<24)|(bytes[o+1]<<16)|(bytes[o+2]<<8)|bytes[o+3]) >>> 0; + const ifd0 = r32(4); + if (ifd0 + 2 > bytes.length) return null; + const count = r16(ifd0); + for (let i = 0; i < Math.min(count, 64); i++) { + const e = ifd0 + 2 + i * 12; + if (e + 12 > bytes.length) break; + if (r16(e) === targetTag && r16(e+2) === 2) { + const cnt = r32(e+4); + const doff = cnt > 4 ? r32(e+8) : e+8; + if (doff + cnt > bytes.length) return null; + return new TextDecoder('latin1').decode(bytes.slice(doff, doff+cnt)).replace(/\0/g,'').trim(); + } + } + return null; +} + function processTiff(file) { const reader = new FileReader(); reader.onload = e => { @@ -1724,12 +1745,22 @@ function processTiff(file) { const imgData = tempCtx.createImageData(w, h); imgData.data.set(rgba); tempCtx.putImageData(imgData, 0, 0); - const meta = extractMetaFromTiffIfd(ifd); + const meta = (() => { + const tiffMeta = extractMetaFromTiffIfd(ifd); + const hasData = !!(tiffMeta.camera || tiffMeta.shutter || tiffMeta.iso || tiffMeta.focalLength); + if (hasData) return tiffMeta; + const descBytes = new Uint8Array(buffer); + const descTag = extractTiffStringTag(descBytes, 0x010E); + if (descTag && descTag.includes('SIMPLE')) { + try { return parseFitsHeader(descTag); } catch(e) {} + } + return tiffMeta; + })(); const img = new Image(); img.onload = () => { + const cardIsShowing = currentImg !== null; currentImg = img; clearStatus(); - const cardIsShowing = currentImg !== null; if (cardIsShowing) { renderCard(img, readEditFields()); } else { @@ -1814,10 +1845,15 @@ function processFits(file) { function parseFitsHeader(text) { const meta = {}; - const cards = []; - for (let i = 0; i + 80 <= text.length; i += 80) { - cards.push(text.slice(i, i + 80)); + + const isFixed = text.length >= 80 && !text.slice(0, 80).includes('\n'); + let cards = []; + if (isFixed) { + for (let i = 0; i + 80 <= text.length; i += 80) cards.push(text.slice(i, i + 80)); + } else { + cards = text.split('\n').map(l => l.padEnd(80)); } + const get = key => { const card = cards.find(c => c.slice(0,8).trim() === key); if (!card) return null; @@ -1854,7 +1890,7 @@ function parseFitsHeader(text) { const stackcnt = getNum('STACKCNT') || getNum('NCOMBINE') || getNum('NFRAMES'); meta.frames = stackcnt ? stackcnt + ' frames' : null; - const totalexp = getNum('TOTALEXP'); + const totalexp = getNum('TOTALEXP') || getNum('LIVETIME'); if (totalexp !== null) { const h = Math.floor(totalexp / 3600); const m = Math.floor((totalexp % 3600) / 60); @@ -1867,7 +1903,7 @@ function parseFitsHeader(text) { } const gain = getNum('GAIN'); - const iso = getNum('ISO'); + const iso = getNum('ISO') || getNum('ISOSPEED'); if (iso !== null) meta.iso = 'ISO ' + iso; else if (gain !== null) meta.iso = 'Gain ' + gain; else meta.iso = null;