⚠️ Warning: This is a draft ⚠️

This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.

If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.

{{task|Raster graphics operations}}

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 output_ppm 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), '''ppmtojpeg''' (package ''"netpbm"'' on Linux), '''convert''' (from ''ImageMagick'', multi-platform).


{{works with|POSIX|.1-2001}} This one uses the ImageMagick convert tool.

/* interface */
void print_jpg(image img, int qual);
#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);

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

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

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


{{works with|Go weekly.2011-12-14}} (Go 1 should be close) Using cjpeg:

package main

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

import (

func main() {
    b := raster.NewBitmap(400, 300)
    // a little extravagant, this draws a design of dots and lines
    for i := 0; i < 2000; i++ {
        b.SetPxRgb(rand.Intn(400), rand.Intn(300), 0x804020)
    for x := 0; x < 400; x++ {
        for y := 240; y < 245; y++ {
            b.SetPxRgb(x, y, 0x804020)
        for y := 260; y < 265; y++ {
            b.SetPxRgb(x, y, 0x804020)
    for y := 0; y < 300; y++ {
        for x := 80; x < 85; x++ {
            b.SetPxRgb(x, y, 0x804020)
        for x := 95; x < 100; x++ {
            b.SetPxRgb(x, y, 0x804020)

    // pipe logic
    c := exec.Command("cjpeg", "-outfile", "pipeout.jpg")
    pipe, err := c.StdinPipe()
    if err != nil {
    err = c.Start()
    if err != nil {
    err = b.WritePpmTo(pipe)
    if err != nil {
    err = pipe.Close()
    if err != nil {


{{works with|Julia|0.6}}

using Images, FileIO

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


{{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.

// Version 1.2.40

import java.awt.Color
import java.awt.Graphics
import java.awt.image.BufferedImage

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 main(args: Array<String>) {
    // create BasicBitmapStorage object
    val width = 640
    val height = 640
    val bbs = BasicBitmapStorage(width, height)
    for (y in 0 until height) {
        for (x in 0 until width) {
            val c = Color(x % 256, y % 256, (x * y) % 256)
            bbs.setPixel(x, y, c)

    // now write the object in PPM format to ImageMagick's STDIN via a pipe
    // so it can be converted to a .jpg file and written to disk
    val pb = ProcessBuilder("convert", "-", "output_piped.jpg")
    val buffer = ByteArray(width * 3) // write one line at a time
    val proc = pb.start()
    val pStdIn = proc.outputStream
    pStdIn.use {
        val header = "P6\n$width $height\n255\n".toByteArray()
        with (it) {
            for (y in 0 until height) {
                for (x in 0 until width) {
                    val c = bbs.getPixel(x, y)
                    buffer[x * 3] = c.red.toByte()
                    buffer[x * 3 + 1] = c.green.toByte()
                    buffer[x * 3 + 2] = c.blue.toByte()


The Windows command line does not like quotes in the middle of text, so strings have been turned into character codes.


== {{Header|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;
    while true do
      let c = input_char ic in
      print_char c
  with End_of_file -> ()

Perl 6

#!/usr/bin/env perl6

# Reference:
# https://rosettacode.org/wiki/Bitmap/Write_a_PPM_file#Perl_6

use v6;

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

    method fill(Pixel $p) {
        @!data = $p.clone xx ($!width*$!height)
    method pixel(
          $i where ^$!width,
          $j where ^$!height
          --> Pixel
      ) is rw { @!data[$i*$!height + $j] }

    method data { @!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

my Bitmap $b = Bitmap.new(width => 125, height => 125) but PPM;
for flat ^$b.height X ^$b.width -> $i, $j {
    $b.pixel($i, $j) = Pixel.new: :R($i*2), :G($j*2), :B(255-$i*2);

my $proc = run '/usr/bin/convert','-','output_piped.jpg', :in;
$proc.in.write: $b.P6;


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


# Create an empty image of 120 x 90 pixels
(setq *Ppm (make (do 90 (link (need 120)))))

# Fill background with green color
(ppmFill *Ppm 0 255 0)

# Draw a diagonal line
(for I 80 (ppmSetPixel *Ppm I I 0 0 0))

# Write to "img.jpg" through a pipe
(ppmWrite *Ppm '("convert" "-" "img.jpg"))


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

im = Image.open("boxes_1.ppm")

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


(define (ppm->jpeg bitmap [jpg-file "output"] [quality 75])
  (define command (format "convert ppm:- -quality ~a jpg:~a.jpg" quality jpg-file))
  (match-define (list in out pid err ctrl)  (process command))
  (bitmap->ppm bitmap out)
  (close-input-port in)
  (close-output-port out))

(ppm->jpeg bm)


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

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

  def save(filename, opts={:format=>"P6"})
    File.open(filename, 'w') do |f|
      write_ppm(f, opts[:format])

  def print(opts={:format=>"P6"})
    write_ppm($stdout, opts[:format])

  def save_as_jpeg(filename, quality=75)
    pipe = IO.popen("convert ppm:- -quality #{quality} jpg:#{filename}", 'w')

image = Pixmap.open('file.ppm')


Referring to [[Write ppm file#Tcl]] and [[Basic bitmap storage#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

However, it is more normal to do this directly with the {{libheader|TkImg}} which is bundled with many Tcl distributions.

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


{{trans|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 ppm:- jpg:"fractal.jpg"|,"w");
img.write(p); p.close();

{{omit from|GUISS}} {{omit from|PARI/GP}} {{omit from|TI-83 BASIC}} {{omit from|TI-89 BASIC}} {{omit from|ZX Spectrum Basic|Does not have pipelining}}