feat: monochrome Noto Emoji subset icons (pin, camera) before watermark lines
This commit is contained in:
Binary file not shown.
@@ -93,6 +93,12 @@ export default function Viewfinder({
|
||||
require('../../assets/CourierPrime-Regular.ttf'),
|
||||
Math.round(vw * 0.032)
|
||||
);
|
||||
// Monochrome Noto Emoji subset (📍 U+1F4CD, 📷 U+1F4F7) for the watermark
|
||||
// icons — glyphs painted with the same color as the text next to them.
|
||||
const iconFont = useFont(
|
||||
require('../../assets/NotoEmoji-GPS.ttf'),
|
||||
Math.round(vw * 0.032)
|
||||
);
|
||||
|
||||
const adjustments = recipe.adjustments;
|
||||
// Camera captures apply exposure compensation as a hardware AE bias (see the
|
||||
@@ -478,7 +484,7 @@ export default function Viewfinder({
|
||||
};
|
||||
|
||||
const renderGPSWatermark = () => {
|
||||
if (!useGeotag || !gpsInfo || !customFont) return null;
|
||||
if (!useGeotag || !gpsInfo || !customFont || !iconFont) return null;
|
||||
|
||||
const locationName = gpsInfo.locality || 'STREET VIEW';
|
||||
const d = new Date(gpsInfo.timestamp);
|
||||
@@ -489,11 +495,17 @@ export default function Viewfinder({
|
||||
// readable; polaroid frames push it further up onto the white area edge.
|
||||
const yOffset = vh - (selectedFrame === 'polaroid' ? vh * 0.18 + 24 : 150);
|
||||
const xOffset = selectedFrame === 'polaroid' ? vw * 0.08 : 16;
|
||||
const gap = (rect: { width?: number } | null) =>
|
||||
Math.round((rect?.width ?? Math.round(vw * 0.032)) + vw * 0.012);
|
||||
const pinW = iconFont.measureText('📍');
|
||||
const camW = iconFont.measureText('📷');
|
||||
|
||||
return (
|
||||
<Group>
|
||||
<SkiaText x={xOffset} y={yOffset - 16} text={`📍 ${locationName}`} font={customFont} color="#f59e0b" />
|
||||
<SkiaText x={xOffset} y={yOffset} text={timestampStr} font={customFont} color="#f59e0b" />
|
||||
<SkiaText x={xOffset} y={yOffset - 16} text="📍" font={iconFont} color="#f59e0b" />
|
||||
<SkiaText x={xOffset + gap(pinW)} y={yOffset - 16} text={locationName} font={customFont} color="#f59e0b" />
|
||||
<SkiaText x={xOffset} y={yOffset} text="📷" font={iconFont} color="#f59e0b" />
|
||||
<SkiaText x={xOffset + gap(camW)} y={yOffset} text={timestampStr} font={customFont} color="#f59e0b" />
|
||||
</Group>
|
||||
);
|
||||
};
|
||||
|
||||
+14
-10
@@ -236,18 +236,19 @@ export async function processAndExportPhoto(
|
||||
// 8. Render GPS Geotag Watermark
|
||||
if (useGeotag && gpsInfo) {
|
||||
const fontAsset = Asset.fromModule(require('../../assets/CourierPrime-Regular.ttf'));
|
||||
if (!fontAsset.localUri) {
|
||||
await fontAsset.downloadAsync();
|
||||
}
|
||||
|
||||
const fontData = await FileSystem.readAsStringAsync(fontAsset.localUri!, {
|
||||
encoding: FileSystem.EncodingType.Base64,
|
||||
});
|
||||
const iconFontAsset = Asset.fromModule(require('../../assets/NotoEmoji-GPS.ttf'));
|
||||
await Promise.all([fontAsset.downloadAsync(), iconFontAsset.downloadAsync()]);
|
||||
const [fontData, iconFontData] = await Promise.all([
|
||||
FileSystem.readAsStringAsync(fontAsset.localUri!, { encoding: FileSystem.EncodingType.Base64 }),
|
||||
FileSystem.readAsStringAsync(iconFontAsset.localUri!, { encoding: FileSystem.EncodingType.Base64 }),
|
||||
]);
|
||||
const typeface = Skia.Typeface.MakeFreeTypeFaceFromData(Skia.Data.fromBase64(fontData));
|
||||
const iconTypeface = Skia.Typeface.MakeFreeTypeFaceFromData(Skia.Data.fromBase64(iconFontData));
|
||||
|
||||
if (typeface) {
|
||||
if (typeface && iconTypeface) {
|
||||
const fontSize = Math.round(width * 0.032); // 3.2% of image width
|
||||
const font = Skia.Font(typeface, fontSize);
|
||||
const iconFont = Skia.Font(iconTypeface, fontSize);
|
||||
const textPaint = Skia.Paint();
|
||||
textPaint.setColor(Skia.Color('#f59e0b')); // Amber 500
|
||||
|
||||
@@ -258,9 +259,12 @@ export async function processAndExportPhoto(
|
||||
|
||||
const yOffset = height - (frameId === 'polaroid' ? height * 0.15 : fontSize * 1.5);
|
||||
const xOffset = frameId === 'polaroid' ? width * 0.08 : fontSize * 1.2;
|
||||
const gap = Math.round(fontSize * 1.2); // icon box (~1em) + spacing
|
||||
|
||||
canvas.drawText(`📍 ${locationName}`, xOffset, yOffset - fontSize * 1.4, textPaint, font);
|
||||
canvas.drawText(timestampStr, xOffset, yOffset, textPaint, font);
|
||||
canvas.drawText('📍', xOffset, yOffset - fontSize * 1.4, textPaint, iconFont);
|
||||
canvas.drawText(locationName, xOffset + gap, yOffset - fontSize * 1.4, textPaint, font);
|
||||
canvas.drawText('📷', xOffset, yOffset, textPaint, iconFont);
|
||||
canvas.drawText(timestampStr, xOffset + gap, yOffset, textPaint, font);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user