Bitmap/Write a PPM file: Difference between revisions
m →{{header|Python}}: Remove the old func. |
m Fixed lang tags. |
||
Line 6: | Line 6: | ||
=={{header|Ada}}== |
=={{header|Ada}}== |
||
<lang ada> |
<lang ada>with Ada.Characters.Latin_1; |
||
with Ada.Characters.Latin_1; |
|||
with Ada.Streams.Stream_IO; use Ada.Streams.Stream_IO; |
with Ada.Streams.Stream_IO; use Ada.Streams.Stream_IO; |
||
Line 32: | Line 31: | ||
end loop; |
end loop; |
||
Character'Write (Stream (File), LF); |
Character'Write (Stream (File), LF); |
||
end Put_PPM; |
end Put_PPM;</lang> |
||
⚫ | |||
The solution writes the image into an opened file. The file format might fail to work on certain [[OS]]es, because output might mangle control characters like LF, CR, FF, HT, VT etc. The OS might also limit the line length of a text file. In general it is a bad idea to mix binary and text output in one file. This solution uses ''stream I/O'', which should be as portable as possible. |
The solution writes the image into an opened file. The file format might fail to work on certain [[OS]]es, because output might mangle control characters like LF, CR, FF, HT, VT etc. The OS might also limit the line length of a text file. In general it is a bad idea to mix binary and text output in one file. This solution uses ''stream I/O'', which should be as portable as possible. |
||
=={{header|AutoHotkey}}== |
=={{header|AutoHotkey}}== |
||
<lang AutoHotkey> |
<lang AutoHotkey>imwrite_ppm(filename, width, height, colors) |
||
imwrite_ppm(filename, width, height, colors) |
|||
{ |
{ |
||
ppmfile = |
ppmfile = |
||
Line 48: | Line 45: | ||
} |
} |
||
imwrite_ppm("blank.ppm", 256, 256, 255) |
imwrite_ppm("blank.ppm", 256, 256, 255)</lang> |
||
⚫ | |||
=={{header|C}}== |
=={{header|C}}== |
||
Line 72: | Line 68: | ||
=={{header|C sharp|C#}}== |
=={{header|C sharp|C#}}== |
||
This implementation uses a StreamWriter to write the header in text, then writes the pixel data in binary using a BinaryWriter. |
This implementation uses a StreamWriter to write the header in text, then writes the pixel data in binary using a BinaryWriter. |
||
<lang csharp> |
<lang csharp>using System; |
||
using System; |
|||
using System.IO; |
using System.IO; |
||
class PPMWriter |
class PPMWriter |
||
Line 96: | Line 91: | ||
writerB.Close(); |
writerB.Close(); |
||
} |
} |
||
⚫ | |||
} |
|||
</lang> |
|||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
||
Line 128: | Line 122: | ||
(write-byte green stream) |
(write-byte green stream) |
||
(write-byte blue stream))))))) |
(write-byte blue stream))))))) |
||
filename) |
filename)</lang> |
||
</lang> |
|||
=={{header|D}}== |
=={{header|D}}== |
||
Line 138: | Line 131: | ||
Two additional imports are needed: |
Two additional imports are needed: |
||
⚫ | |||
<lang D> |
|||
import tango.io.protocol. |
import tango.io.protocol.model.IWriter;</lang> |
||
⚫ | |||
</lang> |
|||
P6Image will implement IWritable interface |
P6Image will implement IWritable interface |
||
<lang D> |
<lang D>class P6Image : IWritable { |
||
class P6Image : IWritable { |
|||
//.... |
//.... |
||
Line 178: | Line 168: | ||
output (); // flush |
output (); // flush |
||
} |
} |
||
⚫ | |||
} |
|||
</lang> |
|||
Saving a file is easy as a pie: |
Saving a file is easy as a pie: |
||
⚫ | |||
<lang D> |
|||
⚫ | |||
auto write = new Writer(new FileConduit("out.ppm", FileConduit.WriteCreate)); |
auto write = new Writer(new FileConduit("out.ppm", FileConduit.WriteCreate)); |
||
write (p6); |
write (p6);</lang> |
||
</lang> |
|||
=={{header|E}}== |
=={{header|E}}== |
||
Line 194: | Line 181: | ||
=={{header|Forth}}== |
=={{header|Forth}}== |
||
<lang forth>: write-ppm { bmp fid -- } |
|||
s" P6" fid write-line throw |
|||
bmp bdim swap |
|||
0 <# bl hold #s #> fid write-file throw |
|||
0 <# #s #> fid write-line throw |
|||
s" 255" fid write-line throw |
|||
bmp bdata bmp bdim * pixels |
|||
bounds do |
|||
i 3 fid write-file throw |
|||
pixel +loop ; |
|||
s" red.ppm" w/o create-file throw |
|||
test over write-ppm |
|||
close-file throw</lang> |
|||
=={{header|Fortran}}== |
=={{header|Fortran}}== |
||
Line 299: | Line 286: | ||
=={{header|J}}== |
=={{header|J}}== |
||
'''Solution:''' |
'''Solution:''' |
||
<lang j> |
<lang j>require 'files' |
||
require 'files' |
|||
NB. ($x) is height, width, colors per pixel |
NB. ($x) is height, width, colors per pixel |
||
Line 309: | Line 295: | ||
'''Example:''' |
'''Example:''' |
||
Using routines from [[Basic_bitmap_storage#J|Basic Bitmap Storage]]: |
Using routines from [[Basic_bitmap_storage#J|Basic Bitmap Storage]]: |
||
⚫ | |||
<lang j> |
|||
⚫ | |||
myimg=: ((145 + pixellist) ; 255 0 255) setPixels 0 255 0 makeRGB 600 200 |
myimg=: ((145 + pixellist) ; 255 0 255) setPixels 0 255 0 makeRGB 600 200 |
||
myimg writeppm jpath '~temp/myimg.ppm' |
myimg writeppm jpath '~temp/myimg.ppm' |
||
360015 |
360015</lang> |
||
</lang> |
|||
=={{header|Modula-3}}== |
=={{header|Modula-3}}== |
Revision as of 18:23, 22 November 2009
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
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, write the image to a PPM file (binary P6 prefered).
(Read the definition of PPM file on Wikipedia.)
Ada
<lang ada>with Ada.Characters.Latin_1; with Ada.Streams.Stream_IO; use Ada.Streams.Stream_IO;
procedure Put_PPM (File : File_Type; Picture : Image) is
use Ada.Characters.Latin_1; Size : constant String := Integer'Image (Picture'Length (2)) & Integer'Image (Picture'Length (1)); Buffer : String (1..Picture'Length (2) * 3); Color : Pixel; Index : Positive;
begin
String'Write (Stream (File), "P6" & LF); String'Write (Stream (File), Size (2..Size'Last) & LF); String'Write (Stream (File), "255" & LF); for I in Picture'Range (1) loop Index := Buffer'First; for J in Picture'Range (2) loop Color := Picture (I, J); Buffer (Index) := Character'Val (Color.R); Buffer (Index + 1) := Character'Val (Color.G); Buffer (Index + 2) := Character'Val (Color.B); Index := Index + 3; end loop; String'Write (Stream (File), Buffer); end loop; Character'Write (Stream (File), LF);
end Put_PPM;</lang> The solution writes the image into an opened file. The file format might fail to work on certain OSes, because output might mangle control characters like LF, CR, FF, HT, VT etc. The OS might also limit the line length of a text file. In general it is a bad idea to mix binary and text output in one file. This solution uses stream I/O, which should be as portable as possible.
AutoHotkey
<lang AutoHotkey>imwrite_ppm(filename, width, height, colors) { ppmfile = ( P6 %width% %height% %colors% )
FileAppend, %ppmfile%, %filename%
}
imwrite_ppm("blank.ppm", 256, 256, 255)</lang>
C
Interface:
<lang c>void output_ppm(FILE *fd, image img);</lang>
Implementation:
<lang c>#include "imglib.h"
void output_ppm(FILE *fd, image img) {
unsigned int n; fprintf(fd, "P6\n%d %d\n255\n", img->width, img->height); n = img->width * img->height; fwrite(img->buf, sizeof(pixel), n, fd); fflush(fd);
}</lang>
C#
This implementation uses a StreamWriter to write the header in text, then writes the pixel data in binary using a BinaryWriter. <lang csharp>using System; using System.IO; class PPMWriter {
public static void WriteBitmapToPPM(string file, Bitmap bitmap){ //Use a streamwriter to write the text part of the encoding var writer = new StreamWriter(file); writer.Write("P6" + Environment.NewLine); writer.Write(bitmap.Width + " " +bitmap.Height + Environment.NewLine); writer.Write("255" + Environment.NewLine); writer.Close(); //Switch to a binary writer to write the data var writerB = new BinaryWriter(new FileStream(file, FileMode.Append)); for(int x=0; x<bitmap.Width;x++) for (int y = 0; y < bitmap.Height; y++) { var color = bitmap.GetPixel(x, y); writerB.Write(color.Red); writerB.Write(color.Green); writerB.Write(color.Blue); } writerB.Close(); }
}</lang>
Common Lisp
<lang lisp>(defun write-rgb-buffer-to-ppm-file (filename buffer)
(with-open-file (stream filename
:element-type '(unsigned-byte 8) :direction :output :if-does-not-exist :create :if-exists :supersede)
(let* ((dimensions (array-dimensions buffer))
(width (first dimensions)) (height (second dimensions)) (header (format nil "P6~A~D ~D~A255~A" #\newline width height #\newline #\newline)))
(loop
:for char :across header :do (write-byte (char-code char) stream)) #| Assumes char-codes match ASCII |#
(loop
:for x :upfrom 0 :below width :do (loop :for y :upfrom 0 :below height :do (let ((pixel (rgb-pixel buffer x y))) (let ((red (rgb-pixel-red pixel)) (green (rgb-pixel-green pixel)) (blue (rgb-pixel-blue pixel))) (write-byte red stream) (write-byte green stream) (write-byte blue stream)))))))
filename)</lang>
D
This describes modifications that needs to be done to class P6Image described on Read ppm file problem page.
Two additional imports are needed: <lang D>import tango.io.protocol.Writer; import tango.io.protocol.model.IWriter;</lang>
P6Image will implement IWritable interface <lang D>class P6Image : IWritable {
//....
// additional convinient constructor this(RgbBitmap bitmap, ubyte maxVal) { this.bitmap = bitmap; _maxVal = maxVal; gotImg = 1; }
// implements tango's IWritable, only one method needed override void write (IWriter output) { static const char space = ' '; static const char newline = '\n'; if (! gotImg) throw new NoImageException;
// unfortunatelly, we can't output(type), // because arrays are prefixed with array length by IWriter foreach (sign; type) output (sign); output (newline); foreach (sign; .toString(bitmap.width)) output (sign); output (space); foreach (sign; .toString(bitmap.height)) output (sign); output (newline);
foreach (sign; .toString(_maxVal)) output (sign); output (newline);
output.buffer.append(bitmap.data); output (); // flush }
}</lang>
Saving a file is easy as a pie: <lang D>auto p6 = new P6Image(new FileConduit("image.ppm")); auto write = new Writer(new FileConduit("out.ppm", FileConduit.WriteCreate));
write (p6);</lang>
E
The code for this task is incorporated into Basic bitmap storage#E.
Forth
<lang forth>: write-ppm { bmp fid -- }
s" P6" fid write-line throw bmp bdim swap 0 <# bl hold #s #> fid write-file throw 0 <# #s #> fid write-line throw s" 255" fid write-line throw bmp bdata bmp bdim * pixels bounds do i 3 fid write-file throw pixel +loop ;
s" red.ppm" w/o create-file throw test over write-ppm close-file throw</lang>
Fortran
It loads RCImageBasic
module, which is defined here.
<lang fortran>module RCImageIO
use RCImageBasic
implicit none
contains
subroutine output_ppm(u, img) integer, intent(in) :: u type(rgbimage), intent(in) :: img integer :: i, j
write(u, '(A2)') 'P6' write(u, '(I0, ,I0)') img%width, img%height write(u, '(A)') '255' do j=1, img%height do i=1, img%width write(u, '(3A1)', advance='no') achar(img%red(i,j)), achar(img%green(i,j)), & achar(img%blue(i,j)) end do end do
end subroutine output_ppm
end module RCImageIO</lang>
Haskell
<lang haskell>{-# LANGUAGE ScopedTypeVariables #-}
module Bitmap.Netpbm(readNetpbm, writeNetpbm) where
import Bitmap import Data.Char import System.IO import Control.Monad import Control.Monad.ST import Data.Array.ST
nil :: a nil = undefined
readNetpbm :: forall c. Color c => FilePath -> IO (Image RealWorld c) readNetpbm path = do
h <- openFile path ReadMode let die = hClose h >> fail "readImage: bad format" ppm <- hGetContents h let (s, rest) = splitAt 2 ppm unless (s == magicNumber) die let getNum :: String -> IO (Int, String) getNum ppm = do let (s, rest) = span isDigit $ skipBlanks ppm when (null s) die return (read s, rest) (width, rest) <- getNum rest (height, rest) <- getNum rest (_, c : rest) <- if getMaxval then getNum rest else return (nil, rest) unless (isSpace c) die i <- stToIO $ listImage width height $ fromNetpbm $ map fromEnum rest hClose h return i where skipBlanks = dropWhile isSpace . until ((/= '#') . head) (tail . dropWhile (/= '\n')) . dropWhile isSpace magicNumber = netpbmMagicNumber (nil :: c) getMaxval = not $ null $ netpbmMaxval (nil :: c)
writeNetpbm :: forall c. Color c => FilePath -> Image RealWorld c -> IO () writeNetpbm path i = do
h <- openFile path WriteMode (width, height) <- stToIO $ dimensions i let w = hPutStrLn h w $ magicNumber w $ show width ++ " " ++ show height if null maxval then return () else w maxval stToIO (getPixels i) >>= hPutStr h . toNetpbm hClose h where magicNumber = netpbmMagicNumber (nil :: c) maxval = netpbmMaxval (nil :: c)</lang>
J
Solution: <lang j>require 'files'
NB. ($x) is height, width, colors per pixel writeppm=:dyad define
header=. 'P6',LF,(":1 0{$x),LF,'255',LF (header,,x{a.) fwrite y
)</lang> Example: Using routines from Basic Bitmap Storage: <lang j> NB. create 10 by 10 block of magenta pixels in top right quadrant of a 300 wide by 600 high green image
myimg=: ((145 + pixellist) ; 255 0 255) setPixels 0 255 0 makeRGB 600 200 myimg writeppm jpath '~temp/myimg.ppm'
360015</lang>
Modula-3
Bitmap
is the module from Basic Bitmap Storage.
<lang modula3>INTERFACE PPM;
IMPORT Bitmap, Pathname;
PROCEDURE Create(imgfile: Pathname.T; img: Bitmap.T);
END PPM.</lang> <lang modula3>MODULE PPM;
IMPORT Bitmap, Wr, FileWr, Pathname; FROM Fmt IMPORT F, Int;
<*FATAL ANY*>
VAR imgfilewr: FileWr.T;
PROCEDURE Create(imgfile: Pathname.T; img: Bitmap.T) =
VAR height := LAST(img^); width := LAST(img[0]); color: Bitmap.Pixel; BEGIN imgfilewr := FileWr.Open(imgfile); Wr.PutText(imgfilewr, F("P6\n%s %s\n255\n", Int(height + 1), Int(width + 1))); FOR i := 0 TO height DO FOR j := 0 TO width DO color := img[i,j]; Wr.PutChar(imgfilewr, VAL(color.R, CHAR)); Wr.PutChar(imgfilewr, VAL(color.G, CHAR)); Wr.PutChar(imgfilewr, VAL(color.B, CHAR)); END; END; Wr.PutChar(imgfilewr, '\n'); Wr.Flush(imgfilewr); END Create;
BEGIN END PPM.</lang>
OCaml
<lang ocaml>let output_ppm ~oc ~img:(_, r_channel, g_channel, b_channel) =
let width = Bigarray.Array2.dim1 r_channel and height = Bigarray.Array2.dim2 r_channel in Printf.fprintf oc "P6\n%d %d\n255\n" width height; for y = 0 to pred height do for x = 0 to pred width do output_char oc (char_of_int r_channel.{x,y}); output_char oc (char_of_int g_channel.{x,y}); output_char oc (char_of_int b_channel.{x,y}); done; done; output_char oc '\n'; flush oc;
- </lang>
Perl
Imlib2 can handle several formats, among these JPG, PNG, PNM/PPM... (but it depends on how the Imlib2 was built on the system, since the ability to load or save in these formats depends on other external libraries, like libpng e.g.)
<lang perl>#! /usr/bin/perl
use strict; use Image::Imlib2;
my $img = Image::Imlib2->new(100,100); $img->set_color(100,200,0, 255); $img->fill_rectangle(0,0,100,100);
$img->save("out0.ppm"); $img->save("out0.jpg"); $img->save("out0.png");
exit 0;</lang>
Normally Image::Imlib2 understands which output format to use from the extension; to override its guess, you can use:
<lang perl>$img->image_set_format("jpeg"); # or png, tiff, ppm ...</lang>
Python
Extending the example given here <lang python>
- String masquerading as ppm file (version P3)
import io ppmfileout = io.StringIO()
def writeppmp3(self, f):
self.writeppm(f, ppmformat='P3')
def writeppm(self, f, ppmformat='P6'):
assert ppmformat in ['P3', 'P6'], 'Format wrong' magic = ppmformat + '\n' comment = '# generated from Bitmap.writeppm\n' maxval = max(max(max(bit) for bit in row) for row in self.map) assert ppmformat == 'P3' or 0 <= maxval < 256, 'R,G,B must fit in a byte' if ppmformat == 'P6': fwrite = lambda s: f.write(bytes(s, 'UTF-8')) maxval = 255 else: fwrite = f.write numsize=len(str(maxval)) fwrite(magic) fwrite(comment) fwrite('%i %i\n%i\n' % (self.width, self.height, maxval)) for h in range(self.height-1, -1, -1): for w in range(self.width): r, g, b = self.get(w, h) if ppmformat == 'P3': fwrite(' %*i %*i %*i' % (numsize, r, numsize, g, numsize, b)) else: fwrite('%c%c%c' % (r, g, b)) if ppmformat == 'P3': fwrite('\n')
Bitmap.writeppmp3 = writeppmp3 Bitmap.writeppm = writeppm
- Draw something simple
bitmap = Bitmap(4, 4, black) bitmap.fillrect(1, 0, 1, 2, white) bitmap.set(3, 3, Colour(127, 0, 63))
- Write to the open 'file' handle
bitmap.writeppmp3(ppmfileout)
- Whats in the generated PPM file
print(ppmfileout.getvalue())
The print statement above produces the following output :
P3
- generated from Bitmap.writeppmp3
4 4 255
0 0 0 0 0 0 0 0 0 127 0 63 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0
- Write a P6 file
ppmfileout = open('tmp.ppm', 'wb') bitmap.writeppm(ppmfileout) ppmfileout.close() </lang>
R
<lang r>
- View the existing code in the library
library(pixmap) pixmap::write.pnm
- Usage
write.pnm(theimage, filename) </lang>
Ruby
Extending Basic_bitmap_storage#Ruby <lang ruby>class RGBColour
def values [@red, @green, @blue] end
end
class Pixmap
def save(filename) File.open(filename, 'w') do |f| f.puts "P6", "#{@width} #{@height}", "255" f.binmode @width.times do |x| @height.times do |y| f.print @data[x][y].values.pack('C3') end end end end alias_method :write, :save
end</lang>
Tcl
Referring to Basic bitmap storage#Tcl: <lang tcl>package require Tk
proc output_ppm {image filename} {
$image write $filename -format ppm
}
set img [newImage 150 150] fill $img red setPixel $img green 40 40 output_ppm $img filename.ppm
- check the file format:
set fh [open filename.ppm] puts [gets $fh] ;# ==> P6 puts [gets $fh] ;# ==> 150 150 puts [gets $fh] ;# ==> 255 binary scan [read $fh 3] c3 pixel foreach colour $pixel {puts [expr {$colour & 0xff}]} ;# ==> 255 \n 0 \n 0 \n close $fh</lang>
Vedit macro language
This routine creates a RAW PPM file (binary). Pixel data must be stored in edit buffer pointed by numeric register #10. The data in the buffer is assumed to be in R,G,B order, which is the order used by PPM file.
///////////////////////////////////////////////////////////////////// // // Save image as PPM file. // @10 = filename. Buffer #10 contains the Pixel data. // :SAVE_PPM: Buf_Switch(#10) BOF IT("P6") IN Num_Ins(#11, LEFT) // width of image Num_Ins(#12, LEFT) // height of image Num_Ins(255, LEFT+NOCR) // maxval IC(10) File_Save_As(@10, OK) Return