Skip to content

More image type support for thumbnails#814

Merged
tankerkiller125 merged 4 commits intomainfrom
mk/more-thumbnails
Jun 26, 2025
Merged

More image type support for thumbnails#814
tankerkiller125 merged 4 commits intomainfrom
mk/more-thumbnails

Conversation

@tankerkiller125
Copy link
Copy Markdown
Contributor

@tankerkiller125 tankerkiller125 commented Jun 25, 2025

What type of PR is this?

  • feature

What this PR does / why we need it:

Adds HEIC and JPEG XL support for thumbnailing. In theory we should be able to support all the image types with this for displaying in the grids and what not.

Summary by CodeRabbit

  • New Features

    • Added support for HEIC/HEIF and JPEG XL image formats, including automatic thumbnail generation.
    • Enhanced photo display with responsive image loading using original and thumbnail image sources.
  • Bug Fixes

    • Improved detection of HEIC, HEIF, AVIF, and JPEG XL image types for accurate processing and display.
  • Chores

    • Updated dependencies to include libraries for HEIC and JPEG XL image decoding.
    • Added database migration to store MIME type information for attachments.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jun 25, 2025

Walkthrough

Support for HEIC/HEIF and JPEG XL image formats was added across backend logic, including thumbnail creation and image type detection. The frontend was updated to utilize responsive image loading via <picture> elements with multiple sources. Error handling for thumbnail subscription was changed to log and continue on errors. New dependencies for HEIC and JPEG XL were introduced. Database migrations add MIME type columns.

Changes

File(s) Change Summary
backend/app/api/handlers/v1/v1_ctrl_items_attachments.go Recognized ".heic" and ".jxl" as photo types in attachment creation logic.
backend/app/api/main.go Modified thumbnail subscription: now runs asynchronously, logs errors, and continues processing instead of terminating.
backend/go.mod Added github.com/gen2brain/heic and github.com/gen2brain/jpegxl dependencies.
backend/internal/data/repo/repo_item_attachments.go Added HEIC/HEIF and JPEG XL support for thumbnail creation; improved content type detection; updated error handling.
backend/internal/data/migrations/postgres/20250625120010_add_mime_type.sql Added mime_type column to attachments table with default 'application/octet-stream'.
backend/internal/data/migrations/sqlite3/20250625120000_add_mime_type.sql Added mime_type column to attachments table with default 'application/octet-stream'.
frontend/pages/item/[id]/index.vue Extended Photo type with originalSrc, thumbnailSrc, and originalType; updated template to use <picture> element for responsive images.
frontend/lib/api/types/data-contracts.ts Added mime_type/mimeType string properties to EntAttachment and ItemAttachment interfaces.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Frontend
    participant Backend
    participant Storage

    User->>Frontend: View item with attachments
    Frontend->>Backend: Request item attachments
    Backend->>Storage: Retrieve attachments (including .heic, .jxl)
    Backend->>Backend: Detect MIME type, create thumbnails if needed
    Backend->>Storage: Upload thumbnails
    Backend->>Frontend: Return attachment info with thumbnails and MIME types
    Frontend->>User: Render images using <picture> with original and thumbnail sources
Loading

Suggested labels

⬆️ enhancement, go

Suggested reviewers

  • tonyaellie

Poem

📸
New formats join the gallery’s light—
HEIC and JXL now in sight!
Thumbnails bloom, responsive and neat,
Images load swift, a modern feat.
Code logs errors but marches on,
With new dependencies, the future’s drawn.

🖼️✨


Security Recommendations

  • Keep the new image decoding libraries (heic, jpegxl) updated to mitigate vulnerabilities.
  • Validate and sanitize all uploaded files to prevent malicious payloads, especially with expanded image format support.
  • Monitor error logs for repeated failures that may indicate malformed or malicious files.
  • Implement rate limiting and authentication on endpoints handling image uploads and processing to reduce abuse risk.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (1.64.8)

Error: you are using a configuration file for golangci-lint v2 with golangci-lint v1: please use golangci-lint v2
Failed executing command with error: you are using a configuration file for golangci-lint v2 with golangci-lint v1: please use golangci-lint v2


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7b755ac and 2fba449.

