Bitmap/Read an image through a pipe: Difference between revisions

From Rosetta Code
Content added Content deleted
(Added Wren)
(→‎{{header|Wren}}: Fixed a potential timing issue with FileSystem.load.)
 
(8 intermediate revisions by 5 users not shown)
Line 1: Line 1:
{{task|Raster graphics operations}}
[[Category:Input Output]]
[[Category:Input Output]]
[[Category:Less Than 20 Examples]]
{{task|Raster graphics operations}}


This task is the ''opposite'' of the [[PPM conversion through a pipe]]. In this task, using a delegate tool (like '''cjpeg''', one of the netpbm package, or '''convert''' of the ImageMagick package) we read an image file and load it into the data storage type [[Basic bitmap storage|defined here]]. We can also use the code from [[Read ppm file]], so that we can use PPM format like a (natural) bridge between the foreign image format and our simple data storage.
This task is the ''opposite'' of the [[PPM conversion through a pipe]]. In this task, using a delegate tool (like '''cjpeg''', one of the netpbm package, or '''convert''' of the ImageMagick package) we read an image file and load it into the data storage type [[Basic bitmap storage|defined here]]. We can also use the code from [[Read ppm file]], so that we can use PPM format like a (natural) bridge between the foreign image format and our simple data storage.
=={{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]].)

