89 lines
4.5 KiB
Plaintext
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";
|