Image Format Converter (java, written by Codex)
envgap__codex__java-t1-18
Written by a coding agent; not on GitHubWritten 2026-03-03
01 / FAILURE SIGNATURE
As the study recorded it
No compression type set - WebP ImageWriter requires compression type
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
codex/java-t1 #18 · read the task the agent was given
Codex 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.
pom.xml
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.tmlr</groupId>
<artifactId>image-format-converter</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-core</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-jpeg</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-bmp</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-tiff</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>org.sejda.imageio</groupId>
<artifactId>webp-imageio</artifactId>
<version>0.1.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<release>17</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<archive>
<manifest>
<mainClass>ImageFormatConverter</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
README.md
# Image Format Converter (Java) Converts images among PNG/JPEG/BMP/TIFF/WebP with quality, resize, alpha handling, batch mode, and sample demo generation. ## Requirements - Ubuntu 22.04 - JDK 17+ - Maven 3.8+ ## Dependencies (Pinned) - TwelveMonkeys ImageIO: - `imageio-core:3.11.0` - `imageio-jpeg:3.11.0` - `imageio-bmp:3.11.0` - `imageio-tiff:3.11.0` - WebP plugin: - `org.sejda.imageio:webp-imageio:0.1.6` ## Build ```bash mvn clean package ``` ## Run ```bash java -jar target/image-format-converter-1.0.0.jar input.png webp --quality 90 java -jar target/image-format-converter-1.0.0.jar input.png jpeg --background "#ffffff" --resize 800x600 --maintain-aspect true java -jar target/image-format-converter-1.0.0.jar input.webp png --strip-metadata java -jar target/image-format-converter-1.0.0.jar ./images jpeg --batch --filter png --quality 80 java -jar target/image-format-converter-1.0.0.jar ``` ## Features - PNG/JPEG/BMP/TIFF/WebP conversion - Quality control for lossy outputs - Resize with optional aspect preservation - Alpha flattening with configurable background for non-alpha targets - Batch conversion with optional input-format filter - Conversion details output - Output path override with `--output` - No-args sample image generation + conversion comparison
src/main/java/ImageFormatConverter.java
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
public final class ImageFormatConverter {
private static final Set<String> SUPPORTED = Set.of("png", "jpeg", "jpg", "bmp", "tiff", "webp");
private record ParsedArgs(Map<String, String> options, List<String> positional) {}
private ImageFormatConverter() {}
public static void main(String[] args) {
try {
ParsedArgs parsed = parseArgs(args);
if (parsed.positional.isEmpty() && !parsed.options.containsKey("batch")) {
runDemo();
return;
}
if (parsed.options.containsKey("batch")) {
if (parsed.positional.size() < 2) throw new IllegalArgumentException("Batch mode: <directory> <target-format>");
String dir = parsed.positional.get(0);
String target = normalizeFormat(parsed.positional.get(1));
batchConvert(Paths.get(dir).toAbsolutePath(), target, parsed.options);
return;
}
if (parsed.positional.size() < 2) throw new IllegalArgumentException("Usage: <input-image> <target-format>");
ConversionDetails d = convertOne(Paths.get(parsed.positional.get(0)).toAbsolutePath(), normalizeFormat(parsed.positional.get(1)), parsed.options);
printDetails(d);
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
System.exit(1);
}
}
private static ParsedArgs parseArgs(String[] args) {
Map<String, String> options = new HashMap<>();
List<String> positional = new ArrayList<>();
for (int i = 0; i < args.length; i++) {
String t = args[i];
if (t.startsWith("--")) {
String k = t.substring(2);
if (i + 1 < args.length && !args[i + 1].startsWith("--")) options.put(k, args[++i]);
else options.put(k, "true");
} else positional.add(t);
}
return new ParsedArgs(options, positional);
}
private static String normalizeFormat(String raw) {
String f = raw.toLowerCase();
if ("jpg".equals(f)) f = "jpeg";
if (!SUPPORTED.contains(f)) throw new IllegalArgumentException("Unsupported format: " + raw);
return f;
}
private static record Size(int w, int h) {}
private static Size parseResize(String s) {
if (s == null || s.isBlank()) return null;
String[] p = s.toLowerCase().split("x", 2);
if (p.length != 2) throw new IllegalArgumentException("Invalid --resize. Use WxH.");
return new Size(Integer.parseInt(p[0]), Integer.parseInt(p[1]));
}
private static boolean boolOpt(Map<String, String> options, String key, boolean def) {
if (!options.containsKey(key)) return def;
String v = options.get(key).toLowerCase();
return !(v.equals("false") || v.equals("0") || v.equals("no"));
}
private static Path outputPath(Path input, String target, String explicit) {
if (explicit != null) return Paths.get(explicit).toAbsolutePath();
String base = input.getFileName().toString();
int dot = base.lastIndexOf('.');
if (dot >= 0) base = base.substring(0, dot);
return input.getParent().resolve(base + "." + target);
}
private static BufferedImage resize(BufferedImage src, Size s, boolean maintainAspect) {
int tw = s.w;
int th = s.h;
if (maintainAspect) {
double scale = Math.min((double) tw / src.getWidth(), (double) th / src.getHeight());
tw = Math.max(1, (int) Math.round(src.getWidth() * scale));
th = Math.max(1, (int) Math.round(src.getHeight() * scale));
}
BufferedImage out = new BufferedImage(tw, th, src.getColorModel().hasAlpha() ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
Graphics2D g = out.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g.drawImage(src, 0, 0, tw, th, null);
g.dispose();
return out;
}
private static BufferedImage flatten(BufferedImage src, Color bg) {
BufferedImage out = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g = out.createGraphics();
g.setColor(bg);
g.fillRect(0, 0, src.getWidth(), src.getHeight());
g.drawImage(src, 0, 0, null);
g.dispose();
return out;
}
private static Color parseColor(String raw) {
if (raw == null || raw.isBlank() || raw.equalsIgnoreCase("white")) return Color.WHITE;
if (raw.startsWith("#")) return Color.decode(raw);
return Color.WHITE;
}
private static record ConversionDetails(
Path input, Path output, String inputFormat, String outputFormat,
String originalDimensions, String newDimensions,
long sizeBefore, long sizeAfter, double compressionRatio
) {}
private static ConversionDetails convertOne(Path input, String target, Map<String, String> options) throws Exception {
int quality = Integer.parseInt(options.getOrDefault("quality", "85"));
if (quality < 1 || quality > 100) throw new IllegalArgumentException("Quality must be in range 1..100.");
Size r = parseResize(options.get("resize"));
boolean maintain = boolOpt(options, "maintain-aspect", true);
Color background = parseColor(options.getOrDefault("background", "white"));
Path output = outputPath(input, target, options.get("output"));
BufferedImage img = ImageIO.read(input.toFile());
if (img == null) throw new IllegalArgumentException("Unsupported/corrupted input image: " + input);
String inFmt = normalizeFormat(extension(input));
int ow = img.getWidth();
int oh = img.getHeight();
BufferedImage working = img;
if (r != null) working = resize(working, r, maintain);
if ((target.equals("jpeg") || target.equals("bmp")) && working.getColorModel().hasAlpha()) {
working = flatten(working, background);
}
Files.createDirectories(output.getParent());
writeImage(working, output.toFile(), target, quality);
long before = Files.size(input);
long after = Files.size(output);
return new ConversionDetails(
input, output, inFmt, target,
ow + "x" + oh, working.getWidth() + "x" + working.getHeight(),
before, after, before == 0 ? 1.0 : ((double) after / before)
);
}
private static void writeImage(BufferedImage img, File outFile, String format, int quality) throws Exception {
Iterator<ImageWriter> it = ImageIO.getImageWritersByFormatName(format);
if (!it.hasNext()) throw new IllegalArgumentException("No writer for format: " + format);
ImageWriter writer = it.next();
try (ImageOutputStream ios = ImageIO.createImageOutputStream(outFile)) {
writer.setOutput(ios);
ImageWriteParam param = writer.getDefaultWriteParam();
if ((format.equals("jpeg") || format.equals("webp")) && param.canWriteCompressed()) {
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(Math.max(0.01f, Math.min(1f, quality / 100f)));
}
writer.write(null, new IIOImage(img, null, null), param);
} finally {
writer.dispose();
}
}
private static String extension(Path p) {
String s = p.getFileName().toString();
int dot = s.lastIndexOf('.');
return dot >= 0 ? s.substring(dot + 1) : "png";
}
private static void printDetails(ConversionDetails d) {
System.out.println("Input: " + d.input);
System.out.println("Output: " + d.output);
System.out.println("Format: " + d.inputFormat + " -> " + d.outputFormat);
System.out.println("Dimensions: " + d.originalDimensions + " -> " + d.newDimensions);
System.out.println("Size: " + d.sizeBefore + " -> " + d.sizeAfter + " bytes");
System.out.printf("Compression ratio: %.4f%n%n", d.compressionRatio);
}
private static void batchConvert(Path dir, String target, Map<String, String> options) throws Exception {
String filter = options.containsKey("filter") ? normalizeFormat(options.get("filter")) : null;
File[] files = dir.toFile().listFiles();
if (files == null) throw new IllegalArgumentException("Invalid directory: " + dir);
for (File f : files) {
if (!f.isFile()) continue;
String ext = normalizeFormat(extension(f.toPath()));
if (filter != null && !ext.equals(filter)) continue;
Map<String, String> per = new HashMap<>(options);
per.remove("output");
ConversionDetails d = convertOne(f.toPath(), target, per);
printDetails(d);
}
}
private static void runDemo() throws Exception {
Path sample = Paths.get("sample_800x600.png").toAbsolutePath();
BufferedImage img = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = img.createGraphics();
GradientPaint gp = new GradientPaint(0, 0, new Color(255, 138, 0), 800, 600, new Color(47, 91, 234));
g.setPaint(gp);
g.fillRect(0, 0, 800, 600);
g.setColor(new Color(255, 255, 255, 100));
g.fillOval(80, 80, 300, 300);
g.setColor(new Color(0, 0, 0, 100));
g.fillRoundRect(430, 140, 220, 220, 24, 24);
g.setColor(Color.WHITE);
g.setFont(new Font("SansSerif", Font.BOLD, 34));
g.drawString("Image Converter Demo", 190, 560);
g.dispose();
ImageIO.write(img, "png", sample.toFile());
System.out.println("format,orig_dim,new_dim,size_before,size_after,ratio");
for (String fmt : List.of("jpeg", "bmp", "tiff", "webp")) {
ConversionDetails d = convertOne(sample, fmt, new HashMap<>(Map.of("quality", "85", "background", "white", "maintain-aspect", "true")));
System.out.printf("%s,%s,%s,%d,%d,%.4f%n",
d.outputFormat, d.originalDimensions, d.newDimensions, d.sizeBefore, d.sizeAfter, d.compressionRatio);
}
}
}