Bitmap/PPM conversion through a pipe

From Rosetta Code
Revision as of 11:35, 4 September 2009 by rosettacode>Glennj (add Ruby)
Task
Bitmap/PPM conversion through a pipe
You are encouraged to solve this task according to the task description, using any language you may know.

Using the data storage type defined on this page for raster images, delegate writing a JPEG file through a pipe using the output_ppm function defined on this other page.

There are various utilities that can be used for this task, for example: cjpeg (package "jpeg-progs" on Linux), ppmtojpeg (package "netpbm" on Linux), convert (from ImageMagick, multi-platform).

C

Works with: POSIX version .1-2001

This one uses the ImageMagick convert tool.

<lang c>/* interface */ void print_jpg(image img, int qual);</lang>

<lang c>#define MAXCMDBUF 100 void print_jpg(image img, int qual) {

  char buf[MAXCMDBUF];
  unsigned int n;
  FILE *pipe;
  
  snprintf(buf, MAXCMDBUF, "convert ppm:- -quality %d jpg:-", qual);
  pipe = popen(buf, "w");
  if ( pipe != NULL )
  {
          fprintf(pipe, "P6\n%d %d\n255\n", img->width, img->height);
          n = img->width * img->height;
          fwrite(img->buf, sizeof(pixel), n, pipe);
          pclose(pipe);
  }

}</lang>

The code that writes to the pipe is the same of output_ppm of course. A complete example is

<lang c>#include "imglib.h"

int main() {

     image img;
     
     img = alloc_img(100,100);
     fill_img(img, 50, 20, 200);
     draw_line(img, 0, 0, 80, 80, 255, 0, 0);
     print_jpg(img, 75);
     free_img(img);

} </lang>

In order to make it working, you must link it with the raster image functions given by the codes here and here

OCaml

<lang ocaml>let print_jpeg ~img ?(quality=96) () =

 let cmd = Printf.sprintf "cjpeg -quality %d" quality in
 (*
 let cmd = Printf.sprintf "ppmtojpeg -quality %d" quality in
 let cmd = Printf.sprintf "convert ppm:- -quality %d jpg:-" quality in
 *)
 let ic, oc = Unix.open_process cmd in
 output_ppm ~img ~oc;
 try
   while true do
     let c = input_char ic in
     print_char c
   done
 with End_of_file -> ()
</lang>

Ruby

Extends Write ppm file#Ruby. Uses the ImageMagick convert tool. Additionally, for debugging, allow writing in pixmap P3 (ascii) format.

<lang ruby>class Pixmap

 PIXMAP_FORMATS = ["P3", "P6"]   # implemented output formats
 PIXMAP_BINARY_FORMATS = ["P6"]  # implemented output formats which are binary
 def write_ppm(ios, format="P6")
   if not PIXMAP_FORMATS.include?(format)
     raise NotImplementedError, "pixmap format #{format} has not been implemented" 
   end
   ios.puts format, "#{@width} #{@height}", "255"
   ios.binmode if PIXMAP_BINARY_FORMATS.include?(format)
   @height.times do |y|
     @width.times do |x|
       case format
       when "P3" then ios.print @data[x][y].values.join(" "),"\n"
       when "P6" then ios.print @data[x][y].values.pack('C3')
       end
     end
   end
 end
 def save(filename, opts={:format=>"P6"})
   File.open(filename, 'w') do |f|
     write_ppm(f, opts[:format])
   end
 end
 def print(opts={:format=>"P6"})
   write_ppm($stdout, opts[:format])
 end
 def save_as_jpeg(filename, quality=75)
   pipe = IO.popen("convert ppm:- -quality #{quality} jpg:#{filename}", 'w')
   write_ppm(pipe)
   pipe.close
 end

end

image = Pixmap.open('file.ppm') image.save_as_jpeg('file.jpg')</lang>

Tcl

Referring to Write ppm file#Tcl and Basic bitmap storage#Tcl

Library: Tk

<lang tcl>package require Tk

proc output_jpeg {image filename {quality 75}} {

   set f [open |[list convert ppm:- -quality $quality jpg:- > $filename] w]
   fconfigure $f -translation binary
   puts -nonewline $f [$image data -format ppm]
   close $f

}</lang>

However, it is more normal to do this directly with the

Library: TkImg

which is bundled with many Tcl distributions.

<lang tcl>package require Tk package require img::jpeg

proc output_jpeg {image filename} {

   $image write $filename -format jpeg

} set img [image create photo -filename filename.ppm] output_jpeg $img filename.jpg</lang>