Bitmap/PPM conversion through a pipe: Difference between revisions

m
→‎{{header|Wren}}: Changed to Wren S/H
m (→‎{{header|Wren}}: Changed to Wren S/H)
 
(9 intermediate revisions by 5 users not shown)
Line 3:
Using the data storage type defined [[Basic_bitmap_storage|on this page]] for raster images, delegate writing a JPEG file through a '''pipe''' using the <tt>output_ppm</tt> function defined [[Write_ppm_file|on this other page]].
 
There are various utilities that can be used for this task, for example: '''cjpeg''' (package ''"jpeg-progs"'' on Linux, or ''"media-libs/libjpeg-turbo"'' on Gentoo), '''ppmtojpeg''' (package ''"netpbm"'' on Linux), '''convert''' (from ''ImageMagick'', multi-platform).
=={{header|ATS}}==
 
I use the <code>magick</code> command from ImageMagick. You need all the source files from [[Bitmap#ATS]], [[Bitmap/Read_a_PPM_file#ATS]], and [[Bitmap/Write_a_PPM_file#ATS]]. (You do ''not'' need the files from [[Grayscale_image#ATS]].)
 
See also [[Bitmap/Read_an_image_through_a_pipe#ATS]].
 
<syntaxhighlight lang="ats">
(* 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
</syntaxhighlight>
 
{{out}}
Using SIPI test image 5.1.12:
<pre>$ myatscc bitmap_write_through_pipe_task.dats
$ ./bitmap_write_through_pipe_task 5.1.12.ppm bitmap_write_through_pipe_task_ATS.jpg</pre>
[[File:Bitmap write through pipe task ATS.jpg|alt=An alarm clock on a book on a book, and a diptych of family portraits. On a table or chest of drawers or some such. Monochrome photograph.]]
 
=={{header|C}}==
Line 9 ⟶ 140:
This one uses the ImageMagick <tt>convert</tt> tool.
 
<langsyntaxhighlight lang="c">/* interface */
void print_jpg(image img, int qual);</langsyntaxhighlight>
 
<langsyntaxhighlight lang="c">#define MAXCMDBUF 100
void print_jpg(image img, int qual)
{
Line 28 ⟶ 159:
pclose(pipe);
}
}</langsyntaxhighlight>
 
The code that writes to the pipe is the same of [[Write_ppm_file|output_ppm]] of course. A complete example is
 
<langsyntaxhighlight lang="c">#include "imglib.h"
 
int main()
Line 43 ⟶ 174:
print_jpg(img, 75);
free_img(img);
}</langsyntaxhighlight>
 
In order to make it working, you must link it with the raster image functions given by the codes [[Bresenham's_line_algorithm#C|here]] and [[Basic_bitmap_storage#C|here]]
Line 50 ⟶ 181:
{{works with|Go weekly.2011-12-14}} (Go 1 should be close)
Using cjpeg:
<langsyntaxhighlight lang="go">package main
 
// Files required to build supporting package raster are found in:
Line 108 ⟶ 239:
fmt.Println(err)
}
}</langsyntaxhighlight>
 
=={{header|Julia}}==
{{works with|Julia|0.6}}
 
<langsyntaxhighlight lang="julia">using Images, FileIO
 
ppmimg = load("data/bitmapInputTest.ppm")
save("data/bitmapOutputTest.jpg", ppmimg)</langsyntaxhighlight>
 
=={{header|Kotlin}}==
{{works with|Ubuntu 16.04}}
In order to provide a complete runnable example, we repeat bits of code from other relevant tasks and add code which pipes .ppm data to ImageMagick's 'convert' tool which then writes the corresponding .jpg file to disk.
<langsyntaxhighlight lang="scala">// Version 1.2.40
 
import java.awt.Color
Line 176 ⟶ 305:
}
}
}</langsyntaxhighlight>
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
The Windows command line does not like quotes in the middle of text, so strings have been turned into character codes.
<langsyntaxhighlight Mathematicalang="mathematica">convert[image_,out_]:=Module[{process=StartProcess[{
"wolfram","-noinit","-noprompt","-run",
"Export[FromCharacterCode["~~ToString[ToCharacterCode[out]]~~"],ImportString[StringRiffle[Table[InputString[],{4}],FromCharacterCode[10]],FromCharacterCode[{80,80,77}]]]"
Line 186 ⟶ 314:
WriteLine[process,image];
WriteLine[process,"Quit[]"];
];</langsyntaxhighlight>
 
=={{header|Nim}}==
We use "convert" command from ImageMagick and "pnmtojpeg" command from Netpbm. The first command allows to specify the output file name, the second writes to stdout and, so, we have to use a redirection. Thus, the way to launch the process is slightly different.
 
<langsyntaxhighlight Nimlang="nim">import bitmap
import ppm_write
import osproc
Line 217 ⟶ 344:
stream = p.inputStream()
image.writePPM(stream)
p.close()</langsyntaxhighlight>
 
=={{Header|OCaml}}==
 
<langsyntaxhighlight lang="ocaml">let print_jpeg ~img ?(quality=96) () =
let cmd = Printf.sprintf "cjpeg -quality %d" quality in
(*
Line 235 ⟶ 362:
done
with End_of_file -> ()
;;</langsyntaxhighlight>
=={{header|Perl}}==
<syntaxhighlight lang="perl"># 20211224 Perl programming solution
 
use strict;
=={{header|Phix}}==
use warnings;
Uses the provided demo\rosetta\viewppm.exw utility to accomplish this task.
<lang Phix>-- demo\rosetta\Bitmap_PPM_conversion_through_a_pipe.exw
requires("0.8.4")
include builtins\pipeio.e
include builtins\serialize.e
include ppm.e -- read_ppm()
 
use Imager;
sequence pipes = repeat(0,3)
use Imager::Test 'test_image_raw';
pipes[PIPEIN] = create_pipe(INHERIT_WRITE)
 
my $img = test_image_raw();
-- Create the child process, with replacement stdin.
my $IO = Imager::io_new_bufchain();
string cmd = sprintf("%s viewppm -save test.jpg",{get_interpreter(true)})
Imager::i_writeppm_wiol($img, $IO) or die;
atom hProc = system_exec(cmd, 12, pipes),
my $raw = Imager::io_slurp($IO) or die;
hPipe = pipes[PIPEIN][WRITE_PIPE]
 
sequence img = serialize(read_ppm("Lena.ppm",bFlat:=true))
if not write_to_pipe(hPipe,img) then crash("error") end if
 
-- Close the pipe handle so the child process stops reading.
--hPipe = close_handles(hPipe)
pipes = close_handles(pipes) -- (may as well do the lot)</lang>
 
open my $fh, '|-', '/usr/local/bin/convert - -compress none output.jpg' or die;
binmode $fh;
syswrite $fh, $raw or die;
close $fh;</syntaxhighlight>
{{out}}
<pre>file output.jpg
output.jpg: JPEG image data, JFIF standard 1.01, comment: "CREATOR: Imager"
magick identify output.jpg
output.jpg JPEG 150x150 150x150+0+0 8-bit sRGB 3952B 0.000u 0:00.012</pre>
=={{header|Phix}}==
Uses the provided demo\rosetta\viewppm.exw utility to accomplish this task.
<!--<syntaxhighlight lang="phix">(notonline)-->
<span style="color: #000080;font-style:italic;">-- demo\rosetta\Bitmap_PPM_conversion_through_a_pipe.exw</span>
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- file i/o, system_exec(), pipes[!!]</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">builtins</span><span style="color: #0000FF;">\</span><span style="color: #000000;">pipeio</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">builtins</span><span style="color: #0000FF;">\</span><span style="color: #7060A8;">serialize</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">ppm</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> <span style="color: #000080;font-style:italic;">-- read_ppm()</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">pipes</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">pipes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">PIPEIN</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">create_pipe</span><span style="color: #0000FF;">(</span><span style="color: #000000;">INHERIT_WRITE</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- Create the child process, with replacement stdin. </span>
<span style="color: #004080;">string</span> <span style="color: #000000;">cmd</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"%s viewppm -save test.jpg"</span><span style="color: #0000FF;">,{</span><span style="color: #7060A8;">get_interpreter</span><span style="color: #0000FF;">(</span><span style="color: #004600;">true</span><span style="color: #0000FF;">)})</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">hProc</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">system_exec</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">12</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pipes</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">hPipe</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">pipes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">PIPEIN</span><span style="color: #0000FF;">][</span><span style="color: #000000;">WRITE_PIPE</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">img</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">serialize</span><span style="color: #0000FF;">(</span><span style="color: #000000;">read_ppm</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Lena.ppm"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bFlat</span><span style="color: #0000FF;">:=</span><span style="color: #004600;">true</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #000000;">write_to_pipe</span><span style="color: #0000FF;">(</span><span style="color: #000000;">hPipe</span><span style="color: #0000FF;">,</span><span style="color: #000000;">img</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"error"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000080;font-style:italic;">-- Close the pipe handle so the child process stops reading.
--hPipe = close_handles(hPipe)</span>
<span style="color: #000000;">pipes</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">close_handles</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pipes</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- (may as well do the lot)</span>
<span style="color: #0000FF;">?</span><span style="color: #008000;">"done"</span>
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp"># Create an empty image of 120 x 90 pixels
(setq *Ppm (make (do 90 (link (need 120)))))
 
Line 271 ⟶ 424:
 
# Write to "img.jpg" through a pipe
(ppmWrite *Ppm '("convert" "-" "img.jpg"))</langsyntaxhighlight>
 
=={{header|Python}}==
<syntaxhighlight lang="python">
<lang Python>
"""
Adapted from https://stackoverflow.com/questions/26937143/ppm-to-jpeg-jpg-conversion-for-python-3-4-1
Line 285 ⟶ 437:
im = Image.open("boxes_1.ppm")
im.save("boxes_1.jpg")
</syntaxhighlight>
</lang>
Does not need to pipe through a conversion utility
because the Pillow module does the conversion.
 
=={{header|Racket}}==
<langsyntaxhighlight lang="racket">
(define (ppm->jpeg bitmap [jpg-file "output"] [quality 75])
(define command (format "convert ppm:- -quality ~a jpg:~a.jpg" quality jpg-file))
Line 298 ⟶ 449:
(close-output-port out))
 
(ppm->jpeg bm)</langsyntaxhighlight>
 
=={{header|Raku}}==
(formerly Perl 6)
<syntaxhighlight lang="raku" perl6line># Reference:
# https://rosettacode.org/wiki/Bitmap/Write_a_PPM_file#Raku
 
Line 338 ⟶ 488:
my $proc = run '/usr/bin/convert','-','output_piped.jpg', :in;
$proc.in.write: $b.P6;
$proc.in.close;</langsyntaxhighlight>
{{out}}
<pre>file output_piped.jpg
output_piped.jpg: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 125x125, frames 3</pre>
 
=={{header|Ruby}}==
Extends [[Write ppm file#Ruby]]. Uses the ImageMagick <code>convert</code> tool.
Additionally, for debugging, allow writing in pixmap P3 (ascii) format.
 
<langsyntaxhighlight lang="ruby">class Pixmap
PIXMAP_FORMATS = ["P3", "P6"] # implemented output formats
PIXMAP_BINARY_FORMATS = ["P6"] # implemented output formats which are binary
Line 385 ⟶ 534:
 
image = Pixmap.open('file.ppm')
image.save_as_jpeg('file.jpg')</langsyntaxhighlight>
 
=={{header|Standard ML}}==
This function uses convert, and retrieves its output
<syntaxhighlight lang="standard ml">
<lang Standard ML>
val useOSConvert = fn ppm =>
let
Line 417 ⟶ 565:
)
end;
</syntaxhighlight>
</lang>
call and return value
<syntaxhighlight lang="standard ml">
<lang Standard ML>
useOSConvert "P3 3 2 255 255 0 0 0 255 0 0 0 255 255 255 0 255 255 255 0 0 0" ;
val it =
fromList[0wxFF, 0wxD8, 0wxFF, 0wxE0, 0wx0, 0wx10, 0wx4A, 0wx46, 0wx49,
0wx46, ...]: BinIO.vector
</syntaxhighlight>
</lang>
This is the fire-and-forget version.
<syntaxhighlight lang="standard ml">
<lang Standard ML>
val demo = fn () =>
let
Line 460 ⟶ 608:
 
end ;
</syntaxhighlight>
</lang>
output, after compilation to 'demo'
shell$ demo
shell$ file /tmp/out.jpeg
/tmp/out.jpeg: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 3x2, frames 3
 
=={{header|Tcl}}==
Referring to [[Write ppm file#Tcl]] and [[Basic bitmap storage#Tcl]]
 
{{libheader|Tk}}
<langsyntaxhighlight lang="tcl">package require Tk
 
proc output_jpeg {image filename {quality 75}} {
Line 477 ⟶ 624:
puts -nonewline $f [$image data -format ppm]
close $f
}</langsyntaxhighlight>
However, it is more normal to do this directly with the {{libheader|TkImg}} which is bundled with many Tcl distributions.
<langsyntaxhighlight lang="tcl">package require Tk
package require img::jpeg
 
Line 486 ⟶ 633:
}
set img [image create photo -filename filename.ppm]
output_jpeg $img filename.jpg</langsyntaxhighlight>
=={{header|Wren}}==
{{libheader|DOME}}
As DOME doesn't have a method for calling an external process (''ImageMagick'' in this case), we first need to create a small plug-in in C to add this functionality.
<syntaxhighlight lang="c">/* gcc -O3 -std=c11 -shared -o pipeconv.so -fPIC -I./include pipeconv.c */
 
#include <stdlib.h>
#include <string.h>
#include "dome.h"
 
static DOME_API_v0* core;
static WREN_API_v0* wren;
 
static const char* source = ""
"class PipeConv {\n"
"foreign static convert(from, to) \n"
"} \n";
 
void C_convert(WrenVM* vm) {
const char *from = wren->getSlotString(vm, 1);
const char *to = wren->getSlotString(vm, 2);
char command[strlen(from) + strlen(to) + 10];
strcpy(command, "convert ");
strcat(command, from);
strcat(command, " ");
strcat(command, to);
int res = system(command);
}
 
DOME_EXPORT DOME_Result PLUGIN_onInit(DOME_getAPIFunction DOME_getAPI, DOME_Context ctx) {
core = DOME_getAPI(API_DOME, DOME_API_VERSION);
wren = DOME_getAPI(API_WREN, WREN_API_VERSION);
core->registerModule(ctx, "pipeconv", source);
core->registerClass(ctx, "pipeconv", "PipeConv", NULL, NULL);
core->registerFn(ctx, "pipeconv", "static PipeConv.convert(_,_)", C_convert);
return DOME_RESULT_SUCCESS;
}
 
DOME_EXPORT DOME_Result PLUGIN_preUpdate(DOME_Context ctx) {
return DOME_RESULT_SUCCESS;
}
 
DOME_EXPORT DOME_Result PLUGIN_postUpdate(DOME_Context ctx) {
return DOME_RESULT_SUCCESS;
}
 
DOME_EXPORT DOME_Result PLUGIN_preDraw(DOME_Context ctx) {
return DOME_RESULT_SUCCESS;
}
 
DOME_EXPORT DOME_Result PLUGIN_postDraw(DOME_Context ctx) {
return DOME_RESULT_SUCCESS;
}
 
DOME_EXPORT DOME_Result PLUGIN_onShutdown(DOME_Context ctx) {
return DOME_RESULT_SUCCESS;
}</syntaxhighlight>
This assumes that the ''dome.h'' header file is copied to an ''include'' sub-directory of the current one and that the resulting ''pipeconv.so'' shared library file is created in the latter.
 
We can now use this plug-in in the following script which calls ''ImageMagick'' to convert the ''output.ppm'' file to a ''jpg'' file and then loads the latter and displays it.
 
<syntaxhighlight lang="wren">import "graphics" for Canvas, ImageData
import "dome" for Window
import "plugin" for Plugin
 
Plugin.load("pipeconv")
 
import "pipeconv" for PipeConv
 
class ConvertPPM {
construct new(fileName, fileName2, width, height) {
Window.resize(width, height)
Canvas.resize(width, height)
Window.title = "Convert PPM file via pipe"
// convert .ppm file to .jpg via a pipe
PipeConv.convert(fileName, fileName2)
// load and display .jpg file
var image = ImageData.loadFromFile(fileName2)
image.draw(0, 0)
}
 
init() {}
 
update() {}
 
draw(alpha) {}
}
 
var Game = ConvertPPM.new("output.ppm", "output_piped.jpg", 350, 350)</syntaxhighlight>
 
=={{header|zkl}}==
Line 493 ⟶ 728:
 
Using the convert utility by ImageMagick:
<langsyntaxhighlight lang="zkl">img:=PPM.readPPMFile("fractal.ppm");
p:=System.popen(0'|convert ppm:- jpg:"fractal.jpg"|,"w");
img.write(p); p.close();</langsyntaxhighlight>
 
{{omit from|GUISS}}
{{omit from|PARI/GP}}
{{omit from|TI-83 BASIC}} {{omit from|TI-89 BASIC}} <!-- Does not have an external OS/command processor. -->
{{omit from|TI-89 BASIC}} <!-- Does not have an external OS/command processor. -->
{{omit from|ZX Spectrum Basic|Does not have pipelining}}
9,476

edits