Skip to content

Commit

Permalink
Merge pull request #1799 from googlefonts/paste-bg-image-issue1798
Browse files Browse the repository at this point in the history
[background image] Paste background image from PNG or JPEG clipboard
  • Loading branch information
justvanrossum authored Nov 16, 2024
2 parents b246b30 + 91e46e8 commit bc41354
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 4 deletions.
4 changes: 2 additions & 2 deletions src/fontra/client/core/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -279,12 +279,12 @@ export async function readClipboardTypes() {
return clipboardTypes;
}

export async function readFromClipboard(type) {
export async function readFromClipboard(type, plainText = true) {
const clipboardContents = await navigator.clipboard.read();
for (const item of clipboardContents) {
if (item.types.includes(type)) {
const blob = await item.getType(type);
return await blob.text();
return plainText ? await blob.text() : blob;
}
}
return undefined;
Expand Down
57 changes: 55 additions & 2 deletions src/fontra/views/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -2017,6 +2017,7 @@ export class EditorController {
let { pasteVarGlyph, pasteLayerGlyphs, backgroundImageData } =
await this._unpackClipboard();
if (!pasteVarGlyph && !pasteLayerGlyphs?.length) {
await this._pasteClipboardImage();
return;
}

Expand Down Expand Up @@ -2106,7 +2107,7 @@ export class EditorController {

_makeBackgroundImageIdentifierMapping(backgroundImageData) {
if (!backgroundImageData || isObjectEmpty(backgroundImageData)) {
return null;
return {};
}
const mapping = {};
for (const originalImageIdentifier of Object.keys(backgroundImageData)) {
Expand All @@ -2127,6 +2128,9 @@ export class EditorController {
}

async _writeBackgroundImageData(backgroundImageData, identifierMapping) {
if (!backgroundImageData) {
return;
}
for (const [imageIdentifier, imageData] of Object.entries(backgroundImageData)) {
const mappedIdentifier = identifierMapping[imageIdentifier] || imageIdentifier;
await this.fontController.putBackgroundImageData(mappedIdentifier, imageData);
Expand Down Expand Up @@ -2178,11 +2182,60 @@ export class EditorController {
console.log("couldn't paste from JSON:", error.toString());
}
} else {
pasteLayerGlyphs = [{ glyph: await this.parseClipboard(plainText) }];
const glyph = await this.parseClipboard(plainText);
if (glyph) {
pasteLayerGlyphs = [{ glyph }];
}
}
return { pasteVarGlyph, pasteLayerGlyphs, backgroundImageData };
}

async _pasteClipboardImage() {
if (!this.sceneSettings.selectedGlyph?.isEditing) {
return;
}

const imageBlob =
(await readFromClipboard("image/png", false)) ||
(await readFromClipboard("image/jpeg", false));

if (!imageBlob) {
return;
}

const reader = new FileReader();
const resultPromise = new Promise((resolve, reject) => {
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
});

reader.readAsDataURL(imageBlob);

const dataURL = await resultPromise;
if (!dataURL) {
return;
}

const imageIdentifiers = [];

await this.sceneController.editLayersAndRecordChanges((layerGlyphs) => {
for (const layerGlyph of Object.values(layerGlyphs)) {
const imageIdentifier = crypto.randomUUID();
layerGlyph.backgroundImage = {
identifier: imageIdentifier,
transformation: getDecomposedIdentity(),
};
imageIdentifiers.push(imageIdentifier);
}
this.sceneController.selection = new Set(["backgroundImage/0"]);
return "paste background image"; // TODO: translate
});

for (const imageIdentifier of imageIdentifiers) {
await this.fontController.putBackgroundImageData(imageIdentifier, dataURL);
}
}

async _pasteReplaceGlyph(varGlyph) {
await this.sceneController.editGlyphAndRecordChanges(
(glyph) => {
Expand Down

0 comments on commit bc41354

Please sign in to comment.