Image Format Converter (java, written by Claude Code)
envgap__claude-code__java-t1-18
Written by a coding agent; not on GitHubWritten 2026-02-27
01 / FAILURE SIGNATURE
As the study recorded it
cannot find symbol: class WebPImageWriterSpi + source in project root
Not a benchmark task.
- Its repair changed source code, so it is not an environment task.
02 / ENVIRONMENT RECIPE
- Base commit
Not freshly verified- Manifest
pom.xml- Reproduce
Awaiting issue-specific recipe- Run under trace
Awaiting a meaningful runtime command
03 / TASK AND FAILURE
claude-code/java-t1 #18 · read the task the agent was given
Claude Code wrote this java project from the task below. It does not run on a clean Ubuntu 22.04 machine as written. Task given to the agent: TASK: Image Format Converter Write a program that converts images between common formats (PNG, JPEG, BMP, TIFF, WebP) with configurable quality settings, preserving metadata where possible. FUNCTIONAL REQUIREMENTS: - Accept an image file path and target format as command-line arguments - Support conversions between: PNG, JPEG, BMP, TIFF, and WebP formats - Support a --quality flag for lossy formats (JPEG, WebP) with a value from 1-100 (default: 85) - Support a --resize flag to resize during conversion using WxH syntax (e.g., --resize 800x600), preserving aspect ratio by default - Support --maintain-aspect flag (default true) to control whether resizing preserves the original aspect ratio by fitting within the specified dimensions - Preserve EXIF metadata during conversion where the target format supports it, with a --strip-metadata flag to optionally remove it - Support alpha channel handling: when converting from formats with transparency (PNG, WebP) to formats without (JPEG, BMP), use a configurable background color via --background flag (default: white) - Support batch conversion of all images in a directory via --batch flag, optionally filtering by input format with --filter flag - Print conversion details to console: input format, output format, original dimensions, new dimensions, file size before and after, compression ratio - Save the converted image to a path specified by --output flag (default: same name with new extension) - If no input is given, generate a sample 800x600 PNG image with gradients, text, and transparency, then convert it to all other supported formats and display a comparison table - Handle errors: unsupported formats, corrupted images, insufficient disk space, invalid resize dimensions Create a complete Java project for a clean Ubuntu 22.04 machine with only JDK 17+ installed. Include: - Source code - pom.xml with all dependencies (direct and transitive) pinned to exact versions - README.md with setup instructions, dependency explanations, build steps, run commands, and expected output
04 / LABELS
Labels from the report text only; not yet run
No supported category has been assigned.
Label rules and the text that matched
[]
05 / FILES
The project as the agent wrote it
3 files, exactly as written, before any repair.
ImageConverter.java
import com.twelvemonkeys.imageio.plugins.webp.WebPImageReaderSpi;
import com.twelvemonkeys.imageio.plugins.webp.WebPImageWriterSpi;
import com.twelvemonkeys.imageio.plugins.tiff.TIFFImageReaderSpi;
import com.twelvemonkeys.imageio.plugins.tiff.TIFFImageWriterSpi;
import javax.imageio.*;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Image Format Converter supporting PNG, JPEG, BMP, TIFF, and WebP.
* Provides quality settings, resize, and metadata preservation.
*/
public class ImageConverter {
private static final Set<String> SUPPORTED_EXTENSIONS = Set.of(
"png", "jpg", "jpeg", "bmp", "tiff", "tif", "webp"
);
private static final Map<String, String> EXTENSION_TO_FORMAT = Map.of(
"png", "PNG",
"jpg", "JPEG",
"jpeg", "JPEG",
"bmp", "BMP",
"tiff", "TIFF",
"tif", "TIFF",
"webp", "WebP"
);
/**
* Result object returned after conversion.
*/
public static class ConversionResult {
private final String outputPath;
private final long fileSizeBytes;
private final int width;
private final int height;
private final String format;
public ConversionResult(String outputPath, long fileSizeBytes, int width, int height, String format) {
this.outputPath = outputPath;
this.fileSizeBytes = fileSizeBytes;
this.width = width;
this.height = height;
this.format = format;
}
public String getOutputPath() { return outputPath; }
public long getFileSizeBytes() { return fileSizeBytes; }
public int getWidth() { return width; }
public int getHeight() { return height; }
public String getFormat() { return format; }
@Override
public String toString() {
return String.format("ConversionResult{path='%s', format='%s', %dx%d, %,d bytes}",
outputPath, format, width, height, fileSizeBytes);
}
}
/**
* Options for image conversion.
*/
public static class ConversionOptions {
private int quality = 85;
private int resizeWidth = -1;
private int resizeHeight = -1;
private boolean preserveMetadata = true;
private boolean verbose = false;
public ConversionOptions() {}
public ConversionOptions quality(int quality) {
this.quality = Math.max(1, Math.min(100, quality));
return this;
}
public ConversionOptions resize(int width, int height) {
this.resizeWidth = width;
this.resizeHeight = height;
return this;
}
public ConversionOptions preserveMetadata(boolean preserve) {
this.preserveMetadata = preserve;
return this;
}
public ConversionOptions verbose(boolean verbose) {
this.verbose = verbose;
return this;
}
public int getQuality() { return quality; }
public int getResizeWidth() { return resizeWidth; }
public int getResizeHeight() { return resizeHeight; }
public boolean isPreserveMetadata() { return preserveMetadata; }
public boolean isVerbose() { return verbose; }
}
/**
* Get the file extension in lowercase.
*/
private static String getExtension(String filename) {
int lastDot = filename.lastIndexOf('.');
if (lastDot < 0) {
return "";
}
return filename.substring(lastDot + 1).toLowerCase();
}
/**
* Get the format name from a file extension.
*/
private static String getFormatFromExtension(String filename) {
String ext = getExtension(filename);
String format = EXTENSION_TO_FORMAT.get(ext);
if (format == null) {
throw new IllegalArgumentException("Unsupported format: " + ext
+ ". Supported: " + SUPPORTED_EXTENSIONS);
}
return format;
}
/**
* Convert a single image file.
*
* @param inputPath Path to the source image.
* @param outputPath Path for the converted image.
* @param options Conversion options.
* @return ConversionResult with details about the output.
* @throws IOException If reading or writing fails.
*/
public static ConversionResult convert(String inputPath, String outputPath,
ConversionOptions options) throws IOException {
File inputFile = new File(inputPath);
if (!inputFile.exists()) {
throw new IOException("Input file not found: " + inputPath);
}
String outputFormat = getFormatFromExtension(outputPath);
if (options.isVerbose()) {
System.out.println("Opening: " + inputPath);
}
// Read image with metadata
ImageInputStream iis = ImageIO.createImageInputStream(inputFile);
Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
if (!readers.hasNext()) {
iis.close();
throw new IOException("No suitable image reader found for: " + inputPath);
}
ImageReader reader = readers.next();
reader.setInput(iis);
// Read metadata
IIOMetadata metadata = null;
if (options.isPreserveMetadata()) {
try {
metadata = reader.getImageMetadata(0);
} catch (Exception e) {
if (options.isVerbose()) {
System.out.println("Warning: Could not read metadata: " + e.getMessage());
}
}
}
BufferedImage image = reader.read(0);
reader.dispose();
iis.close();
if (options.isVerbose()) {
System.out.println("Original size: " + image.getWidth() + "x" + image.getHeight());
System.out.println("Original type: " + image.getType());
}
// Resize if requested
if (options.getResizeWidth() > 0 && options.getResizeHeight() > 0) {
image = resizeImage(image, options.getResizeWidth(), options.getResizeHeight());
if (options.isVerbose()) {
System.out.println("Resized to: " + options.getResizeWidth() + "x" + options.getResizeHeight());
}
}
// Handle JPEG compatibility (no alpha channel)
if ("JPEG".equals(outputFormat) && image.getColorModel().hasAlpha()) {
BufferedImage rgbImage = new BufferedImage(
image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = rgbImage.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, image.getWidth(), image.getHeight());
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
image = rgbImage;
if (options.isVerbose()) {
System.out.println("Converted to RGB for JPEG compatibility.");
}
}
// Ensure output directory exists
File outputFile = new File(outputPath);
if (outputFile.getParentFile() != null) {
outputFile.getParentFile().mkdirs();
}
// Write image
writeImage(image, outputFile, outputFormat, options, metadata);
long fileSize = outputFile.length();
if (options.isVerbose()) {
System.out.println("Saved: " + outputFile.getAbsolutePath());
System.out.printf("Output file size: %,d bytes%n", fileSize);
}
return new ConversionResult(
outputFile.getAbsolutePath(),
fileSize,
image.getWidth(),
image.getHeight(),
outputFormat
);
}
/**
* Write an image to a file with the specified format and options.
*/
private static void writeImage(BufferedImage image, File outputFile, String format,
ConversionOptions options, IIOMetadata metadata) throws IOException {
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(format);
if (!writers.hasNext()) {
throw new IOException("No suitable image writer found for format: " + format);
}
ImageWriter writer = writers.next();
ImageWriteParam writeParam = writer.getDefaultWriteParam();
// Set quality for lossy formats
if ("JPEG".equals(format) || "WebP".equals(format)) {
if (writeParam.canWriteCompressed()) {
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
String[] compressionTypes = writeParam.getCompressionTypes();
if (compressionTypes != null && compressionTypes.length > 0) {
writeParam.setCompressionType(compressionTypes[0]);
}
writeParam.setCompressionQuality(options.getQuality() / 100.0f);
}
}
ImageOutputStream ios = ImageIO.createImageOutputStream(outputFile);
writer.setOutput(ios);
IIOMetadata outputMetadata = null;
if (options.isPreserveMetadata() && metadata != null) {
try {
outputMetadata = writer.convertImageMetadata(metadata, ImageTypeSpecifier.createFromRenderedImage(image), writeParam);
} catch (Exception e) {
if (options.isVerbose()) {
System.out.println("Warning: Could not convert metadata: " + e.getMessage());
}
}
}
IIOImage iioImage = new IIOImage(image, null, outputMetadata);
writer.write(null, iioImage, writeParam);
writer.dispose();
ios.close();
}
/**
* Resize an image using high-quality bilinear interpolation.
*/
private static BufferedImage resizeImage(BufferedImage original, int targetWidth, int targetHeight) {
BufferedImage resized = new BufferedImage(targetWidth, targetHeight, original.getType());
Graphics2D g2d = resized.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawImage(original, 0, 0, targetWidth, targetHeight, null);
g2d.dispose();
return resized;
}
/**
* Batch convert all supported images in a directory.
*
* @param inputDir Path to the source directory.
* @param outputDir Path to the output directory.
* @param targetFormat Target file extension (e.g., "png", "jpg").
* @param options Conversion options.
* @return List of ConversionResult objects.
* @throws IOException If directory access fails.
*/
public static List<ConversionResult> batchConvert(String inputDir, String outputDir,
String targetFormat, ConversionOptions options) throws IOException {
Path inputPath = Paths.get(inputDir);
if (!Files.isDirectory(inputPath)) {
throw new IOException("Input directory not found: " + inputDir);
}
Files.createDirectories(Paths.get(outputDir));
String targetExt = targetFormat.startsWith(".") ? targetFormat.substring(1) : targetFormat;
if (!SUPPORTED_EXTENSIONS.contains(targetExt.toLowerCase())) {
throw new IllegalArgumentException("Unsupported target format: " + targetExt);
}
List<ConversionResult> results = new ArrayList<>();
try (Stream<Path> stream = Files.list(inputPath)) {
List<Path> files = stream
.filter(Files::isRegularFile)
.filter(p -> SUPPORTED_EXTENSIONS.contains(getExtension(p.getFileName().toString())))
.sorted()
.collect(Collectors.toList());
for (Path file : files) {
String baseName = file.getFileName().toString();
int dotIndex = baseName.lastIndexOf('.');
if (dotIndex > 0) {
baseName = baseName.substring(0, dotIndex);
}
String outputFileName = baseName + "." + targetExt;
String outputFilePath = Paths.get(outputDir, outputFileName).toString();
try {
ConversionResult result = convert(file.toString(), outputFilePath, options);
results.add(result);
} catch (Exception e) {
System.err.println("Error converting " + file.getFileName() + ": " + e.getMessage());
}
}
}
return results;
}
/**
* Display image information.
*/
public static void printImageInfo(String filePath) throws IOException {
File file = new File(filePath);
if (!file.exists()) {
throw new IOException("File not found: " + filePath);
}
BufferedImage image = ImageIO.read(file);
if (image == null) {
throw new IOException("Could not read image: " + filePath);
}
System.out.println("File: " + file.getAbsolutePath());
System.out.println("Format: " + getFormatFromExtension(filePath));
System.out.println("Dimensions: " + image.getWidth() + "x" + image.getHeight());
System.out.println("Color model: " + image.getColorModel());
System.out.printf("File size: %,d bytes%n", file.length());
// Read metadata
ImageInputStream iis = ImageIO.createImageInputStream(file);
Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
if (readers.hasNext()) {
ImageReader reader = readers.next();
reader.setInput(iis);
try {
IIOMetadata meta = reader.getImageMetadata(0);
if (meta != null) {
String[] formatNames = meta.getMetadataFormatNames();
System.out.println("Metadata formats: " + String.join(", ", formatNames));
}
} catch (Exception e) {
System.out.println("Metadata: not available");
}
reader.dispose();
}
iis.close();
}
/**
* CLI entry point.
*/
public static void main(String[] args) {
if (args.length < 1) {
printUsage();
System.exit(1);
}
String command = args[0];
try {
switch (command) {
case "convert":
handleConvert(args);
break;
case "batch":
handleBatch(args);
break;
case "info":
handleInfo(args);
break;
default:
System.err.println("Unknown command: " + command);
printUsage();
System.exit(1);
}
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
System.exit(1);
}
}
private static void handleConvert(String[] args) throws IOException {
if (args.length < 3) {
System.err.println("Usage: convert <input> <output> [options]");
System.exit(1);
}
String input = args[1];
String output = args[2];
ConversionOptions options = parseOptions(args, 3);
ConversionResult result = convert(input, output, options);
System.out.println("Converted successfully: " + result);
}
private static void handleBatch(String[] args) throws IOException {
if (args.length < 4) {
System.err.println("Usage: batch <input_dir> <output_dir> <format> [options]");
System.exit(1);
}
String inputDir = args[1];
String outputDir = args[2];
String format = args[3];
ConversionOptions options = parseOptions(args, 4);
List<ConversionResult> results = batchConvert(inputDir, outputDir, format, options);
System.out.println("Batch conversion complete. " + results.size() + " file(s) converted.");
}
private static void handleInfo(String[] args) throws IOException {
if (args.length < 2) {
System.err.println("Usage: info <file>");
System.exit(1);
}
printImageInfo(args[1]);
}
private static ConversionOptions parseOptions(String[] args, int startIndex) {
ConversionOptions options = new ConversionOptions();
for (int i = startIndex; i < args.length; i++) {
switch (args[i]) {
case "-q":
case "--quality":
if (i + 1 < args.length) {
options.quality(Integer.parseInt(args[++i]));
}
break;
case "-r":
case "--resize":
if (i + 1 < args.length) {
String[] parts = args[++i].toLowerCase().split("x");
options.resize(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]));
}
break;
case "--no-metadata":
options.preserveMetadata(false);
break;
case "-v":
case "--verbose":
options.verbose(true);
break;
}
}
return options;
}
private static void printUsage() {
System.out.println("Image Format Converter");
System.out.println();
System.out.println("Commands:");
System.out.println(" convert <input> <output> [options] Convert a single image");
System.out.println(" batch <indir> <outdir> <fmt> [options] Batch convert directory");
System.out.println(" info <file> Display image info");
System.out.println();
System.out.println("Options:");
System.out.println(" -q, --quality <1-100> Quality setting (default: 85)");
System.out.println(" -r, --resize <WxH> Resize (e.g., 800x600)");
System.out.println(" --no-metadata Strip metadata");
System.out.println(" -v, --verbose Verbose output");
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.imageconverter</groupId>
<artifactId>image-format-converter</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>Image Format Converter</name>
<description>Converts between PNG, JPEG, BMP, TIFF, and WebP with quality settings, resize, and metadata preservation.</description>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<twelvemonkeys.version>3.10.1</twelvemonkeys.version>
</properties>
<dependencies>
<!-- TwelveMonkeys ImageIO - TIFF support -->
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-tiff</artifactId>
<version>${twelvemonkeys.version}</version>
</dependency>
<!-- TwelveMonkeys ImageIO - WebP support -->
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-webp</artifactId>
<version>${twelvemonkeys.version}</version>
</dependency>
<!-- TwelveMonkeys ImageIO - BMP enhancements -->
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-bmp</artifactId>
<version>${twelvemonkeys.version}</version>
</dependency>
<!-- TwelveMonkeys ImageIO - JPEG enhancements -->
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-jpeg</artifactId>
<version>${twelvemonkeys.version}</version>
</dependency>
<!-- TwelveMonkeys ImageIO - Core -->
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-core</artifactId>
<version>${twelvemonkeys.version}</version>
</dependency>
<!-- TwelveMonkeys ImageIO - Metadata -->
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-metadata</artifactId>
<version>${twelvemonkeys.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<mainClass>ImageConverter</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>ImageConverter</mainClass>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
README.md
# Image Format Converter (Java - javax.imageio + TwelveMonkeys) An image format converter that supports PNG, JPEG, BMP, TIFF, and WebP formats with quality settings, resize capabilities, and metadata preservation. ## Dependencies - **javax.imageio** (JDK built-in) - Core Java Image I/O framework - **TwelveMonkeys ImageIO 3.10.1** - Extended format support for TIFF, WebP, and enhanced JPEG/BMP handling ## Build ```bash mvn clean package ``` ## Usage ### Convert a single image ```bash java -jar target/image-format-converter-1.0.0.jar convert input.png output.jpg java -jar target/image-format-converter-1.0.0.jar convert input.bmp output.webp -q 90 java -jar target/image-format-converter-1.0.0.jar convert input.tiff output.png -r 800x600 java -jar target/image-format-converter-1.0.0.jar convert input.jpg output.tiff --no-metadata -v ``` ### Batch convert images ```bash java -jar target/image-format-converter-1.0.0.jar batch ./input_dir ./output_dir png java -jar target/image-format-converter-1.0.0.jar batch ./photos ./thumbnails jpg -q 75 -r 200x200 ``` ### Display image information ```bash java -jar target/image-format-converter-1.0.0.jar info photo.jpg ``` ## Options | Option | Description | |--------|-------------| | `-q, --quality` | Quality setting (1-100, default: 85) | | `-r, --resize` | Resize to WIDTHxHEIGHT (e.g., 800x600) | | `--no-metadata` | Strip metadata from output | | `-v, --verbose` | Print detailed conversion information | ## Supported Formats | Format | Read | Write | Notes | |--------|------|-------|-------| | PNG | Yes | Yes | Via JDK built-in | | JPEG | Yes | Yes | Enhanced via TwelveMonkeys | | BMP | Yes | Yes | Enhanced via TwelveMonkeys | | TIFF | Yes | Yes | Via TwelveMonkeys | | WebP | Yes | Yes | Via TwelveMonkeys |