coobird/thumbnailator
Thumbnailator - a thumbnail generation library for Java
Solo project — review before adopting
weakest axissingle-maintainer (no co-maintainers visible); no CI workflows detected
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 3mo ago
- ✓MIT licensed
- ✓Tests present
Show all 5 evidence items →Show less
- ⚠Solo or near-solo (1 contributor active in recent commits)
- ⚠No CI workflows detected
What would change the summary?
- →Use as dependency Mixed → Healthy if: onboard a second core maintainer
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Forkable" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/coobird/thumbnailator)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/coobird/thumbnailator on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: coobird/thumbnailator
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/coobird/thumbnailator shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
WAIT — Solo project — review before adopting
- Last commit 3mo ago
- MIT licensed
- Tests present
- ⚠ Solo or near-solo (1 contributor active in recent commits)
- ⚠ No CI workflows detected
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live coobird/thumbnailator
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/coobird/thumbnailator.
What it runs against: a local clone of coobird/thumbnailator — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in coobird/thumbnailator | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 110 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of coobird/thumbnailator. If you don't
# have one yet, run these first:
#
# git clone https://github.com/coobird/thumbnailator.git
# cd thumbnailator
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of coobird/thumbnailator and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "coobird/thumbnailator(\\.git)?\\b" \\
&& ok "origin remote is coobird/thumbnailator" \\
|| miss "origin remote is not coobird/thumbnailator (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "src/main/java/net/coobird/thumbnailator/Thumbnails.java" \\
&& ok "src/main/java/net/coobird/thumbnailator/Thumbnails.java" \\
|| miss "missing critical file: src/main/java/net/coobird/thumbnailator/Thumbnails.java"
test -f "src/main/java/net/coobird/thumbnailator/builders/ThumbnailParameterBuilder.java" \\
&& ok "src/main/java/net/coobird/thumbnailator/builders/ThumbnailParameterBuilder.java" \\
|| miss "missing critical file: src/main/java/net/coobird/thumbnailator/builders/ThumbnailParameterBuilder.java"
test -f "src/main/java/net/coobird/thumbnailator/tasks/SourceSinkThumbnailTask.java" \\
&& ok "src/main/java/net/coobird/thumbnailator/tasks/SourceSinkThumbnailTask.java" \\
|| miss "missing critical file: src/main/java/net/coobird/thumbnailator/tasks/SourceSinkThumbnailTask.java"
test -f "src/main/java/net/coobird/thumbnailator/makers/ThumbnailMaker.java" \\
&& ok "src/main/java/net/coobird/thumbnailator/makers/ThumbnailMaker.java" \\
|| miss "missing critical file: src/main/java/net/coobird/thumbnailator/makers/ThumbnailMaker.java"
test -f "src/main/java/net/coobird/thumbnailator/resizers/Resizer.java" \\
&& ok "src/main/java/net/coobird/thumbnailator/resizers/Resizer.java" \\
|| miss "missing critical file: src/main/java/net/coobird/thumbnailator/resizers/Resizer.java"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 110 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~80d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/coobird/thumbnailator"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Thumbnailator is a pure Java library for generating high-quality thumbnail images with a fluent, chainable API. It abstracts away the complexity of Java 2D, Image I/O, and image scaling algorithms, allowing developers to resize, filter, and process images in a single method chain—e.g., Thumbnails.of(images).size(640, 480).outputFormat("jpg").toFiles(Rename.PREFIX_DOT_THUMBNAIL). It ships as a zero-dependency JAR with support for multiple scaling algorithms (bicubic, bilinear), image filters (watermark, caption, rotation), and batch processing. Standard Maven monolith: src/main/java/net/coobird/thumbnailator/ is the root package. Core entry points are Thumbnails.java (fluent builder) and Thumbnailator.java (core logic). Modular internal design splits into subpackages: builders/ (fluent configuration), makers/ (scaling strategies), resizers/ (algorithm implementations: bicubic, bilinear), filters/ (image transforms: watermark, rotation, canvas), geometry/ (coordinate/size abstractions), and name/ (batch output naming). All compiled into a single JAR with no separate CLI or plugin layer.
👥Who it's for
Java backend developers and desktop application builders who need to programmatically generate thumbnails for web uploads, image galleries, or media processing without wrestling with BufferedImage, Graphics2D, and ImageIO APIs directly. Also used by developers packaging image processing into libraries or microservices.
🌱Maturity & risk
Production-ready but with cautious development pace. Latest release is 0.4.21 (October 2025), indicating active maintenance. The single-maintainer model and early semver (0.4.x) signal stability in API but potential for minor breaking changes. No visible CI/CD setup in the provided file list, and the codebase targets Java 1.5 (pom.xml compiler source/target), which is dated but ensures broad compatibility.
Minimal risk from external dependencies (zero declared), but heavy reliance on Java's built-in Image I/O and 2D APIs means bugs or regressions in those are inherited. Single maintainer (Chris Kroells per pom.xml) creates knowledge concentration. The low semver version (0.4.x) and disclaimer stating "APIs are subject to change at any time" signal ongoing design evolution. No visible GitHub Actions or test reporting in file list.
Active areas of work
Active maintenance as of October 2025 (latest 0.4.21 release noted in README). No visible recent PRs or breaking changes in the file snapshot, but the project maintains Maven Central distribution and a wiki with examples and FAQ. Appears to be in sustainable steady-state with infrequent but complete releases.
🚀Get running
git clone https://github.com/coobird/thumbnailator.git
cd thumbnailator
mvn clean install
This compiles the library and installs it to your local Maven repository. For a simple test: add <dependency><groupId>net.coobird</groupId><artifactId>thumbnailator</artifactId><version>0.4.21</version></dependency> to your pom.xml.
Daily commands:
This is a library, not a runnable application. To use it: build with mvn clean package to generate target/thumbnailator-0.4.21.jar, then add to your classpath or Maven dependencies. Example code: Thumbnails.of(new File("input.jpg")).size(200, 200).toFile("output.jpg");
🗺️Map of the codebase
src/main/java/net/coobird/thumbnailator/Thumbnails.java— Main public API entry point providing the fluent interface for thumbnail generation; all users interact with this class first.src/main/java/net/coobird/thumbnailator/builders/ThumbnailParameterBuilder.java— Core builder pattern implementation that orchestrates all thumbnail configuration options and parameter validation.src/main/java/net/coobird/thumbnailator/tasks/SourceSinkThumbnailTask.java— Abstract base task that bridges image sources/sinks to the thumbnail generation pipeline; understands the core processing flow.src/main/java/net/coobird/thumbnailator/makers/ThumbnailMaker.java— Interface defining the contract for thumbnail generation strategies; essential for understanding the pluggable maker pattern.src/main/java/net/coobird/thumbnailator/resizers/Resizer.java— Core abstraction for image resizing algorithms; understanding this is critical for modifying scaling behavior.src/main/java/net/coobird/thumbnailator/filters/ImageFilter.java— Filter pipeline interface enabling image transformations; needed to extend thumbnail processing capabilities.pom.xml— Single-jar distribution model with zero external dependencies; critical for understanding deployment and build strategy.
🛠️How to make changes
Add a New Image Resizing Algorithm
- Create a new class extending AbstractResizer in the resizers package (
src/main/java/net/coobird/thumbnailator/resizers/AbstractResizer.java) - Implement the resize(BufferedImage, int, int) method with your algorithm (
src/main/java/net/coobird/thumbnailator/resizers/YourNewResizer.java) - Register your resizer in DefaultResizerFactory or create a FixedResizerFactory variant (
src/main/java/net/coobird/thumbnailator/resizers/DefaultResizerFactory.java) - Optionally add ResizerConfiguration implementations in the configurations subpackage (
src/main/java/net/coobird/thumbnailator/resizers/configurations/ResizerConfiguration.java)
Add a New Image Filter/Transformation
- Create a new class implementing ImageFilter interface (
src/main/java/net/coobird/thumbnailator/filters/ImageFilter.java) - Implement apply(BufferedImage) method with your transformation logic (
src/main/java/net/coobird/thumbnailator/filters/YourNewFilter.java) - Add builder method in ThumbnailParameterBuilder to expose the filter in the fluent API (
src/main/java/net/coobird/thumbnailator/builders/ThumbnailParameterBuilder.java) - Optionally compose with Pipeline if supporting chaining (
src/main/java/net/coobird/thumbnailator/filters/Pipeline.java)
Add Support for a New Image Source Format
- Create a new class extending AbstractImageSource (
src/main/java/net/coobird/thumbnailator/tasks/io/AbstractImageSource.java) - Implement getInputStream() and other required methods for your source type (
src/main/java/net/coobird/thumbnailator/tasks/io/YourNewImageSource.java) - Add overloaded methods in Thumbnails class to accept your source type (
src/main/java/net/coobird/thumbnailator/Thumbnails.java) - Optionally add format detection in SourceSinkThumbnailTask if format-specific handling needed (
src/main/java/net/coobird/thumbnailator/tasks/SourceSinkThumbnailTask.java)
Customize Thumbnail Sizing Strategy
- Create a new class implementing ThumbnailMaker interface (
src/main/java/net/coobird/thumbnailator/makers/ThumbnailMaker.java) - Implement makeThumbnail(BufferedImage) with your sizing/cropping logic (
src/main/java/net/coobird/thumbnailator/makers/YourCustomMaker.java) - Wire it into ThumbnailParameterBuilder or create a custom builder variant (
src/main/java/net/coobird/thumbnailator/builders/ThumbnailParameterBuilder.java)
🪤Traps & gotchas
Java 2D rendering thread-safety: BufferedImage and Graphics2D are not thread-safe; concurrent thumbnail generation without proper synchronization will cause corruption. Image format support varies by JVM: not all formats (JPEG, PNG, etc.) are guaranteed on all platforms—test on target JVM. Memory consumption with large batches: loading many images into BufferedImage arrays (via Thumbnails.of(files).toFiles()) without streaming can exhaust heap on large image directories. Quality vs. performance: bicubic resizing is much slower than bilinear; no automatic algorithm selection based on resize ratio. No color space management: uses JVM default color handling, which may produce different results across platforms for CMYK or other profiles. Output file overwrite: toFiles() silently overwrites existing files—no safeguard in the API.
🏗️Architecture
💡Concepts to learn
- Image resampling algorithms (Bicubic, Bilinear) — Thumbnailator abstracts bicubic vs. bilinear resizing; understanding the tradeoff (quality vs. speed) is essential for choosing the right resizer for your use case
- Aspect ratio preservation — Core feature of Thumbnailator; it scales images to fit within bounds while maintaining aspect ratio. Misunderstanding the logic leads to letterboxing bugs
- Fluent/Builder interface pattern — The entire public API of Thumbnailator is a fluent builder chain; understanding method chaining and immutability is crucial for using the library and extending it
- Java Image I/O API (ImageIO, ImageReader, ImageWriter) — Thumbnailator wraps Java's built-in Image I/O for format detection and encoding; understanding its limitations (codec availability, plugin mechanism) explains why certain formats fail
- BufferedImage color models and raster data — Thumbnailator manipulates BufferedImage internals; knowing RGB vs. ARGB color space, direct vs. indexed color, and raster layout helps debug color/transparency issues
- Graphics2D rendering pipeline and RenderingHints — Resizers use Graphics2D to paint scaled images; RenderingHints control interpolation quality—tweaking these is how quality/performance tradeoffs are made
- Batch file I/O and naming strategies — Thumbnailator's
name/package (Rename, ConsecutivelyNumberedFilenames) handles renaming during batch operations; understanding these prevents accidental file overwrites
🔗Related repos
imgscalr/imgscalr— Pure Java image scaling library with similar scope; offers alternative resizing algorithms (Lanczos, Mitchell) but less fluent API and no filter chainImageMagick/ImageMagick— Industry-standard image processing C library; Thumbnailator is Java equivalent but ImageMagick offers vastly more filters and formats via system calls (higher overhead, language-agnostic)eclipse/imageio-ext— Eclipse Foundation library extending Java ImageIO with GeoTIFF and advanced format support; complements Thumbnailator for specialized image I/O needsjhy/jsoup— Often used alongside Thumbnailator in web applications to parse HTML, extract image URLs, and batch-process thumbnails programmaticallymarvin-image-processing/marvin-framework— Comprehensive Java image processing framework with GUI and real-time filters; heavier than Thumbnailator but covers both thumbnailing and advanced filters
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive unit tests for resizer configurations and algorithms
The resizers package contains multiple resizing algorithms (BicubicResizer, BilinearResizer, ProgressiveBilinearResizer) and configuration classes (AlphaInterpolation, Antialiasing, Dithering, Rendering, ScalingMode) but there's no visible test coverage in src/test. This is critical for image processing quality assurance, as different resizing algorithms can produce visibly different outputs. Adding tests would ensure regressions are caught and document expected behavior.
- [ ] Create src/test/java/net/coobird/thumbnailator/resizers/ directory structure
- [ ] Add unit tests for BicubicResizer.java, BilinearResizer.java, and ProgressiveBilinearResizer.java comparing output dimensions and quality
- [ ] Add unit tests for resizers/configurations/ classes to verify rendering hints and scaling modes are applied correctly
- [ ] Add integration tests in DefaultResizerFactory.java to verify correct resizer selection based on image type
Add GitHub Actions CI workflow for automated testing and Java compatibility matrix
The pom.xml shows compilation targets Java 1.5 (very old), but there's no visible CI configuration in .github/workflows/. Modern Java versions (8, 11, 17, 21) should be tested to identify compatibility issues and ensure the library works across LTS versions. This prevents silent breakage and helps contributors verify their changes.
- [ ] Create .github/workflows/maven-test.yml with matrix testing for Java 8, 11, 17, and 21
- [ ] Configure workflow to run 'mvn clean test' and 'mvn verify' on push and pull requests
- [ ] Add code coverage reporting (JaCoCo plugin to pom.xml) and upload to Codecov or Codacy
- [ ] Create .github/workflows/maven-publish.yml for automated snapshot/release publishing to Maven Central
Add missing unit tests for geometry and filter transformation classes
The geometry package (Position, Positions, Region, Coordinate, AbsoluteSize, RelativeSize) and filters package (Canvas, Caption, Rotation, Flip, Watermark, Pipeline) contain transformation logic that lacks visible test coverage. These are foundational to correct image manipulation. Tests would validate coordinate calculations, rotation angles, watermark positioning, and filter chaining behavior.
- [ ] Create src/test/java/net/coobird/thumbnailator/geometry/ and add tests for Positions.java (all predefined positions), Region.java boundary calculations, and Coordinate.java transformations
- [ ] Create src/test/java/net/coobird/thumbnailator/filters/ and add tests for Rotation.java (0°, 90°, 180°, 270°), Flip.java (HORIZONTAL, VERTICAL), and Canvas.java positioning
- [ ] Add tests for Pipeline.java to verify filter composition and ordering produce expected results
- [ ] Add tests for Watermark.java and Caption.java positioning with various canvas sizes
🌿Good first issues
- Add comprehensive unit tests for the
geometry/package (Region.java, Coordinate.java, Positions.java): currently no test files visible in the file list for these coordinate/sizing abstractions, which are critical for accurate crop and canvas operations. - Document all available ImageFilter subclasses and their parameter requirements in a new filters reference page or Javadoc enhancement: filters like Canvas, Watermark, and Caption exist but lack usage examples in the visible codebase.
- Implement a
NoOpResizeror caching layer inresizers/to optimize the case where input dimensions already match target size—currently no evidence of short-circuit logic when resize is unnecessary, potentially wasting CPU.
📝Recent commits
Click to expand
Recent commits
e31168c— Add contribution guidelines. (coobird)068d36e— Reword template to clarify policy for pull requests. (coobird)c9d9961— Update README with release info for 0.4.21. (coobird)0670828— Update POM for 0.4.21 release. (coobird)9c75e97— Merge branch 'develop' (coobird)113a502— Update LICENSE years. (coobird)f706c62— Merge branch 'bugfix-issue225' into develop (coobird)4e7e1d2— Update Maven Central Repository publishing method. (coobird)36a5829— Rename test class to be recognized by surefire plugin. (coobird)1462ec5— Clarify comments. (coobird)
🔒Security observations
The Thumbnailator codebase has significant security concerns primarily related to outdated build tooling and Java version targeting. The project uses Java 1.5 (EOL 2008) with Maven plugins from 2010-2014, creating a risk environment for known vulnerabilities. Additional architectural risks include insufficient validation in file path handling, URL-based image loading without SSRF protection, and missing input bounds checking on image dimensions. While the library itself appears to be open-source and moderately well-structured, the security posture is substantially weakened by legacy dependencies and outdated compilation targets. Immediate action required: upgrade Java version to 11+ LTS, update all Maven plugins, and implement input validation across file/URL operations.
- High · Outdated Maven Compiler Plugin —
pom.xml - maven-compiler-plugin dependency. The pom.xml uses maven-compiler-plugin version 2.3.2 (released 2010), which is significantly outdated and may contain security vulnerabilities. This plugin is responsible for compiling Java source code. Fix: Update to the latest stable version of maven-compiler-plugin (3.11.0 or later). Also consider updating Java source/target from 1.5 to a modern, supported version (11 or later). - High · Outdated Maven Javadoc Plugin —
pom.xml - maven-javadoc-plugin dependency. The pom.xml uses maven-javadoc-plugin version 2.10.1 (released 2014), which is outdated and may have unpatched security issues in dependency resolution and XML processing. Fix: Update to the latest stable version of maven-javadoc-plugin (3.6.0 or later). - High · Obsolete Java Version Target —
pom.xml - compiler configuration (source=1.5, target=1.5). The project targets Java 1.5 (Java 5, released 2004), which is no longer supported and lacks critical security patches. This ancient version is vulnerable to numerous known exploits and lacks modern security features. Fix: Update source and target to at least Java 11 (LTS) or Java 17+ (current LTS). Java 5 reached end-of-life over 15 years ago. - Medium · Potential Path Traversal in File Operations —
src/main/java/net/coobird/thumbnailator/tasks/io/FileImageSource.java, FileImageSink.java, FileThumbnailTask.java. The library handles file operations (FileImageSource, FileImageSink, FileThumbnailTask) without explicit path validation visible in the provided file structure. User-supplied file paths could potentially be exploited for directory traversal attacks. Fix: Implement strict path validation using Path.normalize() and verify resolved paths are within expected directories. Use java.nio.file.Path API for safer path handling. - Medium · URL-Based Image Loading Without Validation —
src/main/java/net/coobird/thumbnailator/tasks/io/URLImageSource.java. The URLImageSource class loads images from URLs without visible validation. This could be exploited for SSRF (Server-Side Request Forgery) attacks to access internal resources or malicious external content. Fix: Implement URL validation: whitelist allowed protocols (https only), validate against internal IP ranges, implement timeouts, and validate content-type headers before processing. - Medium · No Visible Input Validation on Image Dimensions —
src/main/java/net/coobird/thumbnailator/geometry/AbsoluteSize.java, RelativeSize.java. The geometry classes (AbsoluteSize, RelativeSize) handle image dimensions without visible bounds checking. Large dimension values could cause memory exhaustion or integer overflow attacks. Fix: Implement reasonable maximum dimension limits, validate integer overflow conditions, and implement memory limits for thumbnail generation operations. - Medium · Insufficient Dependency Management —
pom.xml - dependencies section. The pom.xml shows no explicit management of transitive dependencies from Image I/O and other Java standard library classes. No dependency lock file or dependency-check integration is visible. Fix: Add dependency-check plugin integration, use dependency management sections, pin transitive dependency versions, and regularly audit dependencies.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.