RosettaCodeData/Task/Bitmap-PPM-conversion-throu.../ATS/bitmap-ppm-conversion-throu...

118 lines
3.5 KiB
Plaintext

(* This program uses ImageMagick to convert an image, with the target
file specified according to the conventions of ImageMagick. That
allows such things as "gif:foobar.jpg" to mean a GIF named
"foobar.jpg". But, if you leave out the "gif:" prefix, ImageMagick
will make a JPEG. (I notice that one can also insert options to
magick, although this was an unexpected result of my design.) *)
(*
##myatsccdef=\
patscc -std=gnu2x -g -O2 -DATS_MEMALLOC_LIBC \
-o $fname($1) $1 \
bitmap{,_{read,write}_ppm}_task.{s,d}ats
*)
#include "share/atspre_staload.hats"
staload "bitmap_task.sats"
staload "bitmap_read_ppm_task.sats"
staload "bitmap_write_ppm_task.sats"
staload _ = "bitmap_task.dats"
staload _ = "bitmap_read_ppm_task.dats"
staload _ = "bitmap_write_ppm_task.dats"
(*------------------------------------------------------------------*)
(* There is support for pipe-I/O in libats/libc, but I cannot (at
least when in a hurry) figure out how it is supposed to be
used. So, as elsewhere in the "raster graphics operations"
category, what is not in the prelude itself I implement with the
foreign function interfaces. :) Using FFI is a typical part of ATS
programming, and one should get used to doing it.
Anyway, here is some UNSAFE support for pipe-I/O. *)
typedef charstar = $extype"char *"
typedef FILEstar = $extype"FILE *"
fn {}
fileref_popen_unsafe (command : string,
mode : string)
: Option_vt FILEref =
let
val p = $extfcall (ptr, "popen", $UNSAFE.cast{charstar} command,
$UNSAFE.cast{charstar} mode)
in
if iseqz p then
None_vt ()
else
Some_vt ($UNSAFE.cast{FILEref} p)
end
fn {}
fileref_pclose_unsafe (f : FILEref)
: int = (* Returns the exit status of the command. *)
$extfcall (int, "pclose", $UNSAFE.cast{FILEstar} f)
(*------------------------------------------------------------------*)
implement
main0 (argc, argv) =
let
val args = listize_argc_argv (argc, argv)
val nargs = length args
val inpf =
if nargs < 2 then
stdin_ref
else if args[1] = "-" then
stdin_ref
else
fileref_open_exn (args[1], file_mode_r)
val pix_opt = pixmap_read_ppm<rgb24> inpf
val () = fileref_close inpf
in
case+ pix_opt of
| ~ None_vt () =>
begin
free args;
println! ("For some reason, I failed to read the image.");
exit 1
end
| ~ Some_vt @(pfgc1 | pix1) =>
let
val outf_name = if nargs < 3 then "-" else args[2]
val command = string_append ("magick ppm:- ", outf_name)
val () = free args
val pipe_opt =
(* Temporarily treating a strptr as a string, just to make a
function call of this sort, is not actually unsafe. *)
fileref_popen_unsafe ($UNSAFE.strptr2string command, "w")
val () = free command
in
case+ pipe_opt of
| ~ None_vt () =>
begin
free (pfgc1 | pix1);
println! ("For some reason, I failed to open a pipe ",
"to magick.");
exit 3
end
| ~ Some_vt outf =>
let
val success = pixmap_write_ppm (outf, pix1)
in
ignoret (fileref_pclose_unsafe outf);
free (pfgc1 | pix1);
if ~success then
begin
println! ("For some reason, I failed to pipe the ",
"image to magick.");
exit 2
end
end
end
end