Because I wrote this program by modifying [[Bitmap/PPM_conversion_through_a_pipe#ATS]], it both reads ''and writes'' the file by piping through the <code>magick</code> command of ImageMagick. The comments at the top of the earlier program thus apply doubly here.

<syntaxhighlight lang="ats">
(* I both read AND write the image through pipes connected to
ImageMagick. One can also pass options and such but I won't go into
the details. *)

(*

##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_name = if nargs < 2 then "-" else args[1]
val command = string_append ("magick ", inpf_name, " ppm:-")
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, "r")
val () = free command
in
case+ pipe_opt of
| ~ None_vt () =>
begin
free args;
println! ("For some reason, I failed to open a pipe ",
"for reading from magick.");
exit 1
end
| ~ Some_vt inpf =>
let
val pix_opt = pixmap_read_ppm<rgb24> inpf
in
ignoret (fileref_pclose_unsafe inpf);
case+ pix_opt of
| ~ None_vt () =>
begin
free args;
println! ("For some reason, I failed to pipe the image ",
"from magick.");
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 ",
"for writing to magick.");
exit 3
end
| ~ Some_vt outf =>
let
val success = pixmap_write_ppm<rgb24> (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
end
</syntaxhighlight>

{{out}}

Using SIPI test image 4.1.07:

<pre>$ myatscc bitmap_read_through_pipe_task.dats
$ ./bitmap_read_through_pipe_task 4.1.07.tiff > 4.1.07.ppm
$ file 4.1.07.ppm
4.1.07.ppm: Netpbm image data, size = 256 x 256, rawbits, pixmap
$ ./bitmap_read_through_pipe_task 4.1.07.tiff 4.1.07.jpg
$ file 4.1.07.jpg
4.1.07.jpg: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 256x256, components 3</pre>

Notice that, when I did not specify an output file, I got a PPM (PPM being what was sent through the output pipe to magick). Both times, though, the input pipe converts a TIFF image to PPM, which then is read into the internal <code>pixmap</code> type.

Here is the JPEG that was outputted:
[[File:Bitmap read through pipe task ATS.jpg|none|alt=SIPI test image of jellybeans.]]


=={{header|AutoHotkey}}==
=={{header|AutoHotkey}}==
{{works with | AutoHotkey_L}}
{{works with | AutoHotkey_L}}
Uses [http://www.autohotkey.com/forum/viewtopic.php?t=16823 StdoutTovar.ahk]
Uses [http://www.autohotkey.com/forum/viewtopic.php?t=16823 StdoutTovar.ahk]
<lang AutoHotkey>ppm := Run("cmd.exe /c convert lena50.jpg ppm:-")
<syntaxhighlight lang="autohotkey">ppm := Run("cmd.exe /c convert lena50.jpg ppm:-")
; pipe in from imagemagick
; pipe in from imagemagick
img := ppm_read("", ppm) ;
img := ppm_read("", ppm) ;
Line 67: Line 222:
#include bitmap_storage.ahk ; from http://rosettacode.org/wiki/Basic_bitmap_storage/AutoHotkey
#include bitmap_storage.ahk ; from http://rosettacode.org/wiki/Basic_bitmap_storage/AutoHotkey
#include run.ahk ; http://www.autohotkey.com/forum/viewtopic.php?t=16823
#include run.ahk ; http://www.autohotkey.com/forum/viewtopic.php?t=16823
</syntaxhighlight>
</lang>


=={{header|C}}==
=={{header|C}}==
Line 73: Line 228:
Here I've used '''convert''' by ImageMagick. It is up to the program to ''understand'' the source file type; in this way, we can read theoretically any image format ImageMagick can handle. The <tt>get_ppm</tt> function defined in [[Read ppm file]] is used.
Here I've used '''convert''' by ImageMagick. It is up to the program to ''understand'' the source file type; in this way, we can read theoretically any image format ImageMagick can handle. The <tt>get_ppm</tt> function defined in [[Read ppm file]] is used.


<lang c>image read_image(const char *name);</lang>
<syntaxhighlight lang="c">image read_image(const char *name);</syntaxhighlight>


<lang c>#include "imglib.h"
<syntaxhighlight lang="c">#include "imglib.h"


#define MAXCMDBUF 100
#define MAXCMDBUF 100
Line 102: Line 257:
}
}
return NULL;
return NULL;
}</lang>
}</syntaxhighlight>

=={{header|Go}}==
=={{header|Go}}==
This example uses convert to convert the test image for the flood fill task. It reads through the pipe as required for this task, then writes as a .ppm file convenient for the flood fill task.
This example uses convert to convert the test image for the flood fill task. It reads through the pipe as required for this task, then writes as a .ppm file convenient for the flood fill task.
<lang go>package main
<syntaxhighlight lang="go">package main


// Files required to build supporting package raster are found in:
// Files required to build supporting package raster are found in:
Line 135: Line 289:
log.Fatal(err)
log.Fatal(err)
}
}
}</lang>
}</syntaxhighlight>

=={{header|Julia}}==
=={{header|Julia}}==
{{works with|Julia|0.6}}
{{works with|Julia|0.6}}


<lang julia>using Images, FileIO
<syntaxhighlight lang="julia">using Images, FileIO


img = load("data/bitmapOutputTest.jpg")
img = load("data/bitmapOutputTest.jpg")
save("data/bitmapOutputTest.ppm", img)</lang>
save("data/bitmapOutputTest.ppm", img)</syntaxhighlight>

=={{header|Kotlin}}==
=={{header|Kotlin}}==
{{works with|Ubuntu 16.04}}
{{works with|Ubuntu 16.04}}
The code for this is similar to that for the [[Bitmap/Read a PPM file]] task except that the .jpg file is converted via a pipe to .ppm format using the ImageMagick 'convert' tool and stored in a BasicBitmapStorage object. It is then converted to grayscale and saved back to disk as a .jpg file.
The code for this is similar to that for the [[Bitmap/Read a PPM file]] task except that the .jpg file is converted via a pipe to .ppm format using the ImageMagick 'convert' tool and stored in a BasicBitmapStorage object. It is then converted to grayscale and saved back to disk as a .jpg file.
<lang scala>// Version 1.2.40
<syntaxhighlight lang="scala">// Version 1.2.40


import java.awt.Color
import java.awt.Color
Line 282: Line 434:
}
}
}
}
}</lang>
}</syntaxhighlight>

=={{header|Lua}}==
=={{header|Lua}}==
Uses Bitmap class [[Bitmap#Lua|here]], with an RGB tuple pixel representation, and the rudimentary PPM support [[Bitmap/Flood_fill#Lua|here]], and the Lenna image [[:File:Lenna100.jpg|here]].
Uses Bitmap class [[Bitmap#Lua|here]], with an RGB tuple pixel representation, and the rudimentary PPM support [[Bitmap/Flood_fill#Lua|here]], and the Lenna image [[:File:Lenna100.jpg|here]].


First, the <code>loadPPM()</code> method is altered to allow passing an existing file handle:
First, the <code>loadPPM()</code> method is altered to allow passing an existing file handle:
<lang lua>function Bitmap:loadPPM(filename, fp)
<syntaxhighlight lang="lua">function Bitmap:loadPPM(filename, fp)
if not fp then fp = io.open(filename, "rb") end
if not fp then fp = io.open(filename, "rb") end
if not fp then return end
if not fp then return end
Line 300: Line 451:
end
end
fp:close()
fp:close()
end</lang>
end</syntaxhighlight>
Then, for the actual "read-from-pipe" task, a Lua environment that supports <code>io.popen()</code> is required:
Then, for the actual "read-from-pipe" task, a Lua environment that supports <code>io.popen()</code> is required:
<lang lua>local bitmap = Bitmap(0,0)
<syntaxhighlight lang="lua">local bitmap = Bitmap(0,0)
fp = io.popen("magick Lenna100.jpg ppm:-", "rb")
fp = io.popen("magick Lenna100.jpg ppm:-", "rb")
bitmap:loadPPM(nil, fp)
bitmap:loadPPM(nil, fp)


bitmap:savePPM("Lenna100.ppm") -- just as "proof"</lang>
bitmap:savePPM("Lenna100.ppm") -- just as "proof"</syntaxhighlight>

=={{header|Mathematica}}/{{header|Wolfram Language}}==
=={{header|Mathematica}}/{{header|Wolfram Language}}==
Based off the Julia program.
Based off the Julia program.
<lang Mathematica>Export["data/bitmapOutputTest.ppm",Import["data/bitmapOutputTest.jpg"]];</lang>
<syntaxhighlight lang="mathematica">Export["data/bitmapOutputTest.ppm",Import["data/bitmapOutputTest.jpg"]];</syntaxhighlight>

=={{header|Nim}}==
=={{header|Nim}}==
Using "jpegtopnm" from Netpbm suite. Input is a JPEG file and result (the PPM file) is sent to stdout. The procedure "readPPM" reads directly from the stream and build the image container.
Using "jpegtopnm" from Netpbm suite. Input is a JPEG file and result (the PPM file) is sent to stdout. The procedure "readPPM" reads directly from the stream and build the image container.


<lang Nim>import bitmap
<syntaxhighlight lang="nim">import bitmap
import osproc
import osproc
import ppm_read
import ppm_read
Line 326: Line 475:
let image = stream.readPPM()
let image = stream.readPPM()
echo image.w, " ", image.h
echo image.w, " ", image.h
p.close()</lang>
p.close()</syntaxhighlight>

=={{header|OCaml}}==
=={{header|OCaml}}==
The <code>read_ppm</code> function of the page [[read ppm file]] and used by the code below would need to be changed to take as parameter an input channel instead of the filename.
The <code>read_ppm</code> function of the page [[read ppm file]] and used by the code below would need to be changed to take as parameter an input channel instead of the filename.
<lang ocaml>let read_image ~filename =
<syntaxhighlight lang="ocaml">let read_image ~filename =
if not(Sys.file_exists filename)
if not(Sys.file_exists filename)
then failwith(Printf.sprintf "the file %s does not exist" filename);
then failwith(Printf.sprintf "the file %s does not exist" filename);
Line 337: Line 485:
let img = read_ppm ~ic in
let img = read_ppm ~ic in
(img)
(img)
;;</lang>
;;</syntaxhighlight>
=={{header|Perl}}==
<syntaxhighlight lang="perl"># 20211226 Perl programming solution


use strict;
=={{header|Phix}}==
use warnings;
Uses the demo\rosetta\viewppm.exw utility to accomplish this task.<br>
The returned data is raw binary, so you can either write it direct or chuck it through read_ppm/write_ppm.
<lang Phix>-- demo\rosetta\Bitmap_Read_an_image_through_a_pipe.exw
requires("0.8.4")
include builtins\pipeio.e
include ppm.e -- read_ppm(), write_ppm()


use Imager;
sequence pipes = repeat(0,3)
pipes[PIPOUT] = create_pipe(INHERIT_READ)


my $raw;
-- Create the child process, with replacement stdout.
string cmd = sprintf("%s viewppm -load test.jpg",{get_interpreter(true)})
atom hProc = system_exec(cmd, 12, pipes),
hPipe = pipes[PIPOUT][READ_PIPE]


open my $fh, '-|', 'cat Lenna50.jpg' or die;
string ppm = read_from_pipe(hPipe, hProc)
binmode $fh;
while true do
while ( sysread $fh , my $chunk , 1024 ) { $raw .= $chunk }
object chunk = read_from_pipe(hPipe, hProc)
close $fh;
if chunk=-1 then exit end if
ppm &= chunk
end while


my $enable = $Imager::formats{"jpeg"}; # some kind of tie ?
pipes = close_handles(pipes)


my $IO = Imager::io_new_buffer $raw or die;
if 0 then
my $im = Imager::File::JPEG::i_readjpeg_wiol $IO or die;
sequence img = read_ppm(ppm,bText:=true)
write_ppm("Lenapipe.ppm", img)
else -- or
integer fn = open("Lenapipe.ppm","wb")
puts(fn,ppm)
close(fn)
end if</lang>


open my $fh2, '>', 'output.ppm' or die;
binmode $fh2;
my $IO2 = Imager::io_new_fd(fileno $fh2);
Imager::i_writeppm_wiol $im, $IO2 ;
close $fh2;
undef($im);</syntaxhighlight>
{{out}}
<pre>file output.ppm
output.ppm: Netpbm PPM "rawbits" image data, size = 512 x 512
magick identify output.ppm
output.ppm PPM 512x512 512x512+0+0 8-bit sRGB 786464B 0.000u 0:00.014</pre>
=={{header|Phix}}==
Uses the demo\rosetta\viewppm.exw utility to accomplish this task.<br>
The returned data is raw binary, so you can either write it direct or chuck it through read_ppm/write_ppm.
<!--<syntaxhighlight lang="phix">(notonline)-->
<span style="color: #000080;font-style:italic;">-- demo\rosetta\Bitmap_Read_an_image_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;">ppm</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> <span style="color: #000080;font-style:italic;">-- read_ppm(), write_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;">PIPOUT</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_READ</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- Create the child process, with replacement stdout. </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 -load 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;">PIPOUT</span><span style="color: #0000FF;">][</span><span style="color: #000000;">READ_PIPE</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">ppm</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">read_from_pipe</span><span style="color: #0000FF;">(</span><span style="color: #000000;">hPipe</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">hProc</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">object</span> <span style="color: #000000;">chunk</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">read_from_pipe</span><span style="color: #0000FF;">(</span><span style="color: #000000;">hPipe</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">hProc</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">chunk</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">ppm</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">chunk</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</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: #008080;">if</span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">img</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">read_ppm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ppm</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bText</span><span style="color: #0000FF;">:=</span><span style="color: #004600;">true</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">write_ppm</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Lenapipe.ppm"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">img</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">else</span> <span style="color: #000080;font-style:italic;">-- or</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">fn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">open</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Lenapipe.ppm"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"wb"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ppm</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</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}}==
=={{header|PicoLisp}}==
<lang PicoLisp>(setq *Ppm (ppmRead '("convert" "img.jpg" "ppm:-")))</lang>
<syntaxhighlight lang="picolisp">(setq *Ppm (ppmRead '("convert" "img.jpg" "ppm:-")))</syntaxhighlight>

=={{header|Python}}==
=={{header|Python}}==
<syntaxhighlight lang="python">
<lang Python>
"""
"""
Adapted from https://stackoverflow.com/questions/26937143/ppm-to-jpeg-jpg-conversion-for-python-3-4-1
Adapted from https://stackoverflow.com/questions/26937143/ppm-to-jpeg-jpg-conversion-for-python-3-4-1
Line 390: Line 571:
im = Image.open("boxes_1.jpg")
im = Image.open("boxes_1.jpg")
im.save("boxes_1v2.ppm")
im.save("boxes_1v2.ppm")
</syntaxhighlight>
</lang>
Does not need to pipe through a conversion utility
Does not need to pipe through a conversion utility
because the Pillow module does the conversion.
because the Pillow module does the conversion.

=={{header|Racket}}==
=={{header|Racket}}==
<lang racket>
<syntaxhighlight lang="racket">


(define (read-ppm port)
(define (read-ppm port)
Line 426: Line 606:
bmp)
bmp)


(image->bmp "input.jpg")</lang>
(image->bmp "input.jpg")</syntaxhighlight>

=={{header|Raku}}==
=={{header|Raku}}==
(formerly Perl 6)
(formerly Perl 6)
Line 435: Line 614:
Uses imagemagick convert to pipe the image in.
Uses imagemagick convert to pipe the image in.


<lang perl6>class Pixel { has UInt ($.R, $.G, $.B) }
<syntaxhighlight lang="raku" line>class Pixel { has UInt ($.R, $.G, $.B) }
class Bitmap {
class Bitmap {
has UInt ($.width, $.height);
has UInt ($.width, $.height);
Line 467: Line 646:
{ Pixel.new(R => .[0], G => .[1], B => .[2]) };
{ Pixel.new(R => .[0], G => .[1], B => .[2]) };


'./camelia.ppm'.IO.open(:bin, :w).write: $b.P6;</lang>
'./camelia.ppm'.IO.open(:bin, :w).write: $b.P6;</syntaxhighlight>


See [https://github.com/thundergnat/rc/blob/master/img/camelia.png camelia image here].
See [https://github.com/thundergnat/rc/blob/master/img/camelia.png camelia image here].

=={{header|Ruby}}==
=={{header|Ruby}}==
Uses [[Raster graphics operations/Ruby]].
Uses [[Raster graphics operations/Ruby]].


<lang ruby># frozen_string_literal: true
<syntaxhighlight lang="ruby"># frozen_string_literal: true


require_relative 'raster_graphics'
require_relative 'raster_graphics'
Line 518: Line 696:
bitmap = Pixmap.open_from_jpeg('foto.jpg')
bitmap = Pixmap.open_from_jpeg('foto.jpg')
bitmap.save('foto.ppm')
bitmap.save('foto.ppm')
</syntaxhighlight>
</lang>

=={{header|Tcl}}==
=={{header|Tcl}}==
{{works with|Tcl|8.6}}
{{works with|Tcl|8.6}}
{{libheader|Tk}}
{{libheader|Tk}}
<lang tcl>package require Tk
<syntaxhighlight lang="tcl">package require Tk


proc magickalReadImage {bufferImage fileName} {
proc magickalReadImage {bufferImage fileName} {
Line 532: Line 709:
close $f
close $f
}
}
}</lang>
}</syntaxhighlight>

=={{header|Wren}}==
=={{header|Wren}}==
{{libheader|DOME}}
{{libheader|DOME}}
Line 541: Line 717:
We can now use this plug-in in the following script which calls ''ImageMagick'' to convert the ''output_piped.jpg'' file to a ''ppm'' file so that we can load the latter, convert it to a gray scale image, display it and save it to a .jpg file.
We can now use this plug-in in the following script which calls ''ImageMagick'' to convert the ''output_piped.jpg'' file to a ''ppm'' file so that we can load the latter, convert it to a gray scale image, display it and save it to a .jpg file.


<lang ecmascript>import "graphics" for Canvas, ImageData, Color
<syntaxhighlight lang="wren">import "graphics" for Canvas, ImageData, Color
import "dome" for Window, Process
import "dome" for Window, Process
import "io" for FileSystem
import "io" for FileSystem
Line 574: Line 750:
loadPPMFile(fileName) {
loadPPMFile(fileName) {
var ppm = FileSystem.load(fileName)
var ppm = FileSystem.load(fileName)
var count = ppm.count //ensure file is fully loaded before proceeding
if (ppm[0..1] != "P6") {
if (ppm[0..1] != "P6") {
System.print("The loaded file is not a P6 file.")
System.print("The loaded file is not a P6 file.")
Line 622: Line 799:
}
}


var Game = Bitmap.new("output_piped.jpg", "output_piped.ppm", "output_piped_gs.jpg", 350, 350)</lang>
var Game = Bitmap.new("output_piped.jpg", "output_piped.ppm", "output_piped_gs.jpg", 350, 350)</syntaxhighlight>


=={{header|zkl}}==
=={{header|zkl}}==
Line 629: Line 806:


Using the convert utility by ImageMagick:
Using the convert utility by ImageMagick:
<lang zkl>p:=System.popen(0'|convert "fractalTree.jpg" ppm:-|,"r");
<syntaxhighlight lang="zkl">p:=System.popen(0'|convert "fractalTree.jpg" ppm:-|,"r");
img:=PPM.readPPM(p); p.close();</lang>
img:=PPM.readPPM(p); p.close();</syntaxhighlight>

{{omit from|PARI/GP}}
{{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-83 BASIC}}
{{omit from|TI-89 BASIC}} <!-- Does not have an external OS/command processor. -->
[[Category:Less Than 20 Examples]]

Latest revision as of 11:33, 9 November 2023

Task
Bitmap/Read an image through a pipe
You are encouraged to solve this task according to the task description, using any language you may know.

This task is the opposite of the PPM conversion through a pipe. In this task, using a delegate tool (like cjpeg, one of the netpbm package, or convert of the ImageMagick package) we read an image file and load it into the data storage type defined here. We can also use the code from Read ppm file, so that we can use PPM format like a (natural) bridge between the foreign image format and our simple data storage.

ATS

I use the magick 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.)

Because I wrote this program by modifying Bitmap/PPM_conversion_through_a_pipe#ATS, it both reads and writes the file by piping through the magick command of ImageMagick. The comments at the top of the earlier program thus apply doubly here.

(* I both read AND write the image through pipes connected to
   ImageMagick. One can also pass options and such but I won't go into
   the details. *)

(*

##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_name = if nargs < 2 then "-" else args[1]
    val command = string_append ("magick ", inpf_name, " ppm:-")
    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, "r")
    val () = free command
  in
    case+ pipe_opt of
    | ~ None_vt () =>
      begin
        free args;
        println! ("For some reason, I failed to open a pipe ",
                  "for reading from magick.");
        exit 1
      end
    | ~ Some_vt inpf =>
      let
        val pix_opt = pixmap_read_ppm<rgb24> inpf
      in
        ignoret (fileref_pclose_unsafe inpf);
        case+ pix_opt of
        | ~ None_vt () =>
          begin
            free args;
            println! ("For some reason, I failed to pipe the image ",
                      "from magick.");
            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 ",
                          "for writing to magick.");
                exit 3
              end
            | ~ Some_vt outf =>
              let
                val success = pixmap_write_ppm<rgb24> (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
  end
Output:

Using SIPI test image 4.1.07:

$ myatscc bitmap_read_through_pipe_task.dats
$ ./bitmap_read_through_pipe_task 4.1.07.tiff > 4.1.07.ppm
$ file 4.1.07.ppm
4.1.07.ppm: Netpbm image data, size = 256 x 256, rawbits, pixmap
$ ./bitmap_read_through_pipe_task 4.1.07.tiff 4.1.07.jpg
$ file 4.1.07.jpg
4.1.07.jpg: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 256x256, components 3

Notice that, when I did not specify an output file, I got a PPM (PPM being what was sent through the output pipe to magick). Both times, though, the input pipe converts a TIFF image to PPM, which then is read into the internal pixmap type.

Here is the JPEG that was outputted:

SIPI test image of jellybeans.

AutoHotkey

Works with: AutoHotkey_L

Uses StdoutTovar.ahk

ppm := Run("cmd.exe /c convert lena50.jpg ppm:-") 
                       ; pipe in from imagemagick
img := ppm_read("", ppm) ;   
x := img[4,4] ; get pixel(4,4)
y := img[24,24] ; get pixel(24,24)
msgbox % x.rgb() " " y.rgb()
img.write("lena50copy.ppm")
return
 
ppm_read(filename, ppmo=0) ; only ppm6 files supported 
{
if !ppmo  ; if image not already in memory, read from filename
  fileread, ppmo, % filename 

  index := 1  
  pos := 1

  loop, parse, ppmo, `n, `r
  {
    if (substr(A_LoopField, 1, 1) == "#")
      continue
loop, 
{ 
 if !pos := regexmatch(ppmo, "\d+", pixel, pos)
break
    bitmap%A_Index% := pixel
    if (index == 4)
      Break
    pos := regexmatch(ppmo, "\s", x, pos)
    index ++
}
  }
 
  type := bitmap1
  width := bitmap2
  height := bitmap3
  maxcolor := bitmap4
  bitmap := Bitmap(width, height, color(0,0,0))
  index := 1
  i := 1
  j := 1
 bits := pos 
loop % width * height 
  {
      bitmap[i, j, "r"]  := numget(ppmo, 3 * A_Index + bits, "uchar")
      bitmap[i, j, "g"]  := numget(ppmo, 3 * A_Index + bits + 1, "uchar")
      bitmap[i, j, "b"]  := numget(ppmo, 3 * A_Index + bits + 2, "uchar")

      if (j == width)
{
	j := 1
	i += 1
}
      else
	j++
}
 return bitmap  
  }
#include bitmap_storage.ahk ; from http://rosettacode.org/wiki/Basic_bitmap_storage/AutoHotkey
#include run.ahk ; http://www.autohotkey.com/forum/viewtopic.php?t=16823

C

Works with: POSIX version .1-2001

Here I've used convert by ImageMagick. It is up to the program to understand the source file type; in this way, we can read theoretically any image format ImageMagick can handle. The get_ppm function defined in Read ppm file is used.

image read_image(const char *name);
#include "imglib.h"

#define MAXCMDBUF 100
#define MAXFILENAMELEN 256
#define MAXFULLCMDBUF (MAXCMDBUF + MAXFILENAMELEN)
image read_image(const char *name)
{
      FILE *pipe;
      char buf[MAXFULLCMDBUF];
      image im;
      
      FILE *test = fopen(name, "r");
      if ( test == NULL ) {
         fprintf(stderr, "cannot open file %s\n", name);
         return NULL;
      }
      fclose(test);
      
      snprintf(buf, MAXFULLCMDBUF, "convert \"%s\" ppm:-", name);
      pipe = popen(buf, "r");
      if ( pipe != NULL )
      {
           im = get_ppm(pipe);
           pclose(pipe);
           return im;
      }
      return NULL;
}

Go

This example uses convert to convert the test image for the flood fill task. It reads through the pipe as required for this task, then writes as a .ppm file convenient for the flood fill task.

package main

// Files required to build supporting package raster are found in:
// * Bitmap
// * Read a PPM file
// * Write a PPM file

import (
    "log"
    "os/exec"
    "raster"
)

func main() {
    c := exec.Command("convert", "Unfilledcirc.png", "-depth", "1", "ppm:-")
    pipe, err := c.StdoutPipe()
    if err != nil {
        log.Fatal(err)
    }
    if err = c.Start(); err != nil {
        log.Fatal(err)
    }
    b, err := raster.ReadPpmFrom(pipe)
    if err != nil {
        log.Fatal(err)
    }
    if err = b.WritePpmFile("Unfilledcirc.ppm"); err != nil {
        log.Fatal(err)
    }
}

Julia

Works with: Julia version 0.6
using Images, FileIO

img = load("data/bitmapOutputTest.jpg")
save("data/bitmapOutputTest.ppm", img)

Kotlin

Works with: Ubuntu 16.04

The code for this is similar to that for the Bitmap/Read a PPM file task except that the .jpg file is converted via a pipe to .ppm format using the ImageMagick 'convert' tool and stored in a BasicBitmapStorage object. It is then converted to grayscale and saved back to disk as a .jpg file.

// Version 1.2.40

import java.awt.Color
import java.awt.Graphics
import java.awt.image.BufferedImage
import java.io.PushbackInputStream
import java.io.File
import javax.imageio.ImageIO

class BasicBitmapStorage(width: Int, height: Int) {
    val image = BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR)

    fun fill(c: Color) {
        val g = image.graphics
        g.color = c
        g.fillRect(0, 0, image.width, image.height)
    }

    fun setPixel(x: Int, y: Int, c: Color) = image.setRGB(x, y, c.getRGB())

    fun getPixel(x: Int, y: Int) = Color(image.getRGB(x, y))

    fun toGrayScale() {
        for (x in 0 until image.width) {
            for (y in 0 until image.height) {
                var rgb  = image.getRGB(x, y)
                val red   = (rgb shr 16) and 0xFF
                val green = (rgb shr  8) and 0xFF
                val blue  =  rgb and 0xFF
                val lumin = (0.2126 * red + 0.7152 * green + 0.0722 * blue).toInt()
                rgb = (lumin shl 16) or (lumin shl 8) or lumin
                image.setRGB(x, y, rgb)
            }
        }
    }
}

fun PushbackInputStream.skipComment() {
    while (read().toChar() != '\n') {}
}

fun PushbackInputStream.skipComment(buffer: ByteArray) {
    var nl: Int
    while (true) {
        nl = buffer.indexOf(10) // look for newline at end of comment
        if (nl != -1) break
        read(buffer)  // read another buffer full if newline not yet found
    }
    val len = buffer.size
    if (nl < len - 1) unread(buffer, nl + 1, len - nl - 1)
}

fun Byte.toUInt() = if (this < 0) 256 + this else this.toInt()

fun main(args: Array<String>) {
    // use file, output_piped.jpg, created in the
    // Bitmap/PPM conversion through a pipe task
    val pb = ProcessBuilder("convert", "output_piped.jpg", "ppm:-")
    pb.directory(null)
    pb.redirectOutput(ProcessBuilder.Redirect.PIPE)
    val proc = pb.start()
    val pStdOut = proc.inputStream
    val pbis = PushbackInputStream(pStdOut, 80)
    pbis.use {
        with (it) {
            val h1 = read().toChar()
            val h2 = read().toChar()
            val h3 = read().toChar()
            if (h1 != 'P' || h2 != '6' || h3 != '\n') {
                println("Not a P6 PPM file")
                System.exit(1)
            }
            val sb = StringBuilder()
            while (true) {
                val r = read().toChar()
                if (r == '#') { skipComment(); continue }
                if (r == ' ') break  // read until space reached
                sb.append(r.toChar())
            }
            val width = sb.toString().toInt()
            sb.setLength(0)
            while (true) {
                val r = read().toChar()
                if (r == '#') { skipComment(); continue }
                if (r == '\n') break  // read until new line reached
                sb.append(r.toChar())
            }
            val height = sb.toString().toInt()
            sb.setLength(0)
            while (true) {
                val r = read().toChar()
                if (r == '#') { skipComment(); continue }
                if (r == '\n') break  // read until new line reached
                sb.append(r.toChar())
            }
            val maxCol = sb.toString().toInt()
            if (maxCol !in 0..255) {
                println("Maximum color value is outside the range 0..255")
                System.exit(1)
            }
            var buffer = ByteArray(80)
            // get rid of any more opening comments before reading data
            while (true) {
                read(buffer)
                if (buffer[0].toChar() == '#') {
                    skipComment(buffer)
                }
                else {
                    unread(buffer)
                    break
                }
            }
            // read data
            val bbs = BasicBitmapStorage(width, height)
            buffer = ByteArray(width * 3)
            var y = 0
            while (y < height) {
                read(buffer)
                for (x in 0 until width) {
                    val c = Color(
                        buffer[x * 3].toUInt(),
                        buffer[x * 3 + 1].toUInt(),
                        buffer[x * 3 + 2].toUInt()
                    )
                    bbs.setPixel(x, y, c)
                }
                y++
            }
            // convert to grayscale and save to a file
            bbs.toGrayScale()
            val grayFile = File("output_piped_gray.jpg")
            ImageIO.write(bbs.image, "jpg", grayFile)
        }
    }
}

Lua

Uses Bitmap class here, with an RGB tuple pixel representation, and the rudimentary PPM support here, and the Lenna image here.

First, the loadPPM() method is altered to allow passing an existing file handle:

function Bitmap:loadPPM(filename, fp)
  if not fp then fp = io.open(filename, "rb") end
  if not fp then return end
  local head, width, height, depth, tail = fp:read("*line", "*number", "*number", "*number", "*line")
  self.width, self.height = width, height
  self:alloc()
  for y = 1, self.height do
    for x = 1, self.width do
      self.pixels[y][x] = { string.byte(fp:read(1)), string.byte(fp:read(1)), string.byte(fp:read(1)) }
    end
  end
  fp:close()
end

Then, for the actual "read-from-pipe" task, a Lua environment that supports io.popen() is required:

local bitmap = Bitmap(0,0)
fp = io.popen("magick Lenna100.jpg ppm:-", "rb")
bitmap:loadPPM(nil, fp)

bitmap:savePPM("Lenna100.ppm") -- just as "proof"

Mathematica/Wolfram Language

Based off the Julia program.

Export["data/bitmapOutputTest.ppm",Import["data/bitmapOutputTest.jpg"]];

Nim

Using "jpegtopnm" from Netpbm suite. Input is a JPEG file and result (the PPM file) is sent to stdout. The procedure "readPPM" reads directly from the stream and build the image container.

import bitmap
import osproc
import ppm_read
import streams

# Launch Netpbm "jpegtopnm".
# Input is taken from "input.jpeg" and result sent to stdout.
let p = startProcess("jpegtopnm", args = ["input.jpeg"], options = {poUsePath})
let stream = FileStream(p.outputStream())
let image = stream.readPPM()
echo image.w, " ", image.h
p.close()

OCaml

The read_ppm function of the page read ppm file and used by the code below would need to be changed to take as parameter an input channel instead of the filename.

let read_image ~filename =
  if not(Sys.file_exists filename)
  then failwith(Printf.sprintf "the file %s does not exist" filename);
  let cmd = Printf.sprintf "convert \"%s\" ppm:-" filename in
  let ic, oc = Unix.open_process cmd in
  let img = read_ppm ~ic in
  (img)
;;

Perl

# 20211226 Perl programming solution

use strict;
use warnings;

use Imager;

my $raw;

open my $fh, '-|', 'cat Lenna50.jpg' or die;
binmode $fh;
while ( sysread $fh , my $chunk , 1024 ) { $raw .= $chunk }
close $fh;

my $enable = $Imager::formats{"jpeg"}; # some kind of tie ?

my $IO = Imager::io_new_buffer $raw or die;
my $im = Imager::File::JPEG::i_readjpeg_wiol $IO or die;

open my $fh2, '>', 'output.ppm' or die;
binmode $fh2;
my $IO2 = Imager::io_new_fd(fileno $fh2);
Imager::i_writeppm_wiol $im, $IO2 ;
close $fh2;
undef($im);
Output:
file output.ppm
output.ppm: Netpbm PPM "rawbits" image data, size = 512 x 512
magick identify output.ppm
output.ppm PPM 512x512 512x512+0+0 8-bit sRGB 786464B 0.000u 0:00.014

Phix

Uses the demo\rosetta\viewppm.exw utility to accomplish this task.
The returned data is raw binary, so you can either write it direct or chuck it through read_ppm/write_ppm.

-- demo\rosetta\Bitmap_Read_an_image_through_a_pipe.exw
without js -- file i/o, system_exec(), pipes[!!]
include builtins\pipeio.e
include ppm.e -- read_ppm(), write_ppm()

sequence pipes = repeat(0,3)
pipes[PIPOUT] = create_pipe(INHERIT_READ)

-- Create the child process, with replacement stdout. 
string cmd = sprintf("%s viewppm -load test.jpg",{get_interpreter(true)})
atom hProc = system_exec(cmd, 12, pipes),
     hPipe = pipes[PIPOUT][READ_PIPE]

string ppm = read_from_pipe(hPipe, hProc)
while true do
    object chunk = read_from_pipe(hPipe, hProc)
    if chunk=-1 then exit end if
    ppm &= chunk
end while

pipes = close_handles(pipes)

if 0 then
    sequence img = read_ppm(ppm,bText:=true)
    write_ppm("Lenapipe.ppm", img)
else -- or
    integer fn = open("Lenapipe.ppm","wb")
    puts(fn,ppm)
    close(fn)
end if

?"done"
{} = wait_key()

PicoLisp

(setq *Ppm (ppmRead '("convert" "img.jpg" "ppm:-")))

Python

"""
Adapted from https://stackoverflow.com/questions/26937143/ppm-to-jpeg-jpg-conversion-for-python-3-4-1
Requires pillow-5.3.0 with Python 3.7.1 32-bit on Windows.
Sample ppm graphics files from http://www.cs.cornell.edu/courses/cs664/2003fa/images/
"""

from PIL import Image

# boxes_1.jpg is the jpg version of boxes_1.ppm

im = Image.open("boxes_1.jpg")
im.save("boxes_1v2.ppm")

Does not need to pipe through a conversion utility because the Pillow module does the conversion.

Racket

(define (read-ppm port)
  (parameterize ([current-input-port port])
    (define magic (read-line))
    (match-define (list w h) (string-split (read-line) " "))
    (define width (string->number w))
    (define height (string->number h))
    (define maxcol (string->number (read-line)))
    (define bm (make-object bitmap% width height))
    (define dc (new bitmap-dc% [bitmap bm]))
    (send dc set-smoothing 'unsmoothed)
    (define (adjust v) (* 255 (/ v maxcol)))
    (for/list ([x width])
      (for/list ([y height])
        (define red (read-byte))
        (define green (read-byte))
        (define blue (read-byte))
        (define color (make-object color% (adjust red) (adjust green) (adjust blue)))
        (send dc set-pen color 1 'solid)
        (send dc draw-point x y)))
    bm))

(define (image->bmp filename)
  (define command (format "convert ~a ppm:-" filename))
  (match-define (list in out pid err ctrl)  (process command))
  (define bmp (read-ppm in))
  (close-input-port in)
  (close-output-port out)
  bmp)

(image->bmp "input.jpg")

Raku

(formerly Perl 6)

Works with: Rakudo version 2017.09

Uses pieces from Bitmap and Read a PPM file tasks. Included here to make a complete, runnable program.

Uses imagemagick convert to pipe the image in.

class Pixel { has UInt ($.R, $.G, $.B) }
class Bitmap {
    has UInt ($.width, $.height);
    has Pixel @.data;
}

role PPM {
    method P6 returns Blob {
	"P6\n{self.width} {self.height}\n255\n".encode('ascii')
	~ Blob.new: flat map { .R, .G, .B }, self.data
    }
}

sub getline ( $proc ) {
    my $line = '#'; # skip comment when reading a .png
    $line = $proc.out.get while $line.substr(0,1) eq '#';
    $line;
}

my $filename = './camelia.png';

my $proc = run 'convert', $filename, 'ppm:-', :enc('ISO-8859-1'), :out;

my $type = getline($proc);
my ($width, $height) = getline($proc).split: ' ';
my $depth = getline($proc);

my Bitmap $b = Bitmap.new( width => $width.Int, height => $height.Int) but PPM;

$b.data = $proc.out.slurp.ords.rotor(3).map:
  { Pixel.new(R => .[0], G => .[1], B => .[2]) };

'./camelia.ppm'.IO.open(:bin, :w).write: $b.P6;

See camelia image here.

Ruby

Uses Raster graphics operations/Ruby.

# frozen_string_literal: true

require_relative 'raster_graphics'

class Pixmap
  def self.read_ppm(ios)
    format = ios.gets.chomp
    width, height = ios.gets.chomp.split.map(&:to_i)
    max_colour = ios.gets.chomp

    if !PIXMAP_FORMATS.include?(format) ||
       (width < 1) || (height < 1) ||
       (max_colour != '255')
      ios.close
      raise StandardError, "file '#{filename}' does not start with the expected header"
    end
    ios.binmode if PIXMAP_BINARY_FORMATS.include?(format)

    bitmap = new(width, height)
    height.times do |y|
      width.times do |x|
        # read 3 bytes
        red, green, blue = case format
                           when 'P3' then ios.gets.chomp.split
                           when 'P6' then ios.read(3).unpack('C3')
                           end
        bitmap[x, y] = RGBColour.new(red, green, blue)
      end
    end
    ios.close
    bitmap
  end

  def self.open(filename)
    read_ppm(File.open(filename, 'r'))
  end

  def self.open_from_jpeg(filename)
    read_ppm(IO.popen("convert jpg:#{filename} ppm:-", 'r'))
  end
end

bitmap = Pixmap.open_from_jpeg('foto.jpg')
bitmap.save('foto.ppm')

Tcl

Works with: Tcl version 8.6
Library: Tk
package require Tk

proc magickalReadImage {bufferImage fileName} {
    set f [open |[list convert [file normalize $fileName] ppm:-] "rb"]
    try {
        $bufferImage put [read $f] -format ppm
    } finally {
        close $f
    }
}

Wren

Library: DOME

As DOME doesn't have a method for calling an external process (ImageMagick in this case), we re-use the small plug-in (pipeconv.so) we created in the 'PPM conversion through a pipe' task to add this functionality.

We can now use this plug-in in the following script which calls ImageMagick to convert the output_piped.jpg file to a ppm file so that we can load the latter, convert it to a gray scale image, display it and save it to a .jpg file.

import "graphics" for Canvas, ImageData, Color
import "dome" for Window, Process
import "io" for FileSystem
import "plugin" for Plugin

Plugin.load("pipeconv")

import "pipeconv" for PipeConv

class Bitmap {
    construct new(fileName, fileName2, fileName3, width, height) {
        Window.title = "Bitmap - read image via pipe"
        Window.resize(width, height)
        Canvas.resize(width, height)
        _w = width
        _h = height
        _fn3 = fileName3
        // convert .jpg file to .ppm via a pipe
        PipeConv.convert(fileName, fileName2)
        // load the .ppm file
        loadPPMFile(fileName2)
    }

    init() {
        toGrayScale()
        // display gray scale image
        _bmp2.draw(0, 0)
        // save it to file
        _bmp2.saveToFile(_fn3)
    }

    loadPPMFile(fileName) {
        var ppm = FileSystem.load(fileName)
        var count = ppm.count //ensure file is fully loaded before proceeding 
        if (ppm[0..1] != "P6") {
            System.print("The loaded file is not a P6 file.")
            Process.exit()
        }
        var lines = ppm.split("\n")
        if (Num.fromString(lines[2]) > 255) {
            System.print("The maximum color value can't exceed 255.")
            Process.exit()
        }
        var wh = lines[1].split(" ")
        var w = Num.fromString(wh[0])
        var h = Num.fromString(wh[1])
        _bmp = ImageData.create(fileName, w, h)
        var bytes = ppm.bytes
        var i = bytes.count - 3 * w * h
        for (y in 0...h) {
            for (x in 0...w) {
                var r = bytes[i]
                var g = bytes[i+1]
                var b = bytes[i+2]
                var c = Color.rgb(r, g, b)
                pset(x, y, c)
                i = i + 3
            }
        }
    }

    toGrayScale() {
        _bmp2 = ImageData.create("gray scale", _bmp.width, _bmp.height)
        for (x in 0..._bmp.width) {
            for (y in 0..._bmp.height) {
                var c1 = _bmp.pget(x, y)
                var lumin = (0.2126 * c1.r + 0.7152 * c1.g + 0.0722 * c1.b).floor
                var c2 = Color.rgb(lumin, lumin,lumin, c1.a)
                _bmp2.pset(x, y, c2)
            }
        }
    }

    pset(x, y, col) { _bmp.pset(x, y, col) }

    pget(x, y) { _bmp.pget(x, y) }

    update() {}

    draw(alpha) {}
}

var Game = Bitmap.new("output_piped.jpg", "output_piped.ppm", "output_piped_gs.jpg", 350, 350)

zkl

Translation of: C

Uses the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl

Using the convert utility by ImageMagick:

p:=System.popen(0'|convert "fractalTree.jpg" ppm:-|,"r");
img:=PPM.readPPM(p); p.close();