Spaces:
Paused
Paused
| import express from 'express'; | |
| import { createCanvas, loadImage } from 'canvas'; | |
| const app = express(); | |
| const port = 3000; | |
| app.use(express.json()); | |
| app.use(express.urlencoded({ extended: true })); | |
| /** | |
| * Fungsi untuk menghasilkan gambar status kustom | |
| * @param {string} profileImage - URL gambar profil | |
| * @param {string} mainImage - URL gambar utama | |
| * @param {string} caption - Teks caption | |
| * @param {number} views - Jumlah tayangan | |
| * @returns {Promise<Buffer>} - Buffer gambar dalam format PNG | |
| */ | |
| async function createCustomSWGenerator({ profileImage, mainImage, caption = "Custom Caption", views = 4 }) { | |
| const canvasWidth = 1080; | |
| const canvasHeight = 1920; | |
| const canvas = createCanvas(canvasWidth, canvasHeight); | |
| const ctx = canvas.getContext("2d"); | |
| // Background hitam | |
| ctx.fillStyle = "#000000"; | |
| ctx.fillRect(0, 0, canvasWidth, canvasHeight); | |
| // Tambahkan gambar utama | |
| if (mainImage) { | |
| try { | |
| const mainImg = await loadImage(mainImage); | |
| ctx.drawImage(mainImg, 0, 200, canvasWidth, 1080); | |
| } catch (error) { | |
| console.error("Gagal memuat gambar utama:", error.message); | |
| } | |
| } | |
| // Header background | |
| ctx.fillStyle = "rgba(0, 0, 0, 0.7)"; | |
| ctx.fillRect(0, 0, canvasWidth, 180); | |
| // Gambar profil dengan border putih | |
| if (profileImage) { | |
| try { | |
| const profileImg = await loadImage(profileImage); | |
| ctx.save(); | |
| ctx.beginPath(); | |
| ctx.arc(90, 90, 60, 0, Math.PI * 2); | |
| ctx.closePath(); | |
| ctx.clip(); | |
| // Gambar profil | |
| ctx.drawImage(profileImg, 30, 30, 120, 120); | |
| // Garis putih di luar profil | |
| ctx.beginPath(); | |
| ctx.arc(90, 90, 62, 0, Math.PI * 2); // Radius sedikit lebih besar | |
| ctx.strokeStyle = "white"; | |
| ctx.lineWidth = 10; // Stroke putih tipis | |
| ctx.stroke(); | |
| ctx.closePath(); | |
| ctx.restore(); | |
| } catch (error) { | |
| console.error("Gagal memuat gambar profil:", error.message); | |
| } | |
| } | |
| // Teks header | |
| ctx.fillStyle = "#FFFFFF"; | |
| ctx.font = "50px 'Roboto Sans', Arial"; // Gunakan Roboto Sans jika tersedia | |
| ctx.fillText("Status saya", 180, 80); | |
| ctx.fillStyle = "#CCCCCC"; | |
| ctx.font = "30px 'Roboto Sans', Arial"; // Gunakan Roboto Sans | |
| ctx.fillText("1 menit yang lalu", 180, 130); | |
| // Caption teks | |
| ctx.fillStyle = "#FFFFFF"; | |
| ctx.font = "40px 'Roboto Sans', Arial"; | |
| ctx.textAlign = "center"; | |
| ctx.fillText(caption, canvasWidth / 2, 1400); | |
| // Footer background | |
| ctx.fillStyle = "rgba(0, 0, 0, 0.7)"; | |
| ctx.fillRect(0, 1620, canvasWidth, 300); | |
| // Ikon dan teks footer | |
| try { | |
| const viewIcon = await loadImage('https://example.com/eye.png'); // Ganti dengan URL ikon tayangan | |
| const shareIcon = await loadImage('https://example.com/share.png'); // Ganti dengan URL ikon bagikan | |
| const promoteIcon = await loadImage('https://example.com/promotion.png'); // Ganti dengan URL ikon promosikan | |
| // "Tayangan" | |
| ctx.drawImage(viewIcon, 80, 1660, 70, 70); // Ikon tayangan | |
| ctx.fillStyle = "#FFFFFF"; | |
| ctx.font = "30px 'Roboto Sans', Arial"; | |
| ctx.textAlign = "center"; | |
| ctx.fillText(`${views} Tayangan`, 170, 1780); | |
| // "Promosikan" | |
| ctx.drawImage(promoteIcon, 460, 1660, 70, 70); // Ikon promosikan | |
| ctx.fillText("Promosikan", 550, 1780); | |
| // "Bagikan" | |
| ctx.drawImage(shareIcon, 840, 1660, 70, 70); // Ikon bagikan | |
| ctx.fillText("Bagikan", 920, 1780); | |
| } catch (error) { | |
| console.error("Gagal memuat ikon:", error.message); | |
| } | |
| // Kembalikan gambar sebagai Buffer PNG | |
| return canvas.toBuffer('image/png'); | |
| } | |
| /** | |
| * Endpoint untuk membuat gambar status | |
| * @route POST /generate-status | |
| * @param {string} profileImage - URL gambar profil | |
| * @param {string} mainImage - URL gambar utama | |
| * @param {string} caption - Teks caption | |
| * @param {number} views - Jumlah tayangan | |
| * @returns {Buffer} - Gambar dalam format PNG | |
| */ | |
| app.post('/generate-status', async (req, res) => { | |
| const { profileImage, mainImage, caption, views } = req.body; | |
| if (!profileImage || !mainImage) { | |
| return res.status(400).json({ error: "Gambar profil dan gambar utama harus disediakan." }); | |
| } | |
| try { | |
| const imageBuffer = await createCustomSWGenerator({ profileImage, mainImage, caption, views }); | |
| res.setHeader('Content-Type', 'image/png'); | |
| res.send(imageBuffer); | |
| } catch (error) { | |
| console.error(error); | |
| res.status(500).json({ error: "Gagal membuat gambar." }); | |
| } | |
| }); | |
| // Mulai server Express | |
| app.listen(port, () => { | |
| console.log(`Server berjalan di http://localhost:${port}`); | |
| }); | |