feat(wm): GPS watermark color + place-name/time toggles, "commune, city" locality
This commit is contained in:
@@ -53,7 +53,7 @@ export interface ExportOptions {
|
||||
// WATERMARK tab drag + pinch on the GPS lines: 0..1 fractions of the same
|
||||
// area the custom mark uses (a framed export's canvas IS the frame) plus a
|
||||
// multiplier on the base 3.2%-of-width size. Absent = the old top-left look.
|
||||
gpsWatermark?: { x: number; y: number; size: number } | null;
|
||||
gpsWatermark?: { x: number; y: number; size: number; color?: string; showName?: boolean; showTime?: boolean } | null;
|
||||
// WALL FRAME hung the other way round (4000x3117, artwork un-rotated).
|
||||
wallframeLandscape?: boolean;
|
||||
// Library framed-window photo reposition (Viewfinder.getFrameWindowZoom):
|
||||
@@ -606,18 +606,23 @@ export async function processAndExportPhoto(
|
||||
const gpsGap = Math.round(gpsSize * 1.6); // icon box (~1em) + one clear mono space (~0.6em)
|
||||
const baseX = clamp01(gpsPos?.x ?? 0.05) * stampW;
|
||||
const baseY = clamp01(gpsPos?.y ?? 0.1) * stampH;
|
||||
const row1Y = baseY + Math.round(gpsSize * 1.1);
|
||||
const row2Y = baseY + Math.round(gpsSize * 2.3);
|
||||
// Each enabled line (place name / shot time) stacks under the
|
||||
// previous one, exactly as the viewfinder draws it.
|
||||
const lines: { icon: string; text: string }[] = [];
|
||||
if (gpsPos?.showName !== false) lines.push({ icon: '📍', text: locationName });
|
||||
if (gpsPos?.showTime !== false) lines.push({ icon: '📷', text: timestampStr });
|
||||
textPaint.setColor(Skia.Color(gpsPos?.color ?? '#f59e0b')); // user-chosen, amber by default
|
||||
|
||||
// Spin the whole two-line block around its top-left (the anchor the
|
||||
// Spin the whole block around its top-left (the anchor the
|
||||
// viewfinder uses). 0 = the historical upright look.
|
||||
const wmRot = options?.watermarkRotation ?? 0;
|
||||
stampCanvas.save();
|
||||
if (wmRot) stampCanvas.rotate(wmRot, baseX, baseY);
|
||||
stampCanvas.drawText('📍', baseX, row1Y, iconPaint, gpsIconFont);
|
||||
stampCanvas.drawText(locationName, baseX + gpsGap, row1Y, textPaint, gpsFont);
|
||||
stampCanvas.drawText('📷', baseX, row2Y, iconPaint, gpsIconFont);
|
||||
stampCanvas.drawText(timestampStr, baseX + gpsGap, row2Y, textPaint, gpsFont);
|
||||
lines.forEach((line, i) => {
|
||||
const rowY = baseY + Math.round(gpsSize * (1.1 + i * 1.2));
|
||||
stampCanvas.drawText(line.icon, baseX, rowY, iconPaint, gpsIconFont);
|
||||
stampCanvas.drawText(line.text, baseX + gpsGap, rowY, textPaint, gpsFont);
|
||||
});
|
||||
stampCanvas.restore();
|
||||
}
|
||||
|
||||
|
||||
@@ -49,12 +49,17 @@ export async function getCurrentGPS(): Promise<GPSInfo | null> {
|
||||
}
|
||||
}
|
||||
|
||||
// The one place-name picker: city first, because "the place" on a stamp means
|
||||
// the town people would name, while subregion is Android's subAdminArea — the
|
||||
// county/district, i.e. the wrong name for the same coordinates. Shared so the
|
||||
// camera stamp and a photo's stamp can never disagree.
|
||||
// The one place-name picker, shared so the camera stamp and a photo's stamp can
|
||||
// never disagree. A Vietnamese geocoder answers with the commune/ward in
|
||||
// subregion (post-2025 two-level administration: the commune is the district-
|
||||
// level name) and the province/city in region, while city and district come
|
||||
// back null, so the stamp reads "COMMUNE, CITY" instead of a bare city.
|
||||
export function localityName(address: Location.LocationGeocodedAddress): string | null {
|
||||
const name = address.city || address.subregion || address.district || address.region;
|
||||
const district = address.subregion || address.district;
|
||||
const city = address.city || address.region;
|
||||
// Same name in both slots (one field echoed twice) must not print twice.
|
||||
const parts = district && district !== city ? [district, city] : [district || city];
|
||||
const name = parts.filter(Boolean).join(', ');
|
||||
return name ? name.toUpperCase() : null;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user