(()=>{ 'use strict'; const PAGE_W=595.28, PAGE_H=841.89; const enc=new TextEncoder(); const ascii=s=>enc.encode(s); const concat=parts=>{const len=parts.reduce((n,p)=>n+p.length,0),out=new Uint8Array(len);let at=0;for(const p of parts){out.set(p,at);at+=p.length}return out}; const object=(id,body)=>{const b=body instanceof Uint8Array?body:ascii(body);return concat([ascii(`${id} 0 obj\n`),b,ascii('\nendobj\n')])}; function normalize(images){ if(!Array.isArray(images)||!images.length)throw new Error('PDF: нет страниц для экспорта.'); return images.map((img,index)=>{ const width=Math.max(1,Math.trunc(Number(img?.width)||0)),height=Math.max(1,Math.trunc(Number(img?.height)||0)); const bytes=img?.bytes instanceof Uint8Array?img.bytes:null; if(!bytes?.length||!width||!height)throw new Error(`PDF: некорректная страница ${index+1}.`); const ratio=width/height,target=PAGE_W/PAGE_H; if(Math.abs(ratio-target)>.015)console.warn(`PDF page ${index+1}: aspect ratio ${ratio.toFixed(4)} differs from A4 ${target.toFixed(4)}`); return {width,height,bytes}; }); } function fromJpegs(input){ const images=normalize(input),objCount=2+images.length*3,objects=new Array(objCount+1); objects[1]=object(1,'<< /Type /Catalog /Pages 2 0 R >>'); const kids=images.map((_,i)=>`${3+i*3} 0 R`).join(' '); objects[2]=object(2,`<< /Type /Pages /Count ${images.length} /Kids [${kids}] >>`); images.forEach((img,i)=>{ const pageId=3+i*3,imageId=4+i*3,contentId=5+i*3; const content=`q\n${PAGE_W} 0 0 ${PAGE_H} 0 0 cm\n/Im1 Do\nQ\n`; objects[pageId]=object(pageId,`<< /Type /Page /Parent 2 0 R /MediaBox [0 0 ${PAGE_W} ${PAGE_H}] /Resources << /XObject << /Im1 ${imageId} 0 R >> >> /Contents ${contentId} 0 R >>`); objects[imageId]=object(imageId,concat([ascii(`<< /Type /XObject /Subtype /Image /Width ${img.width} /Height ${img.height} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode /Length ${img.bytes.length} >>\nstream\n`),img.bytes,ascii('\nendstream')])); const cb=ascii(content);objects[contentId]=object(contentId,concat([ascii(`<< /Length ${cb.length} >>\nstream\n`),cb,ascii('endstream')])); }); const header=concat([ascii('%PDF-1.4\n%'),new Uint8Array([255,255,255,255]),ascii('\n')]); const offsets=new Array(objCount+1).fill(0),parts=[header];let pos=header.length; for(let id=1;id<=objCount;id++){offsets[id]=pos;parts.push(objects[id]);pos+=objects[id].length} const xrefPos=pos;let xref=`xref\n0 ${objCount+1}\n0000000000 65535 f \n`; for(let id=1;id<=objCount;id++)xref+=String(offsets[id]).padStart(10,'0')+' 00000 n \n'; parts.push(ascii(xref+`trailer\n<< /Size ${objCount+1} /Root 1 0 R >>\nstartxref\n${xrefPos}\n%%EOF\n`)); return new Blob(parts,{type:'application/pdf'}); } window.SunPdfEngine=Object.freeze({PAGE_W,PAGE_H,fromJpegs}); })();