Public
Edited
Aug 17, 2024
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
resized = {
const ab = await emoji.arrayBuffer()
const original = new Uint8Array(ab);
if (!emoji.mimeType || emoji.name.endsWith('.lottie'))
return {
blob: new Blob([original], { encoding: "application/lottie+zip" }),
original,
bytes: original,
type: "lottie"
};
const {bytes, frames} = await resizePngToUintArray(ab, 128);
const blob = new Blob([bytes], {encoding: 'image/png'});
return {blob, bytes, original, type: 'png'};
}
Insert cell
async function resizePngToUintArray(arrayBuffer, size) {
const img = UPNG.decode(arrayBuffer);
const rgba = UPNG.toRGBA8(img);
const resized = await Promise.all(
rgba.map(async (buf) => {
const imageData = new ImageData(
new Uint8ClampedArray(buf),
img.width,
img.height
);
const bitmap = await createImageBitmap(imageData, {
resizeWidth: size,
resizeHeight: size,
// resizeQuality: 'high', // this makes everything look worse for some reason
});

const ctx = DOM.context2d(size, size, 1);
ctx.drawImage(bitmap, 0, 0);
const { buffer } = ctx.getImageData(0, 0, size, size).data;
return buffer;
})
);

const apng = UPNG.encode(
resized,
size,
size,
img.depth,
img.frames.map((f) => f.delay)
);
return {bytes: new Uint8Array(apng), frames: img.frames.length};
}
Insert cell
agent = {
const agent = new AtpAgent({ service });

if (username && password) {
try {
await agent.login({ identifier: username, password });
} catch (e) {
console.error(e);
}
}

return agent;
}
Insert cell
result = {
submit;
if (agent && emoji && alttext && emojiName) {
const formats = { $type: "blue.moji.collection.item#formats_v0" };

switch (resized.type) {
case "png": {
const { data: originalBlob } = await agent.uploadBlob(
resized.original,
{
encoding: "image/png"
}
);

formats.original = originalBlob;

// Add bytes APNG version if smaller than 65kb (SUBJECT TO CHANGE)
if (resized.bytes.byteLength < 65536 && resized.frames > 1) {
formats.apng_128 = resized.bytes;
} else {
const { data: blobAsset } = await agent.com.atproto.repo.uploadBlob(
resized.bytes,
{ encoding: "image/png" }
);
formats.png_128 = blobAsset.blob;
}
}
case "lottie": {
formats.lottie = resized.bytes;
}
}


return agent.com.atproto.repo.putRecord({
validate: false,
repo: agent.session.did,
collection: "blue.moji.collection.item",
rkey: emojiName.replace(/:/g, ""), // strip colons
record: {
name: `:${emojiName.replace(/:/g, "")}:`, // ensure colons are on the name
alt: alttext,
createdAt: new Date().toISOString(),
formats,
}
});
} else {
return false;
}
}

Insert cell
user_did = agent?.session?.did
Insert cell
AtpAgent = {
const { BskyAgent } = await import("https://esm.sh/@atproto/api@latest");
return BskyAgent;
}
Insert cell
UPNG = {
const upng = await import('https://esm.sh/upng-js');
return upng.default;
}
Insert cell
BluemojiRichText = (await import('https://esm.sh/@aendra/bluemoji@3.0.21')).BluemojiRichText
Insert cell
lottie = import('https://esm.sh/@lottiefiles/dotlottie-web@latest');
Insert cell
bluemoji = import('https://esm.sh/@aendra/bluemoji@3.0.21/render')
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more