3a8b110c1b
Watermark editing no longer covers the photo: the preview letterboxes the image inside its fit rect while the deck is open, and the idle hint is gone. The FRAME tab can rotate a library photo 90 degrees clockwise. Rotation swaps the pixel dimensions instead of the frame, so the polaroid/wall window keeps its aspect and every consumer (cover crop, watermark area, export) picks up the new orientation from width()/height() with no extra layout branch. The rotate surface is CPU-backed on purpose - a GPU snapshot loses its pixels before the next frame and renders the photo black. Custom watermark text can now be dragged anywhere on the photo, double-tapped to re-edit, and is only baked into the file once ACCEPT is pressed; the export engine takes the same position. It also gained COLOR/SIZE/FONT chips, with the font list read from the OS via Skia's FontMgr so any installed family can be used.
28 lines
1.4 KiB
TypeScript
28 lines
1.4 KiB
TypeScript
import { Skia, type SkImage } from '@shopify/react-native-skia';
|
|
|
|
// Turn a decoded image 90deg clockwise into a fresh SkImage. Used by the FRAME
|
|
// tab so a library photo can go landscape <-> portrait before it enters a frame:
|
|
// every consumer reads width()/height(), so the pixel-dimension swap carries the
|
|
// new orientation through the polaroid window aspect, the cover crop and the
|
|
// watermark areas without a single extra layout branch.
|
|
// ponytail: offscreen surface, same fallback as exportEngine.createSurface; a
|
|
// matrix-based draw would avoid the copy if this ever shows up in a profile.
|
|
export function rotateSkImage90(image: SkImage | null): SkImage | null {
|
|
if (!image) return null;
|
|
const w = image.width();
|
|
const h = image.height();
|
|
if (!(w > 0 && h > 0)) return null;
|
|
// CPU-backed on purpose: a GPU (MakeOffscreen) snapshot keeps its pixels in a
|
|
// context texture that is gone by the time the <Canvas> draws a frame later —
|
|
// the preview then renders the photo completely black. Raster pixels survive
|
|
// the trip to the render thread.
|
|
const surface = Skia.Surface.Make(h, w);
|
|
if (!surface) return image; // keep the unrotated photo on allocation failure
|
|
const canvas = surface.getCanvas();
|
|
canvas.clear(Skia.Color('transparent'));
|
|
canvas.translate(h, 0);
|
|
canvas.rotate(90, 0, 0);
|
|
canvas.drawImage(image, 0, 0);
|
|
return surface.makeImageSnapshot() ?? image;
|
|
}
|