Files
EMLy/app_screenshot.go
2026-02-05 22:41:02 +01:00

165 lines
4.6 KiB
Go

// Package main provides screenshot functionality for EMLy.
// This file contains methods for capturing, saving, and exporting screenshots
// of the application window.
package main
import (
"encoding/base64"
"fmt"
"os"
"path/filepath"
"strings"
"time"
"emly/backend/utils"
"github.com/wailsapp/wails/v2/pkg/runtime"
)
// =============================================================================
// Screenshot Types
// =============================================================================
// ScreenshotResult contains the captured screenshot data and metadata.
type ScreenshotResult struct {
// Data is the base64-encoded PNG image data
Data string `json:"data"`
// Width is the image width in pixels
Width int `json:"width"`
// Height is the image height in pixels
Height int `json:"height"`
// Filename is the suggested filename for saving
Filename string `json:"filename"`
}
// =============================================================================
// Screenshot Methods
// =============================================================================
// TakeScreenshot captures the current EMLy application window and returns it as base64 PNG.
// This uses Windows GDI API to capture the window contents, handling DWM composition
// for proper rendering of modern Windows applications.
//
// The method automatically detects whether the app is in main mode or viewer mode
// and captures the appropriate window.
//
// Returns:
// - *ScreenshotResult: Contains base64 PNG data, dimensions, and suggested filename
// - error: Error if window capture or encoding fails
func (a *App) TakeScreenshot() (*ScreenshotResult, error) {
// Determine window title based on current mode
windowTitle := "EMLy - EML Viewer for 3gIT"
// Check if running in viewer mode
for _, arg := range os.Args {
if strings.Contains(arg, "--view-image") {
windowTitle = "EMLy Image Viewer"
break
}
if strings.Contains(arg, "--view-pdf") {
windowTitle = "EMLy PDF Viewer"
break
}
}
// Capture the window using Windows GDI API
img, err := utils.CaptureWindowByTitle(windowTitle)
if err != nil {
return nil, fmt.Errorf("failed to capture window: %w", err)
}
// Encode to PNG and convert to base64
base64Data, err := utils.ScreenshotToBase64PNG(img)
if err != nil {
return nil, fmt.Errorf("failed to encode screenshot: %w", err)
}
// Build result with metadata
bounds := img.Bounds()
timestamp := time.Now().Format("20060102_150405")
return &ScreenshotResult{
Data: base64Data,
Width: bounds.Dx(),
Height: bounds.Dy(),
Filename: fmt.Sprintf("emly_screenshot_%s.png", timestamp),
}, nil
}
// SaveScreenshot captures and saves the screenshot to the system temp directory.
// This is a convenience method that captures and saves in one step.
//
// Returns:
// - string: The full path to the saved screenshot file
// - error: Error if capture or save fails
func (a *App) SaveScreenshot() (string, error) {
// Capture the screenshot
result, err := a.TakeScreenshot()
if err != nil {
return "", err
}
// Decode base64 data
data, err := base64.StdEncoding.DecodeString(result.Data)
if err != nil {
return "", fmt.Errorf("failed to decode screenshot data: %w", err)
}
// Save to temp directory
tempDir := os.TempDir()
filePath := filepath.Join(tempDir, result.Filename)
if err := os.WriteFile(filePath, data, 0644); err != nil {
return "", fmt.Errorf("failed to save screenshot: %w", err)
}
return filePath, nil
}
// SaveScreenshotAs captures a screenshot and opens a save dialog for the user
// to choose where to save it.
//
// Returns:
// - string: The selected save path, or empty string if cancelled
// - error: Error if capture, dialog, or save fails
func (a *App) SaveScreenshotAs() (string, error) {
// Capture the screenshot first
result, err := a.TakeScreenshot()
if err != nil {
return "", err
}
// Open save dialog with PNG filter
savePath, err := runtime.SaveFileDialog(a.ctx, runtime.SaveDialogOptions{
DefaultFilename: result.Filename,
Title: "Save Screenshot",
Filters: []runtime.FileFilter{
{
DisplayName: "PNG Images (*.png)",
Pattern: "*.png",
},
},
})
if err != nil {
return "", fmt.Errorf("failed to open save dialog: %w", err)
}
// User cancelled
if savePath == "" {
return "", nil
}
// Decode base64 data
data, err := base64.StdEncoding.DecodeString(result.Data)
if err != nil {
return "", fmt.Errorf("failed to decode screenshot data: %w", err)
}
// Save to selected location
if err := os.WriteFile(savePath, data, 0644); err != nil {
return "", fmt.Errorf("failed to save screenshot: %w", err)
}
return savePath, nil
}