Skip to content

Commit

Permalink
Merge #273 from superbrotherx4
Browse files Browse the repository at this point in the history
 /compare supports animations now wooooooo
  • Loading branch information
3vorp authored Nov 23, 2023
2 parents 435ce6d + 4dc9810 commit 6d9029f
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 11 deletions.
4 changes: 2 additions & 2 deletions src/helpers/functions/getTexture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
Contributor,
GalleryTexture,
} from "@interfaces/firestorm";
import { animateToAttachment } from "@images/animate";
import { MCMETA, animateToAttachment } from "@images/animate";
import minecraftSorter from "@utility/minecraftSorter";
import formatName from "@utility/formatName";
import { textureButtons } from "@utility/buttons";
Expand All @@ -30,7 +30,7 @@ export async function getTexture(interaction: Interaction, texture: Texture, pac
const contributionJSON: Contributor[] = (await axios.get(`${tokens.apiUrl}contributions/authors`))
.data;

let mcmeta: any = {};
let mcmeta: MCMETA;
if (isAnimated) {
const animatedPath = paths.filter((p) => p.mcmeta === true)[0];
const raw = (await axios.get(`${tokens.apiUrl}settings/repositories.raw`)).data;
Expand Down
90 changes: 83 additions & 7 deletions src/helpers/functions/textureComparison.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import stitch from "@images/stitch";
import { magnifyToAttachment } from "@images/magnify";
import { Image, loadImage } from "@napi-rs/canvas";
import { magnify, magnifyToAttachment } from "@images/magnify";
import { Image, loadImage, createCanvas, Canvas } from "@napi-rs/canvas";
import { Client, EmbedBuilder } from "@client";
import { addPathsToEmbed } from "@functions/getTexture";
import { AnyPack, GalleryTexture } from "@interfaces/firestorm";
import axios from "axios";
import { ActionRowBuilder, ButtonBuilder } from "discord.js";
import { ActionRowBuilder, AttachmentBuilder, ButtonBuilder } from "discord.js";
import { template } from "@utility/buttons";
import { animateToAttachment, MCMETA } from "@helpers/images/animate";

/**
* Get the corresponding pack IDs for a given display choice
Expand Down Expand Up @@ -34,6 +35,47 @@ export function parseDisplay(display: string) {
}
}

/**
* Slices tilesheets into individual frames and calculates the number of frames
* @author Superboxer47
* @param loadedImages Array of loaded images
* @param dimension Base image for dimensions
* @param mcmeta mcmeta for the texture, used for the dimensions of a single frame
* @returns 3D array with all of the frames and the number of frames
*/
export function sliceTileSheet(loadedImages: Image[][], dimension: Image, mcmeta: MCMETA) {
const frameCount: number = !mcmeta.animation?.height
? dimension.height / dimension.width
: dimension.height / mcmeta.animation.height; // if height is not specified, assume square image
let canvasArray: Canvas[][][] = [];
for (const images of loadedImages) {
canvasArray.push([]);
for (const image of images) {
canvasArray.at(-1).push([]);
let individualHeight = image.height / frameCount; // height of each frame adjusted for resolution
for (let i = 0; i < frameCount; ++i) {
const canvas = createCanvas(image.width, individualHeight); // canvas for each frame adjusted for resolution
const ctx = canvas.getContext("2d");
ctx.imageSmoothingEnabled = false;

ctx.drawImage(
image, // image
0,
individualHeight * i, // sx, sy
image.width,
individualHeight, // sWidth, sHeight
0,
0, // dx, dy
image.width,
individualHeight, // dWidth, dHeight
);
canvasArray.at(-1).at(-1).push(canvas); // putting the new frame into the array
}
}
}
return { canvasArray, frameCount }; // returns the 3D array with all of the frames and the number of frames
}

/**
* Generate a texture comparison by ID
* @author Evorp
Expand All @@ -50,6 +92,10 @@ export default async function textureComparison(
await axios.get(`${client.tokens.apiUrl}gallery/modal/${id}/latest`)
).data;

const isAnimated = result.paths.filter((p) => p.mcmeta === true).length !== 0;
const mcmeta: MCMETA = result.mcmeta ?? ({} as MCMETA);
const displayMCMETA: MCMETA = structuredClone(mcmeta);

const displayed = parseDisplay(display);
const defaultURL = result.urls.default;

Expand All @@ -72,19 +118,49 @@ export default async function textureComparison(
}
}

const stitched = await stitch(loadedImages);
const magnified = await magnifyToAttachment(stitched);
let attachment;
if (isAnimated) {
const { canvasArray, frameCount } = sliceTileSheet(loadedImages, dimension, mcmeta);
const stitchedFrames: Image[][] = [];
for (let i = 0; i < frameCount; ++i) {
// This is to orient the frames vertically so they stitch properly
stitchedFrames.push([]);
stitchedFrames
.at(-1)
.push(await loadImage(await stitch(canvasArray.map((imageSet) => imageSet.map((image) => image[i]))))); // image[i] is the frame of the image
}
const firstTileSheet = await stitch(stitchedFrames, 0);
const { magnified, factor, height, width } = await magnify(firstTileSheet, {
isAnimation: true,
});
if (!mcmeta.animation) mcmeta.animation = {};
mcmeta.animation.height = !mcmeta.animation?.height
? height / frameCount
: mcmeta.animation.height * factor; // These scale the mcmeta info for the new resolution
mcmeta.animation.width = !mcmeta.animation?.width ? width : mcmeta.animation.width * factor;
attachment = await animateToAttachment(magnified, mcmeta);
}
else {
const stitched = await stitch(loadedImages);
attachment = await magnifyToAttachment(stitched);
}

const embed = new EmbedBuilder()
.setImage("attachment://magnified.png")
.setImage(`attachment://${isAnimated ? "animated.gif" : "magnified.png"}`)
.setTitle(`[#${result.texture.id}] ${result.texture.name}`)
.setURL(`https://webapp.faithfulpack.net/#/gallery/java/32x/latest/all/?show=${id}`)
.addFields(addPathsToEmbed(result))
.setFooter({ text: `Displaying: ${display ?? "All"}` });

if (Object.keys(displayMCMETA?.animation ?? {}).length)
embed.addFields({
name: "MCMETA",
value: `\`\`\`json\n${JSON.stringify(displayMCMETA.animation)}\`\`\``,
});

return {
embeds: [embed],
files: [magnified],
files: [attachment],
components: [new ActionRowBuilder<ButtonBuilder>().addComponents(template)],
};
}
3 changes: 1 addition & 2 deletions src/helpers/images/magnify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ export async function magnify(origin: ImageSource, options: MagnifyOptions = {})
const input = await loadImage(origin);

// ignore height if tilesheet, otherwise it's not scaled as much
const surface = options.isAnimation ? input.width * 16 : input.width * input.height;

const surface = options.isAnimation ? input.width ** 2 : input.width * input.height;
// no custom factor provided
let factor = 64;
if (surface <= 256) factor = 32;
Expand Down
3 changes: 3 additions & 0 deletions src/interfaces/firestorm.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { MCMETA } from "@helpers/images/animate";

export type MinecraftEdition = "java" | "bedrock";

export type FaithfulPack =
Expand Down Expand Up @@ -52,6 +54,7 @@ export interface Texture extends BaseTexture {
uses: Use[];
paths: Path[];
contributions?: Contribution[];
mcmeta?: MCMETA;
}

// used for comparison loader
Expand Down

0 comments on commit 6d9029f

Please sign in to comment.