Bitmap/Read an image through a pipe

From Rosetta Code
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.

AutoHotkey[edit]

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[edit]

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[edit]

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)
}
}

Mathematica[edit]

This example is untested. Please check that it's correct, debug it as necessary, and remove this message.


Export["out.bmp", ImportString[InputString[], "PPM"]];

OCaml[edit]

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 6[edit]

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.

PicoLisp[edit]

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

Racket[edit]

 
 
(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")

Ruby[edit]

Extending Read ppm file#Ruby and PPM conversion through a pipe#Ruby. Uses the ImageMagick convert tool.

class Pixmap
def self.read_ppm(ios)
format = ios.gets.chomp
width, height = ios.gets.chomp.split.map {|n| n.to_i }
max_colour = ios.gets.chomp
 
if (not PIXMAP_FORMATS.include?(format)) or
width < 1 or height < 1 or
max_colour != '255'
then
ios.close
raise StandardError, "file '#{filename}' does not start with the expected header"
end
ios.binmode if PIXMAP_BINARY_FORMATS.include?(format)
 
bitmap = self.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('file.jpg')

Tcl[edit]

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
}
}

zkl[edit]

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();