diff --git a/next.config.ts b/next.config.ts index 121c3a3..8e76b72 100644 --- a/next.config.ts +++ b/next.config.ts @@ -15,7 +15,7 @@ const nextConfig: NextConfig = { pathname: "/tutorial/**", }, { - pathname: "/guest.webp", + pathname: "/guest.png", }, ], remotePatterns: [ diff --git a/public/guest.png b/public/guest.png new file mode 100644 index 0000000..f6c82fe Binary files /dev/null and b/public/guest.png differ diff --git a/public/guest.webp b/public/guest.webp deleted file mode 100644 index ce37848..0000000 Binary files a/public/guest.webp and /dev/null differ diff --git a/src/app/api/auth/picture/route.ts b/src/app/api/auth/picture/route.ts index 8688d2a..813f7f8 100644 --- a/src/app/api/auth/picture/route.ts +++ b/src/app/api/auth/picture/route.ts @@ -49,7 +49,7 @@ export async function PATCH(request: NextRequest) { if (!image) { await prisma.user.update({ where: { id: Number(session.user.id) }, - data: { image: `/guest.webp`, imageUpdatedAt: new Date() }, + data: { image: `/guest.png`, imageUpdatedAt: new Date() }, }); return rateLimit.sendResponse({ success: true }); @@ -64,10 +64,10 @@ export async function PATCH(request: NextRequest) { try { const buffer = Buffer.from(await image.arrayBuffer()); - const webpBuffer = await sharp(buffer, { animated: true }).resize({ width: 128, height: 128 }).webp({ quality: 85 }).toBuffer(); - const fileLocation = path.join(uploadsDirectory, `${session.user.id}.webp`); + const pngBuffer = await sharp(buffer, { animated: true }).resize({ width: 128, height: 128 }).png({ quality: 85 }).toBuffer(); + const fileLocation = path.join(uploadsDirectory, `${session.user.id}.png`); - await fs.writeFile(fileLocation, webpBuffer); + await fs.writeFile(fileLocation, pngBuffer); } catch (error) { console.error("Error uploading profile picture:", error); Sentry.captureException(error, { extra: { stage: "upload-profile-picture" } }); diff --git a/src/app/api/mii/[id]/edit/route.ts b/src/app/api/mii/[id]/edit/route.ts index 85b40ac..29a35f1 100644 --- a/src/app/api/mii/[id]/edit/route.ts +++ b/src/app/api/mii/[id]/edit/route.ts @@ -126,10 +126,10 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise< await Promise.all( images.map(async (image, index) => { const buffer = Buffer.from(await image.arrayBuffer()); - const webpBuffer = await sharp(buffer).webp({ quality: 85 }).toBuffer(); - const fileLocation = path.join(miiUploadsDirectory, `image${index}.webp`); + const pngBuffer = await sharp(buffer).png({ quality: 85 }).toBuffer(); + const fileLocation = path.join(miiUploadsDirectory, `image${index}.png`); - await fs.writeFile(fileLocation, webpBuffer); + await fs.writeFile(fileLocation, pngBuffer); }), ); } catch (error) { diff --git a/src/app/api/submit/route.ts b/src/app/api/submit/route.ts index 824d51f..11cd0fa 100644 --- a/src/app/api/submit/route.ts +++ b/src/app/api/submit/route.ts @@ -148,10 +148,10 @@ export async function POST(request: NextRequest) { try { // Compress and store - const studioWebpBuffer = await sharp(studioBuffer).webp({ quality: 85 }).toBuffer(); - const studioFileLocation = path.join(miiUploadsDirectory, "mii.webp"); + const studioPngBuffer = await sharp(studioBuffer).png({ quality: 85 }).toBuffer(); + const studioFileLocation = path.join(miiUploadsDirectory, "mii.png"); - await fs.writeFile(studioFileLocation, studioWebpBuffer); + await fs.writeFile(studioFileLocation, studioPngBuffer); // Generate a new QR code for aesthetic reasons const byteString = String.fromCharCode(...qrBytes); @@ -165,10 +165,10 @@ export async function POST(request: NextRequest) { const codeBuffer = Buffer.from(codeBase64, "base64"); // Compress and store - const codeWebpBuffer = await sharp(codeBuffer).webp({ quality: 85 }).toBuffer(); - const codeFileLocation = path.join(miiUploadsDirectory, "qr-code.webp"); + const codePngBuffer = await sharp(codeBuffer).png({ quality: 85 }).toBuffer(); + const codeFileLocation = path.join(miiUploadsDirectory, "qr-code.png"); - await fs.writeFile(codeFileLocation, codeWebpBuffer); + await fs.writeFile(codeFileLocation, codePngBuffer); await generateMetadataImage(miiRecord, session.user.name!); } catch (error) { // Clean up if something went wrong @@ -184,10 +184,10 @@ export async function POST(request: NextRequest) { await Promise.all( images.map(async (image, index) => { const buffer = Buffer.from(await image.arrayBuffer()); - const webpBuffer = await sharp(buffer).webp({ quality: 85 }).toBuffer(); - const fileLocation = path.join(miiUploadsDirectory, `image${index}.webp`); + const pngBuffer = await sharp(buffer).png({ quality: 85 }).toBuffer(); + const fileLocation = path.join(miiUploadsDirectory, `image${index}.png`); - await fs.writeFile(fileLocation, webpBuffer); + await fs.writeFile(fileLocation, pngBuffer); }), ); diff --git a/src/app/mii/[id]/image/route.ts b/src/app/mii/[id]/image/route.ts index 50e23df..d6d553d 100644 --- a/src/app/mii/[id]/image/route.ts +++ b/src/app/mii/[id]/image/route.ts @@ -32,8 +32,7 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{ if (!searchParamsParsed.success) return rateLimit.sendResponse({ error: searchParamsParsed.error.issues[0].message }, 400); const { type: imageType } = searchParamsParsed.data; - const fileExtension = imageType === "metadata" ? ".png" : ".webp"; - const filePath = path.join(process.cwd(), "uploads", "mii", miiId.toString(), `${imageType}${fileExtension}`); + const filePath = path.join(process.cwd(), "uploads", "mii", miiId.toString(), `${imageType}.png`); let buffer: Buffer | undefined; // Only find Mii if image type is 'metadata' @@ -109,7 +108,7 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{ } return rateLimit.sendResponse(buffer, 200, { - "Content-Type": "image/webp", + "Content-Type": "image/png", "X-Robots-Tag": "noindex, noimageindex, nofollow", "Cache-Control": "no-store", }); diff --git a/src/app/profile/[id]/page.tsx b/src/app/profile/[id]/page.tsx index 422d218..4140c3a 100644 --- a/src/app/profile/[id]/page.tsx +++ b/src/app/profile/[id]/page.tsx @@ -47,7 +47,7 @@ export async function generateMetadata({ params }: Props): Promise { type: "profile", title: `${user.name} (@${user.username}) - TomodachiShare`, description: `View ${user.name}'s profile on TomodachiShare. Creator of ${user._count.miis} Miis. Member since ${joinDate}.`, - images: [user.image ?? "/guest.webp"], + images: [user.image ?? "/guest.png"], username: user.username, firstName: user.name, }, @@ -55,7 +55,7 @@ export async function generateMetadata({ params }: Props): Promise { card: "summary", title: `${user.name} (@${user.username}) - TomodachiShare`, description: `View ${user.name}'s profile on TomodachiShare. Creator of ${user._count.miis} Miis. Member since ${joinDate}.`, - images: [user.image ?? "/guest.webp"], + images: [user.image ?? "/guest.png"], creator: user.username!, }, alternates: { diff --git a/src/app/profile/[id]/picture/route.ts b/src/app/profile/[id]/picture/route.ts index a050da7..352f887 100644 --- a/src/app/profile/[id]/picture/route.ts +++ b/src/app/profile/[id]/picture/route.ts @@ -16,7 +16,7 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{ if (!parsed.success) return rateLimit.sendResponse({ error: parsed.error.issues[0].message }, 400); const userId = parsed.data; - const filePath = path.join(process.cwd(), "uploads", "user", `${userId}.webp`); + const filePath = path.join(process.cwd(), "uploads", "user", `${userId}.png`); try { const buffer = await fs.readFile(filePath); diff --git a/src/components/description.tsx b/src/components/description.tsx index e37e707..deacf3f 100644 --- a/src/components/description.tsx +++ b/src/components/description.tsx @@ -63,7 +63,7 @@ export default function Description({ text, className }: Props) { href={`/profile/${id}`} className="inline-flex items-center align-bottom gap-1.5 pr-2 bg-orange-100 border border-orange-400 rounded-lg mx-1 text-orange-800 text-xs" > - + {linkedProfile.name} ); diff --git a/src/components/dropzone.tsx b/src/components/dropzone.tsx index ff4611e..6f9188f 100644 --- a/src/components/dropzone.tsx +++ b/src/components/dropzone.tsx @@ -22,7 +22,7 @@ export default function Dropzone({ onDrop, options, children }: Props) { onDrop: handleDrop, maxFiles: 3, accept: { - "image/*": [".png", ".jpg", ".jpeg", ".bmp", ".webp", ".heic"], + "image/*": [".png", ".jpg", ".jpeg", ".bmp", ".png", ".heic"], }, ...options, }); diff --git a/src/components/profile-information.tsx b/src/components/profile-information.tsx index c11454f..0de8b8d 100644 --- a/src/components/profile-information.tsx +++ b/src/components/profile-information.tsx @@ -30,7 +30,7 @@ export default async function ProfileInformation({ userId, page }: Props) {
{/* Profile picture */} - + {/* User information */}
diff --git a/src/components/profile-overview.tsx b/src/components/profile-overview.tsx index 463e3b4..f536f98 100644 --- a/src/components/profile-overview.tsx +++ b/src/components/profile-overview.tsx @@ -9,7 +9,7 @@ export default async function ProfileOverview() {
  • profile picture) { const { src, ...rest } = props; const [imgSrc, setImgSrc] = useState(src); - return {"profile setImgSrc("/guest.webp")} />; + return {"profile setImgSrc("/guest.png")} />; } diff --git a/src/components/profile-settings/profile-picture.tsx b/src/components/profile-settings/profile-picture.tsx index 58aeb9c..0eb2745 100644 --- a/src/components/profile-settings/profile-picture.tsx +++ b/src/components/profile-settings/profile-picture.tsx @@ -59,7 +59,7 @@ export default function ProfilePictureSettings() {

    new profile picture

    New profile picture:

    new profile picture
    - +

    {user.name}

    @{user.username}

    diff --git a/src/components/submit-form/edit-form.tsx b/src/components/submit-form/edit-form.tsx index f27b3f4..c20122e 100644 --- a/src/components/submit-form/edit-form.tsx +++ b/src/components/submit-form/edit-form.tsx @@ -90,7 +90,7 @@ export default function EditForm({ mii, likes }: Props) { const response = await fetch(path); const blob = await response.blob(); - return Object.assign(new File([blob], `image${index}.webp`, { type: "image/webp" }), { path }); + return Object.assign(new File([blob], `image${index}.png`, { type: "image/png" }), { path }); }), ); diff --git a/src/lib/images.tsx b/src/lib/images.tsx index 8fff17d..f7cfeed 100644 --- a/src/lib/images.tsx +++ b/src/lib/images.tsx @@ -130,16 +130,14 @@ export async function generateMetadataImage(mii: Mii, author: string): Promise<{ // Load assets concurrently const [miiImage, qrCodeImage, fonts] = await Promise.all([ - // Read and convert the .webp images to .png (because satori doesn't support it) - fs.readFile(path.join(miiUploadsDirectory, "mii.webp")).then((buffer) => + // Read and convert the images to data URI + fs.readFile(path.join(miiUploadsDirectory, "mii.png")).then((buffer) => sharp(buffer) - .png() .toBuffer() .then((pngBuffer) => `data:image/png;base64,${pngBuffer.toString("base64")}`), ), - fs.readFile(path.join(miiUploadsDirectory, "qr-code.webp")).then((buffer) => + fs.readFile(path.join(miiUploadsDirectory, "qr-code.png")).then((buffer) => sharp(buffer) - .png() .toBuffer() .then((pngBuffer) => `data:image/png;base64,${pngBuffer.toString("base64")}`), ), @@ -209,8 +207,6 @@ export async function generateMetadataImage(mii: Mii, author: string): Promise<{ // Store the file try { - // I tried using .webp here but the quality looked awful - // but it actually might be well-liked due to the hatred of .webp const fileLocation = path.join(miiUploadsDirectory, "metadata.png"); await fs.writeFile(fileLocation, buffer); } catch (error) {