📒 Files selected for processing (1)
  • backend/internal/data/repo/repo_item_attachments.go (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/internal/data/repo/repo_item_attachments.go
⏰ Context from checks skipped due to timeout of 90000ms (18)
  • GitHub Check: build (linux/amd64)
  • GitHub Check: build (linux/riscv64)
  • GitHub Check: build (linux/arm/v7)
  • GitHub Check: build (linux/arm64)
  • GitHub Check: Frontend Tests / Integration Tests PGSQL 17
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 4/4
  • GitHub Check: Frontend Tests / Integration Tests PGSQL 15
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 2/4
  • GitHub Check: Frontend Tests / Integration Tests PGSQL 16
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 3/4
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 1/4
  • GitHub Check: Backend Server Tests / Go
  • GitHub Check: Frontend Tests / Integration Tests
  • GitHub Check: build (linux/riscv64)
  • GitHub Check: build (linux/amd64)
  • GitHub Check: build (linux/arm64)
  • GitHub Check: build (linux/arm/v7)
  • GitHub Check: Analyze (go)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Post Copyable Unit Tests in Comment
  • Commit Unit Tests in branch mk/more-thumbnails

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
backend/app/api/main.go (1)

348-368: Critical: Error handling changes mask security issues.

The modified error handling is concerning from a security perspective. Previously, errors would terminate processing, but now they're only logged while processing continues. This could mask:

  1. Malformed UUID attacks - Invalid group_id/attachment_id values are logged but processing continues
  2. Thumbnail creation failures - Failed image processing (potentially from malicious images) is logged but the message is still acknowledged
  3. Resource exhaustion - Processing continues even when thumbnail creation fails due to resource issues

This creates a security vulnerability where malicious actors could submit crafted requests that cause errors but still get processed.

Consider implementing proper error categorization:

 msg, err := subscription.Receive(ctx)
 if err != nil {
     log.Err(err).Msg("failed to receive message from pubsub topic")
+    continue // Skip this iteration on receive errors
 }
 groupId, err := uuid.Parse(msg.Metadata["group_id"])
 if err != nil {
     log.Error().Err(err).Str("group_id", msg.Metadata["group_id"]).Msg("failed to parse group ID")
+    msg.Nack() // Reject malformed messages
+    continue
 }
 attachmentId, err := uuid.Parse(msg.Metadata["attachment_id"])
 if err != nil {
     log.Error().Err(err).Str("attachment_id", msg.Metadata["attachment_id"]).Msg("failed to parse attachment ID")
+    msg.Nack() // Reject malformed messages
+    continue
 }
 err = app.repos.Attachments.CreateThumbnail(ctx, groupId, attachmentId, msg.Metadata["title"], msg.Metadata["path"])
 if err != nil {
     log.Err(err).Msg("failed to create thumbnail")
+    msg.Nack() // Reject failed processing
+    continue
 }
 msg.Ack()
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d97bfb9 and be0376d.

⛔ Files ignored due to path filters (1)
  • backend/go.sum is excluded by !**/*.sum
📒 Files selected for processing (5)
  • backend/app/api/handlers/v1/v1_ctrl_items_attachments.go (1 hunks)
  • backend/app/api/main.go (1 hunks)
  • backend/go.mod (1 hunks)
  • backend/internal/data/repo/repo_item_attachments.go (4 hunks)
  • frontend/pages/item/[id]/index.vue (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (18)
  • GitHub Check: build (linux/amd64)
  • GitHub Check: build (linux/riscv64)
  • GitHub Check: build (linux/arm/v7)
  • GitHub Check: build (linux/arm64)
  • GitHub Check: Frontend Tests / Integration Tests PGSQL 15
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 4/4
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 1/4
  • GitHub Check: Frontend Tests / Integration Tests PGSQL 16
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 3/4
  • GitHub Check: Frontend Tests / Integration Tests PGSQL 17
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 2/4
  • GitHub Check: Backend Server Tests / Go
  • GitHub Check: Frontend Tests / Integration Tests
  • GitHub Check: build (linux/arm64)
  • GitHub Check: build (linux/amd64)
  • GitHub Check: build (linux/riscv64)
  • GitHub Check: build (linux/arm/v7)
  • GitHub Check: Analyze (go)
🔇 Additional comments (9)
backend/go.mod (1)

12-13: Let’s fetch each repo’s popularity, last update, and license to ensure they’re well-maintained and properly licensed:

#!/bin/bash
echo "Gathering metadata for gen2brain/heic..."
gh repo view gen2brain/heic --json stargazerCount,pushedAt,licenseInfo

echo "Gathering metadata for gen2brain/jpegxl..."
gh repo view gen2brain/jpegxl --json stargazerCount,pushedAt,licenseInfo
backend/app/api/handlers/v1/v1_ctrl_items_attachments.go (1)

85-85: LGTM - File extension detection extended for new formats.

The addition of .heic and .jxl extensions follows the existing pattern for photo type detection. Note that this relies on file extensions rather than content-based validation, but the actual image processing and validation occurs downstream in the thumbnail creation pipeline.

frontend/pages/item/[id]/index.vue (3)

103-103: LGTM - TypeScript type extension for responsive images.

The optional srcset property correctly extends the Photo type to support responsive image loading.


110-122: LGTM - Proper responsive image implementation.

The logic correctly implements responsive image loading by using thumbnails as the primary src and original images as srcset when thumbnails are available. This provides good performance optimization for image display.


692-692: LGTM - Standard srcset implementation.

The template correctly binds both src and srcset attributes for responsive image loading.

backend/app/api/main.go (1)

312-312: Asynchronous execution is appropriate for background processing.

Running the thumbnail subscription asynchronously is correct for background task processing.

backend/internal/data/repo/repo_item_attachments.go (3)

15-16: LGTM - Required imports for new image format support.

The imports for HEIC and JPEG XL decoding libraries are necessary for the new functionality.


422-428: LGTM - Content type detection enhancement.

The fallback content type detection for HEIC/HEIF and AVIF files is necessary since http.DetectContentType may not recognize these newer formats. This follows a secure approach by checking file extensions as a fallback.


92-92: Verify performance impact of thumbnail query.

The added thumbnail query in ToItemAttachment could impact performance if called frequently, as it adds an additional database query for each attachment.

#!/bin/bash
# Check how frequently ToItemAttachment is called
rg -A 5 -B 5 "ToItemAttachment" --type go

@tankerkiller125
Copy link
Copy Markdown
Contributor Author

@tonyaellie I'm not 100% sure on the Vue updates here, it seems to work sometimes, but not always for HEIC/JPEG XL files. I'm really not sure if src and srcset is the correct way to do this.

I should note that it works just fine in the item grid, it's only on the actual individual item page that I'm having trouble with.

@tonyaellie
Copy link
Copy Markdown
Collaborator

The best approach would probably be to generate a thumbnail and a high res version, then use the thumbnail for the like small picture and the high res version for the dialog, and then only use the original when they click download. I dont think srcset is really needed.

@tonyaellie
Copy link
Copy Markdown
Collaborator

Reading ur message on discord if u just want to first try the normal image and then fallback to the thumbnail you will want something like

<picture>
  <source srcset="image.avif" type="image/avif" />
  <img src="thumbnail.png" />
</picture>

@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying homebox-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 7b755ac
Status: ✅  Deploy successful!
Preview URL: https://da287401.homebox-docs.pages.dev
Branch Preview URL: https://mk-more-thumbnails.homebox-docs.pages.dev

View logs

@coderabbitai coderabbitai bot requested a review from tonyaellie June 26, 2025 00:53
@coderabbitai coderabbitai bot added go Pull requests that update Go code ⬆️ enhancement New feature or request labels Jun 26, 2025
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
backend/internal/data/repo/repo_item_attachments.go (1)

558-633: Security and maintainability issues in thumbnail creation.

The HEIC and JPEG XL thumbnail creation code has several critical issues that need to be addressed:

  1. Security vulnerability: No input validation for image dimensions after decoding, which could lead to memory exhaustion attacks
  2. Error message inconsistency: Both HEIC and JPEG XL error handlers incorrectly log "failed to decode avif image"
  3. Code duplication: Significant duplication across all image format handlers

Security fixes needed:

 case contentType == "image/heic" || contentType == "image/heif":
     log.Debug().Msg("creating thumbnail for heic file")
     img, err := heic.Decode(bytes.NewReader(contentBytes))
     if err != nil {
-        log.Err(err).Msg("failed to decode avif image")
+        log.Err(err).Msg("failed to decode heic image")
         // ... error handling
     }
+    
+    // Validate decoded image dimensions
+    bounds := img.Bounds()
+    if bounds.Dx() > 20000 || bounds.Dy() > 20000 {
+        return fmt.Errorf("image dimensions too large: %dx%d", bounds.Dx(), bounds.Dy())
+    }

 case contentType == "image/jxl":
     log.Debug().Msg("creating thumbnail for jpegxl file")
     img, err := jpegxl.Decode(bytes.NewReader(contentBytes))
     if err != nil {
-        log.Err(err).Msg("failed to decode avif image")
+        log.Err(err).Msg("failed to decode jpeg xl image")
         // ... error handling
     }
+    
+    // Validate decoded image dimensions
+    bounds := img.Bounds()
+    if bounds.Dx() > 20000 || bounds.Dy() > 20000 {
+        return fmt.Errorf("image dimensions too large: %dx%d", bounds.Dx(), bounds.Dy())
+    }

Refactor suggestion: Extract the common thumbnail creation logic into a shared function to eliminate code duplication and ensure consistent security measures across all image formats.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between be0376d and 7b755ac.

⛔ Files ignored due to path filters (15)
  • backend/app/api/static/docs/docs.go is excluded by !backend/app/api/static/docs/**
  • backend/app/api/static/docs/swagger.json is excluded by !backend/app/api/static/docs/**
  • backend/app/api/static/docs/swagger.yaml is excluded by !backend/app/api/static/docs/**
  • backend/go.sum is excluded by !**/*.sum
  • backend/internal/data/ent/attachment.go is excluded by !backend/internal/data/ent/**
  • backend/internal/data/ent/attachment/attachment.go is excluded by !backend/internal/data/ent/**
  • backend/internal/data/ent/attachment/where.go is excluded by !backend/internal/data/ent/**
  • backend/internal/data/ent/attachment_create.go is excluded by !backend/internal/data/ent/**
  • backend/internal/data/ent/attachment_update.go is excluded by !backend/internal/data/ent/**
  • backend/internal/data/ent/migrate/schema.go is excluded by !backend/internal/data/ent/**
  • backend/internal/data/ent/mutation.go is excluded by !backend/internal/data/ent/**
  • backend/internal/data/ent/runtime.go is excluded by !backend/internal/data/ent/**
  • backend/internal/data/ent/schema/attachment.go is excluded by !backend/internal/data/ent/**
  • docs/en/api/openapi-2.0.json is excluded by !docs/en/api/**
  • docs/en/api/openapi-2.0.yaml is excluded by !docs/en/api/**
📒 Files selected for processing (5)
  • backend/internal/data/migrations/postgres/20250625120010_add_mime_type.sql (1 hunks)
  • backend/internal/data/migrations/sqlite3/20250625120000_add_mime_type.sql (1 hunks)
  • backend/internal/data/repo/repo_item_attachments.go (6 hunks)
  • frontend/lib/api/types/data-contracts.ts (2 hunks)
  • frontend/pages/item/[id]/index.vue (4 hunks)
✅ Files skipped from review due to trivial changes (2)
  • backend/internal/data/migrations/sqlite3/20250625120000_add_mime_type.sql
  • frontend/lib/api/types/data-contracts.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/pages/item/[id]/index.vue
⏰ Context from checks skipped due to timeout of 90000ms (15)
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 4/4
  • GitHub Check: Frontend Tests / Integration Tests PGSQL 16
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 2/4
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 3/4
  • GitHub Check: End-to-End Playwright Tests / E2E Playwright Testing 1/4
  • GitHub Check: Backend Server Tests / Go
  • GitHub Check: build (linux/arm64)
  • GitHub Check: build (linux/arm/v7)
  • GitHub Check: build (linux/riscv64)
  • GitHub Check: build (linux/amd64)
  • GitHub Check: build (linux/amd64)
  • GitHub Check: build (linux/riscv64)
  • GitHub Check: build (linux/arm64)
  • GitHub Check: build (linux/arm/v7)
  • GitHub Check: Analyze (go)
🔇 Additional comments (6)
backend/internal/data/migrations/postgres/20250625120010_add_mime_type.sql (1)

1-4: Migration looks good!

The migration correctly adds the mime_type column with an appropriate default value. The syntax is correct and the change is non-breaking.

backend/internal/data/repo/repo_item_attachments.go (5)

15-16: New image format dependencies added correctly.

The imports for HEIC and JPEG XL libraries are properly added to support the new image formats.


67-67: MimeType field addition looks good.

The MimeType field is properly added to the ItemAttachment struct with appropriate JSON tag.


434-440: Content type fallback logic is well implemented.

The fallback logic for detecting HEIC/HEIF and AVIF formats when http.DetectContentType returns application/octet-stream is a good solution for handling formats that may not be properly detected by the standard library.


638-638: Good practice: Explicit MIME type setting for thumbnails.

Setting the MIME type to "image/webp" explicitly for all thumbnails ensures consistency and proper handling downstream.


93-95: The previous search didn’t surface any references—let’s locate all uses of ToItemAttachment and QueryThumbnail to understand how they’re invoked in bulk:

#!/bin/bash
# Find every occurrence of ToItemAttachment
rg --color=never -n 'ToItemAttachment'

# Find every occurrence of QueryThumbnail and show nearby lines for context
rg --color=never -n 'QueryThumbnail' -A3 -B3

Security recommendation: Always validate and sanitize thumbnail data returned from the database to guard against potential injection or data-leak vulnerabilities.

@tankerkiller125 tankerkiller125 merged commit 4861a85 into main Jun 26, 2025
26 of 27 checks passed
@tankerkiller125 tankerkiller125 deleted the mk/more-thumbnails branch June 26, 2025 14:19
yannicschuller pushed a commit to yannicschuller/homebox that referenced this pull request Sep 24, 2025
auzroz pushed a commit to auzroz/homebox that referenced this pull request Dec 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⬆️ enhancement New feature or request go Pull requests that update Go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants