mirror of
https://github.com/Theodor-Springmann-Stiftung/kgpz_web.git
synced 2025-10-28 16:45:32 +00:00
+Compressed IMG files
This commit is contained in:
@@ -41,14 +41,16 @@ type IndividualPiecesByPage struct {
|
||||
}
|
||||
|
||||
type IssuePage struct {
|
||||
PageNumber int
|
||||
ImagePath string
|
||||
Available bool
|
||||
GridColumn int // 1 or 2 for left/right positioning
|
||||
GridRow int // Row number in grid
|
||||
HasHeader bool // Whether this page has a double-spread header
|
||||
HeaderText string // Text for double-spread header
|
||||
PageIcon string // Icon type: "first", "last", "even", "odd"
|
||||
PageNumber int
|
||||
ImagePath string // Full-quality image path (prefers WebP over JPEG)
|
||||
PreviewPath string // Compressed WebP path for layout views
|
||||
JpegPath string // JPEG path for download button
|
||||
Available bool
|
||||
GridColumn int // 1 or 2 for left/right positioning
|
||||
GridRow int // Row number in grid
|
||||
HasHeader bool // Whether this page has a double-spread header
|
||||
HeaderText string // Text for double-spread header
|
||||
PageIcon string // Icon type: "first", "last", "even", "odd"
|
||||
}
|
||||
|
||||
type IssueImages struct {
|
||||
@@ -58,13 +60,15 @@ type IssueImages struct {
|
||||
}
|
||||
|
||||
type ImageFile struct {
|
||||
Year int
|
||||
Issue int
|
||||
Page int
|
||||
IsBeilage bool
|
||||
BeilageNo int
|
||||
Filename string
|
||||
Path string
|
||||
Year int
|
||||
Issue int
|
||||
Page int
|
||||
IsBeilage bool
|
||||
BeilageNo int
|
||||
Filename string
|
||||
Path string // Primary path (prefers WebP over JPEG)
|
||||
PreviewPath string // Path to compressed WebP version for layout views
|
||||
JpegPath string // Path to JPEG version (for download button)
|
||||
}
|
||||
|
||||
type ImageRegistry struct {
|
||||
@@ -518,16 +522,30 @@ func LoadIssueImages(issue xmlmodels.Issue) (IssueImages, error) {
|
||||
|
||||
if foundFile != nil {
|
||||
images.HasImages = true
|
||||
// Use preview path if available, otherwise fallback to original
|
||||
previewPath := foundFile.PreviewPath
|
||||
if previewPath == "" {
|
||||
previewPath = foundFile.Path
|
||||
}
|
||||
// Use JPEG path if available, otherwise fallback to primary
|
||||
jpegPath := foundFile.JpegPath
|
||||
if jpegPath == "" {
|
||||
jpegPath = foundFile.Path
|
||||
}
|
||||
images.MainPages = append(images.MainPages, IssuePage{
|
||||
PageNumber: page,
|
||||
ImagePath: foundFile.Path,
|
||||
Available: true,
|
||||
PageNumber: page,
|
||||
ImagePath: foundFile.Path,
|
||||
PreviewPath: previewPath,
|
||||
JpegPath: jpegPath,
|
||||
Available: true,
|
||||
})
|
||||
} else {
|
||||
images.MainPages = append(images.MainPages, IssuePage{
|
||||
PageNumber: page,
|
||||
ImagePath: "",
|
||||
Available: false,
|
||||
PageNumber: page,
|
||||
ImagePath: "",
|
||||
PreviewPath: "",
|
||||
JpegPath: "",
|
||||
Available: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -539,10 +557,22 @@ func LoadIssueImages(issue xmlmodels.Issue) (IssueImages, error) {
|
||||
// Add ALL beilage files found for this issue
|
||||
for _, file := range beilageFiles {
|
||||
images.HasImages = true
|
||||
// Use preview path if available, otherwise fallback to original
|
||||
previewPath := file.PreviewPath
|
||||
if previewPath == "" {
|
||||
previewPath = file.Path
|
||||
}
|
||||
// Use JPEG path if available, otherwise fallback to primary
|
||||
jpegPath := file.JpegPath
|
||||
if jpegPath == "" {
|
||||
jpegPath = file.Path
|
||||
}
|
||||
beilagePages = append(beilagePages, IssuePage{
|
||||
PageNumber: file.Page,
|
||||
ImagePath: file.Path,
|
||||
Available: true,
|
||||
PageNumber: file.Page,
|
||||
ImagePath: file.Path,
|
||||
PreviewPath: previewPath,
|
||||
JpegPath: jpegPath,
|
||||
Available: true,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -573,7 +603,10 @@ func initImageRegistry() error {
|
||||
ByYearPage: make(map[string]ImageFile),
|
||||
}
|
||||
|
||||
return filepath.Walk("pictures", func(path string, info os.FileInfo, err error) error {
|
||||
// Temporary map to collect all files by their base name (year-issue-page)
|
||||
tempFiles := make(map[string]*ImageFile)
|
||||
|
||||
err := filepath.Walk("pictures", func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -583,14 +616,22 @@ func initImageRegistry() error {
|
||||
}
|
||||
|
||||
filename := info.Name()
|
||||
filenamelower := strings.ToLower(filename)
|
||||
|
||||
// Skip non-jpg files
|
||||
if !strings.HasSuffix(strings.ToLower(filename), ".jpg") {
|
||||
return nil
|
||||
// Only process .jpg and .webp files (but skip preview files)
|
||||
var nameWithoutExt string
|
||||
var isWebP bool
|
||||
|
||||
if strings.HasSuffix(filenamelower, ".jpg") {
|
||||
nameWithoutExt = strings.TrimSuffix(filename, ".jpg")
|
||||
isWebP = false
|
||||
} else if strings.HasSuffix(filenamelower, ".webp") && !strings.HasSuffix(filenamelower, "-preview.webp") {
|
||||
nameWithoutExt = strings.TrimSuffix(filename, ".webp")
|
||||
isWebP = true
|
||||
} else {
|
||||
return nil // Skip non-image files and preview files
|
||||
}
|
||||
|
||||
// Remove .jpg extension and split by -
|
||||
nameWithoutExt := strings.TrimSuffix(filename, ".jpg")
|
||||
parts := strings.Split(nameWithoutExt, "-")
|
||||
|
||||
// Need at least 3 parts: year-issue-page
|
||||
@@ -624,26 +665,87 @@ func initImageRegistry() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
imageFile := ImageFile{
|
||||
Year: year,
|
||||
Issue: issue,
|
||||
Page: page,
|
||||
IsBeilage: isBeilage,
|
||||
BeilageNo: 1, // Default beilage number
|
||||
Filename: filename,
|
||||
Path: fmt.Sprintf("/static/pictures/%s", path[9:]), // Remove "pictures/" prefix
|
||||
// Create unique key for this image (handles both regular and beilage)
|
||||
var uniqueKey string
|
||||
if isBeilage {
|
||||
uniqueKey = fmt.Sprintf("%d-%db-%d", year, issue, page)
|
||||
} else {
|
||||
uniqueKey = fmt.Sprintf("%d-%d-%d", year, issue, page)
|
||||
}
|
||||
|
||||
imageRegistry.Files = append(imageRegistry.Files, imageFile)
|
||||
// Get or create the ImageFile entry
|
||||
imageFile, exists := tempFiles[uniqueKey]
|
||||
if !exists {
|
||||
imageFile = &ImageFile{
|
||||
Year: year,
|
||||
Issue: issue,
|
||||
Page: page,
|
||||
IsBeilage: isBeilage,
|
||||
BeilageNo: 1, // Default beilage number
|
||||
}
|
||||
tempFiles[uniqueKey] = imageFile
|
||||
}
|
||||
|
||||
yearIssueKey := fmt.Sprintf("%d-%d", year, issue)
|
||||
imageRegistry.ByYearIssue[yearIssueKey] = append(imageRegistry.ByYearIssue[yearIssueKey], imageFile)
|
||||
|
||||
if !isBeilage {
|
||||
yearPageKey := fmt.Sprintf("%d-%d", year, page)
|
||||
imageRegistry.ByYearPage[yearPageKey] = imageFile
|
||||
// Set paths based on file type
|
||||
currentPath := fmt.Sprintf("/static/pictures/%s", path[9:]) // Remove "pictures/" prefix
|
||||
if isWebP {
|
||||
// WebP is the primary path for single page viewer
|
||||
imageFile.Path = currentPath
|
||||
imageFile.Filename = filename
|
||||
} else {
|
||||
// JPEG is the fallback path for download
|
||||
imageFile.JpegPath = currentPath
|
||||
// If no WebP path is set yet, use JPEG as primary
|
||||
if imageFile.Path == "" {
|
||||
imageFile.Path = currentPath
|
||||
imageFile.Filename = filename
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Second pass: set PreviewPath for each ImageFile by checking for preview files
|
||||
for _, imageFile := range tempFiles {
|
||||
// Extract the base name from the filename to preserve original format
|
||||
baseNameWithExt := imageFile.Filename
|
||||
var baseName string
|
||||
|
||||
// Remove extension to get base name
|
||||
if strings.HasSuffix(strings.ToLower(baseNameWithExt), ".webp") {
|
||||
baseName = strings.TrimSuffix(baseNameWithExt, ".webp")
|
||||
} else if strings.HasSuffix(strings.ToLower(baseNameWithExt), ".jpg") {
|
||||
baseName = strings.TrimSuffix(baseNameWithExt, ".jpg")
|
||||
} else {
|
||||
baseName = baseNameWithExt
|
||||
}
|
||||
|
||||
// Generate preview filename using the original base name format
|
||||
previewFilename := baseName + "-preview.webp"
|
||||
|
||||
// Check if preview file exists
|
||||
previewFullPath := filepath.Join("pictures", fmt.Sprintf("%d", imageFile.Year), previewFilename)
|
||||
if _, err := os.Stat(previewFullPath); err == nil {
|
||||
imageFile.PreviewPath = fmt.Sprintf("/static/pictures/%d/%s", imageFile.Year, previewFilename)
|
||||
}
|
||||
}
|
||||
|
||||
// Convert temp map to final registry structures
|
||||
for _, imageFile := range tempFiles {
|
||||
imageRegistry.Files = append(imageRegistry.Files, *imageFile)
|
||||
|
||||
yearIssueKey := fmt.Sprintf("%d-%d", imageFile.Year, imageFile.Issue)
|
||||
imageRegistry.ByYearIssue[yearIssueKey] = append(imageRegistry.ByYearIssue[yearIssueKey], *imageFile)
|
||||
|
||||
if !imageFile.IsBeilage {
|
||||
yearPageKey := fmt.Sprintf("%d-%d", imageFile.Year, imageFile.Page)
|
||||
imageRegistry.ByYearPage[yearPageKey] = *imageFile
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -11,7 +11,9 @@ type PiecePageEntry struct {
|
||||
PageNumber int
|
||||
IssueYear int
|
||||
IssueNumber int
|
||||
ImagePath string
|
||||
ImagePath string // Full-quality image path (prefers WebP over JPEG)
|
||||
PreviewPath string // Compressed WebP path for layout views
|
||||
JpegPath string // JPEG path for download button
|
||||
IsContinuation bool
|
||||
IssueContext string // "1764 Nr. 37" for display
|
||||
Available bool
|
||||
@@ -96,8 +98,8 @@ func NewPieceView(piece xmlmodels.Piece, lib *xmlmodels.Library) (*PieceVM, erro
|
||||
PartNumber: partIndex + 1, // Part number (1-based)
|
||||
}
|
||||
|
||||
// Get actual image path from registry
|
||||
pageEntry.ImagePath = getImagePathFromRegistryWithBeilage(issueRef.When.Year, issueRef.Nr, pageNum, issueRef.Beilage > 0)
|
||||
// Get actual image path, preview path, and JPEG path from registry
|
||||
pageEntry.ImagePath, pageEntry.PreviewPath, pageEntry.JpegPath = getImagePathsFromRegistryWithBeilage(issueRef.When.Year, issueRef.Nr, pageNum, issueRef.Beilage > 0)
|
||||
|
||||
pvm.AllPages = append(pvm.AllPages, pageEntry)
|
||||
}
|
||||
@@ -140,10 +142,12 @@ func (pvm *PieceVM) loadImages() error {
|
||||
for i, pageEntry := range pvm.AllPages {
|
||||
// Create IssuePage for template compatibility
|
||||
issuePage := IssuePage{
|
||||
PageNumber: pageEntry.PageNumber,
|
||||
ImagePath: pageEntry.ImagePath,
|
||||
Available: true, // Assume available for now
|
||||
PageIcon: "single", // Simplified icon for piece view
|
||||
PageNumber: pageEntry.PageNumber,
|
||||
ImagePath: pageEntry.ImagePath,
|
||||
PreviewPath: pageEntry.PreviewPath,
|
||||
JpegPath: pageEntry.JpegPath,
|
||||
Available: true, // Assume available for now
|
||||
PageIcon: "single", // Simplified icon for piece view
|
||||
}
|
||||
|
||||
// Check if image actually exists using the registry
|
||||
@@ -231,7 +235,56 @@ func getImagePathFromRegistry(year, page int) string {
|
||||
return fmt.Sprintf("/static/pictures/%d/seite_%d.jpg", year, page)
|
||||
}
|
||||
|
||||
// getImagePathsFromRegistryWithBeilage gets image paths: primary (WebP preferred), preview (compressed), and JPEG, handling both regular and Beilage pages
|
||||
func getImagePathsFromRegistryWithBeilage(year, issue, page int, isBeilage bool) (string, string, string) {
|
||||
// Initialize registry if needed
|
||||
if err := initImageRegistry(); err != nil {
|
||||
return "", "", ""
|
||||
}
|
||||
|
||||
// For regular pages, use the year-page lookup
|
||||
if !isBeilage {
|
||||
key := fmt.Sprintf("%d-%d", year, page)
|
||||
if imageFile, exists := imageRegistry.ByYearPage[key]; exists {
|
||||
previewPath := imageFile.PreviewPath
|
||||
if previewPath == "" {
|
||||
previewPath = imageFile.Path // Fallback to original if no preview
|
||||
}
|
||||
jpegPath := imageFile.JpegPath
|
||||
if jpegPath == "" {
|
||||
jpegPath = imageFile.Path // Fallback to primary if no separate JPEG
|
||||
}
|
||||
return imageFile.Path, previewPath, jpegPath
|
||||
}
|
||||
// Fallback for regular pages
|
||||
fallbackPath := fmt.Sprintf("/static/pictures/%d/seite_%d.jpg", year, page)
|
||||
return fallbackPath, fallbackPath, fallbackPath
|
||||
}
|
||||
|
||||
// For Beilage pages, search through all files for this year-issue
|
||||
yearIssueKey := fmt.Sprintf("%d-%d", year, issue)
|
||||
if issueFiles, exists := imageRegistry.ByYearIssue[yearIssueKey]; exists {
|
||||
for _, file := range issueFiles {
|
||||
if file.IsBeilage && file.Page == page {
|
||||
previewPath := file.PreviewPath
|
||||
if previewPath == "" {
|
||||
previewPath = file.Path // Fallback to original if no preview
|
||||
}
|
||||
jpegPath := file.JpegPath
|
||||
if jpegPath == "" {
|
||||
jpegPath = file.Path // Fallback to primary if no separate JPEG
|
||||
}
|
||||
return file.Path, previewPath, jpegPath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No file found
|
||||
return "", "", ""
|
||||
}
|
||||
|
||||
// getImagePathFromRegistryWithBeilage gets the actual image path, handling both regular and Beilage pages
|
||||
// Kept for backward compatibility
|
||||
func getImagePathFromRegistryWithBeilage(year, issue, page int, isBeilage bool) string {
|
||||
// Initialize registry if needed
|
||||
if err := initImageRegistry(); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user