File size: 3,844 Bytes
213c234
 
 
 
 
 
 
 
 
 
 
 
34f0868
f444918
34f0868
f444918
 
213c234
34f0868
 
213c234
f444918
c6f0353
f444918
 
34f0868
c6f0353
 
213c234
c6f0353
f444918
34f0868
213c234
 
c6f0353
213c234
 
f444918
213c234
f444918
 
 
34f0868
213c234
34f0868
f444918
 
 
213c234
 
 
f444918
34f0868
 
f444918
 
 
 
 
 
213c234
c6f0353
213c234
f444918
c6f0353
f444918
213c234
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import type { PicletInstance } from '$lib/db/schema';
import { embedPicletMetadata } from './picletMetadata';

/**
 * Generates a shareable image of a piclet with embedded metadata
 */
export async function generateShareableImage(piclet: PicletInstance): Promise<Blob> {
  // Create canvas
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  if (!ctx) throw new Error('Could not create canvas context');
  
  // Set canvas size - narrower width to match content, tighter height
  const canvasWidth = 700;
  const canvasHeight = 700; // Square format, tighter
  canvas.width = canvasWidth;
  canvas.height = canvasHeight;
  
  // Clear canvas for transparency (no background fill)
  ctx.clearRect(0, 0, canvasWidth, canvasHeight);
  
  // Load piclet image first
  const picletImg = await loadImage(piclet.imageData || piclet.imageUrl);
  const picletSize = 512;
  const picletX = (canvasWidth - picletSize) / 2;
  const picletY = 120; // Position piclet closer to top, leaving room for name
  
  // Load and draw grass platform positioned under the piclet
  const grassImg = await loadImage('/assets/grass.PNG');
  const platformSize = picletSize + 100; // Slightly larger than piclet
  const platformX = (canvasWidth - platformSize) / 2;
  const platformY = picletY + picletSize - 200; // Platform overlaps bottom of piclet
  ctx.drawImage(grassImg, platformX, platformY, platformSize, platformSize);
  
  // Draw piclet on top of platform
  ctx.drawImage(picletImg, picletX, picletY, picletSize, picletSize);
  
  // Add piclet name with video game font
  ctx.fillStyle = 'white';
  ctx.strokeStyle = '#1e3a8a'; // Dark blue outline
  ctx.lineWidth = 8;
  // Try to use a more gaming-style font, fallback to Impact
  ctx.font = 'bold 64px "Press Start 2P", "Courier New", Impact, monospace';
  ctx.textAlign = 'center';
  ctx.shadowColor = 'rgba(0, 0, 0, 0.8)';
  ctx.shadowBlur = 10;
  ctx.shadowOffsetX = 4;
  ctx.shadowOffsetY = 4;
  
  const nameText = piclet.nickname || piclet.typeId;
  
  // Draw name with outline and shadow
  ctx.strokeText(nameText, canvasWidth / 2, 80);
  ctx.fillText(nameText, canvasWidth / 2, 80);
  
  // Reset shadow
  ctx.shadowColor = 'transparent';
  ctx.shadowBlur = 0;
  ctx.shadowOffsetX = 0;
  ctx.shadowOffsetY = 0;
  
  // Load and draw translucent watermark
  const logoImg = await loadImage('/assets/snap_logo.png');
  const logoSize = 120;
  ctx.globalAlpha = 0.3; // More translucent
  ctx.drawImage(logoImg, canvasWidth - logoSize - 20, canvasHeight - logoSize - 20, logoSize, logoSize);
  ctx.globalAlpha = 1.0;
  
  // Get the image as blob
  const blob = await canvasToBlob(canvas);
  
  // Embed metadata in the blob
  return embedPicletMetadata(blob, piclet);
}

/**
 * Downloads a piclet card image
 */
export async function downloadPicletCard(piclet: PicletInstance, filename?: string): Promise<void> {
  const blob = await generateShareableImage(piclet);
  const url = URL.createObjectURL(blob);
  
  const a = document.createElement('a');
  a.href = url;
  a.download = filename || `Piclet_${piclet.nickname || piclet.typeId}_Lv${piclet.level}.png`;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  
  URL.revokeObjectURL(url);
}

/**
 * Helper to load an image
 */
function loadImage(src: string): Promise<HTMLImageElement> {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.crossOrigin = 'anonymous';
    img.onload = () => resolve(img);
    img.onerror = reject;
    img.src = src;
  });
}

/**
 * Convert canvas to blob
 */
function canvasToBlob(canvas: HTMLCanvasElement): Promise<Blob> {
  return new Promise((resolve, reject) => {
    canvas.toBlob((blob) => {
      if (blob) resolve(blob);
      else reject(new Error('Failed to create blob'));
    }, 'image/png');
  });
}