mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-13 11:40:49 +08:00
Show Retina screenshots at their intended size
macOS saves Retina screenshots at 144 DPI and we rendered them at twice the size they had on screen. We now scale PNGs with a 2x or 3x density down; everything else, including 300 DPI print exports, stays 1:1.
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
import { toDom } from "hast-util-to-dom";
|
||||
import { mount, tick, unmount } from "svelte";
|
||||
|
||||
import { embedPreviewKind } from "@app/lib/embeds";
|
||||
import { embedPreviewKind, retinaWidth } from "@app/lib/embeds";
|
||||
import { parseFrontmatter } from "@app/lib/frontmatter";
|
||||
import { invoke } from "@app/lib/invoke";
|
||||
import {
|
||||
@@ -73,10 +73,15 @@
|
||||
function createEmbedPreview(
|
||||
mimeType: string | null,
|
||||
url: string,
|
||||
content: Uint8Array,
|
||||
): HTMLElement | undefined {
|
||||
const kind = embedPreviewKind(mimeType);
|
||||
if (kind === "image") {
|
||||
const element = document.createElement("img");
|
||||
const width = retinaWidth(content);
|
||||
if (width) {
|
||||
element.style.width = `${width}px`;
|
||||
}
|
||||
element.setAttribute("src", url);
|
||||
element.style.display = "block";
|
||||
return element;
|
||||
@@ -308,10 +313,9 @@
|
||||
}
|
||||
let preview = embedPreviews.get(href);
|
||||
if (!preview) {
|
||||
const url = URL.createObjectURL(
|
||||
new Blob([Buffer.from(content)]),
|
||||
);
|
||||
const element = createEmbedPreview(mimeType, url);
|
||||
const bytes = Buffer.from(content);
|
||||
const url = URL.createObjectURL(new Blob([bytes]));
|
||||
const element = createEmbedPreview(mimeType, url, bytes);
|
||||
if (!element) {
|
||||
URL.revokeObjectURL(url);
|
||||
console.warn(
|
||||
|
||||
@@ -11,3 +11,38 @@ export function embedPreviewKind(
|
||||
if (mimeType?.startsWith("audio")) return "audio";
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const pngSignature = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
|
||||
|
||||
function chunkType(bytes: Uint8Array, offset: number): string {
|
||||
return String.fromCharCode(...bytes.subarray(offset, offset + 4));
|
||||
}
|
||||
|
||||
export function retinaWidth(bytes: Uint8Array): number | undefined {
|
||||
if (
|
||||
bytes.length < 24 ||
|
||||
!pngSignature.every((byte, i) => bytes[i] === byte) ||
|
||||
chunkType(bytes, 12) !== "IHDR"
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
||||
const width = view.getUint32(16);
|
||||
|
||||
let offset = 8;
|
||||
while (offset + 8 <= bytes.length) {
|
||||
const length = view.getUint32(offset);
|
||||
const type = chunkType(bytes, offset + 4);
|
||||
if (type === "pHYs" && length === 9 && offset + 17 <= bytes.length) {
|
||||
const x = view.getUint32(offset + 8);
|
||||
const y = view.getUint32(offset + 12);
|
||||
const metre = bytes[offset + 16] === 1;
|
||||
if (!metre || x !== y) return undefined;
|
||||
const scale = Math.round((x * 0.0254) / 72);
|
||||
return scale === 2 || scale === 3 ? Math.round(width / scale) : undefined;
|
||||
}
|
||||
if (type === "IDAT" || type === "IEND") return undefined;
|
||||
offset += 12 + length;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user