mcap/tools/image_probe.jai

89 lines
4.5 KiB
Plaintext

// image-probe: what modules/Image_Decode makes of image and video files. For each FILE, its kind, EXIF and the
// decoded size; with -out FOLDER, the decoded image (turned the right way up) and its .mcap preview
// written there as PNGs, to look at.
//
// Build: jai first.jai - image_probe Run: bin/image-probe FILE... [-out FOLDER]
main :: () {
args := get_command_line_arguments();
files: [..] string;
out_folder: string;
i := 1;
while i < args.count {
if args[i] == "-out" && i + 1 < args.count { out_folder = args[i + 1]; i += 2; continue; }
array_add(*files, args[i]);
i += 1;
}
if !files.count { print("Usage: image-probe FILE... [-out FOLDER]\n"); exit(2); }
if out_folder make_directory_if_it_does_not_exist(out_folder, recursive = true);
failures := 0;
for path: files {
// A video: what video_poster finds, and its poster frame.
head: [256] u8;
head_count := 0;
file, opened := file_open(path, log_errors = false);
if opened {
_, head_count = file_read(file, head.data, head.count);
file_close(*file);
}
head_view := array_view(head, 0, head_count);
if image_kind(head_view) == .VIDEO || array_find(string.["mts", "m2ts", "ts"], to_lower_copy(path_extension(path),, temp)) {
start := current_time_monotonic();
image, info, decoded, error := video_poster(path);
print("%\n video, %\n", path, video_format_name(head_view, path));
if !decoded { print(" cannot decode: %\n", error); failures += 1; continue; }
print(" % x % as shown, % s, % fps, %, rotation %, audio %; poster at % s, in % ms\n", info.width, info.height, FF(info.duration, 2), FF(info.frame_rate, 2), info.codec, info.rotation, info.has_audio, FF(info.poster_time, 2), FF(to_float64_seconds(current_time_monotonic() - start) * 1000, 1));
print(" creationdate \"%\", creation_time \"%\", make \"%\", model \"%\", software \"%\", location \"%\"\n", info.creation_date, info.creation_time, info.make, info.model, info.software, info.location);
if out_folder {
name := path_strip_extension(path_filename(path));
stbi_write_png(temp_c_string(tprint("%/%.poster.png", out_folder, name)), image.width, image.height, 4, image.pixels, image.width * 4);
print(" wrote %/%.poster.png\n", out_folder, name);
}
image_free(*image);
reset_temporary_storage();
continue;
}
data, ok := read_entire_file(path, log_errors = false);
if !ok { print("%: cannot be read\n", path); failures += 1; continue; }
bytes := cast([] u8) data;
kind := image_kind_from_name(image_kind(bytes), path);
exif := exif_read(bytes, kind);
print("%\n kind %, % bytes\n", path, image_kind_name(kind), bytes.count);
if kind == .GIF {
frames, duration_ms := gif_info(bytes);
print(" GIF: % frames, % ms\n", frames, duration_ms);
}
if exif.found {
print(" EXIF: orientation %, date \"%\" %, make \"%\", model \"%\", software \"%\"\n", exif.orientation, exif.date_original, exif.offset_original, exif.make, exif.model, exif.software);
if exif.has_gps print(" GPS: %, %, % m\n", exif.latitude, exif.longitude, exif.altitude);
}
if kind == .HEIF || kind == .AVIF {
heif := heif_info(bytes);
print(" container: % x %, irot %, imir %, Exif item % bytes\n", heif.width, heif.height, heif.rotation, heif.mirror, heif.exif.count);
}
start := current_time_monotonic();
image, decoded, error := image_decode(bytes, kind);
if !decoded { print(" cannot decode: %\n", error); failures += 1; continue; }
print(" decoded: % x % in % ms (%)\n", image.width, image.height, FF(to_float64_seconds(current_time_monotonic() - start) * 1000, 1), ifx image.from_stb then "stb_image" else "WIC, ImageIO or turned");
if out_folder {
name := path_strip_extension(path_filename(path));
full := stbi_write_png(temp_c_string(tprint("%/%.png", out_folder, name)), image.width, image.height, 4, image.pixels, image.width * 4);
png, w, h, preview_ok, preview_error := image_preview_png(image, 320);
if preview_ok write_entire_file(tprint("%/%.preview.png", out_folder, name), png.data, png.count);
print(" wrote %/%.png%\n", out_folder, name, ifx preview_ok then tprint(" and a % x % preview", w, h) else tprint("; no preview: %", preview_error));
}
image_free(*image);
reset_temporary_storage();
}
exit(xx ifx failures then 1 else 0);
}
#import "Basic";
#import "String";
#import "File";
#import "Image_Decode";
#import "stb_image_write";