June 2018 Update
This commit is contained in:
parent
ba8067c3b7
commit
22f33d4004
5278 changed files with 84726 additions and 14379 deletions
102
Task/Bitmap-Read-a-PPM-file/Erlang/bitmap-read-a-ppm-file-1.erl
Normal file
102
Task/Bitmap-Read-a-PPM-file/Erlang/bitmap-read-a-ppm-file-1.erl
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
% This module provides basic operations on ppm files:
|
||||
% Read from file, create ppm in memory (from generic bitmap) and save to file.
|
||||
% Writing PPM files was introduced in roseta code task 'Bitmap/Write a PPM file'
|
||||
% but the same code is included here to provide whole set of operations on ppm
|
||||
% needed for purposes of this task.
|
||||
|
||||
-module(ppm).
|
||||
|
||||
-export([ppm/1, write/2, read/1]).
|
||||
|
||||
% constants for writing ppm file
|
||||
-define(WHITESPACE, <<10>>).
|
||||
-define(SPACE, <<32>>).
|
||||
|
||||
% constants for reading ppm file
|
||||
-define(WHITESPACES, [9, 10, 13, 32]).
|
||||
-define(PPM_HEADER, "P6").
|
||||
|
||||
% data structure introduced in task Bitmap (module ros_bitmap.erl)
|
||||
-record(bitmap, {
|
||||
mode = rgb,
|
||||
pixels = nil,
|
||||
shape = {0, 0}
|
||||
}).
|
||||
|
||||
%%%%%%%%% API %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
% read ppm file from file
|
||||
read(Filename) ->
|
||||
{ok, File} = file:read_file(Filename),
|
||||
parse(File).
|
||||
|
||||
% create ppm image from bitmap record
|
||||
ppm(Bitmap) ->
|
||||
{Width, Height} = Bitmap#bitmap.shape,
|
||||
Pixels = ppm_pixels(Bitmap),
|
||||
Maxval = 255, % original ppm format maximum
|
||||
list_to_binary([
|
||||
header(), width_and_height(Width, Height), maxval(Maxval), Pixels]).
|
||||
|
||||
% write bitmap as ppm file
|
||||
write(Bitmap, Filename) ->
|
||||
Ppm = ppm(Bitmap),
|
||||
{ok, File} = file:open(Filename, [binary, write]),
|
||||
file:write(File, Ppm),
|
||||
file:close(File).
|
||||
|
||||
%%%%%%%%% Reading PPM %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
parse(Binary) ->
|
||||
{?PPM_HEADER, Data} = get_next_token(Binary),
|
||||
{Width, HeightAndRest} = get_next_token(Data),
|
||||
{Height, MaxValAndRest} = get_next_token(HeightAndRest),
|
||||
{_MaxVal, RawPixels} = get_next_token(MaxValAndRest),
|
||||
Shape = {list_to_integer(Width), list_to_integer(Height)},
|
||||
Pixels = load_pixels(RawPixels),
|
||||
#bitmap{pixels=Pixels, shape=Shape}.
|
||||
|
||||
% load binary as a list of RGB triplets
|
||||
load_pixels(Binary) when is_binary(Binary)->
|
||||
load_pixels([], Binary).
|
||||
load_pixels(Acc, <<>>) ->
|
||||
array:from_list(lists:reverse(Acc));
|
||||
load_pixels(Acc, <<R, G, B, Rest/binary>>) ->
|
||||
load_pixels([<<R,G,B>>|Acc], Rest).
|
||||
|
||||
is_whitespace(Byte) ->
|
||||
lists:member(Byte, ?WHITESPACES).
|
||||
|
||||
% get next part of PPM file, skip whitespaces, and return the rest of a binary
|
||||
get_next_token(Binary) ->
|
||||
get_next_token("", true, Binary).
|
||||
get_next_token(CurrentToken, false, <<Byte, Rest/binary>>) ->
|
||||
case is_whitespace(Byte) of
|
||||
true ->
|
||||
{lists:reverse(CurrentToken), Rest};
|
||||
false ->
|
||||
get_next_token([Byte | CurrentToken], false, Rest)
|
||||
end;
|
||||
get_next_token(CurrentToken, true, <<Byte, Rest/binary>>) ->
|
||||
case is_whitespace(Byte) of
|
||||
true ->
|
||||
get_next_token(CurrentToken, true, Rest);
|
||||
false ->
|
||||
get_next_token([Byte | CurrentToken], false, Rest)
|
||||
end.
|
||||
|
||||
%%%%%%%%% Writing PPM %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
header() ->
|
||||
[<<"P6">>, ?WHITESPACE].
|
||||
|
||||
width_and_height(Width, Height) ->
|
||||
[encode_decimal(Width), ?SPACE, encode_decimal(Height), ?WHITESPACE].
|
||||
|
||||
maxval(Maxval) ->
|
||||
[encode_decimal(Maxval), ?WHITESPACE].
|
||||
|
||||
ppm_pixels(Bitmap) ->
|
||||
% 24 bit color depth
|
||||
array:to_list(Bitmap#bitmap.pixels).
|
||||
|
||||
encode_decimal(Number) ->
|
||||
integer_to_list(Number).
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
Colorful = ppm:read("colorful.ppm"),
|
||||
Gray = ros_bitmap:convert(ros_bitmap:convert(Colorful, grey), rgb),
|
||||
ppm:write(Gray, "gray.ppm"),
|
||||
|
|
@ -1,13 +1,5 @@
|
|||
using Color, Images, FixedPointNumbers
|
||||
using Images, FileIO, Netpbm
|
||||
|
||||
const M_RGB_Y = reshape(Color.M_RGB_XYZ[2,:], 3)
|
||||
|
||||
function rgb2gray(img::Image)
|
||||
g = red(img)*M_RGB_Y[1] + green(img)*M_RGB_Y[2] + blue(img)*M_RGB_Y[3]
|
||||
g = clamp(g, 0.0, 1.0)
|
||||
return grayim(g)
|
||||
end
|
||||
|
||||
ima = imread("bitmap_read_ppm_in.ppm")
|
||||
imb = convert(Image{Gray{Ufixed8}}, ima)
|
||||
imwrite(imb, "bitmap_read_ppm_out.png")
|
||||
rgbimg = load("data/bitmapInputTest.ppm")
|
||||
greyimg = Gray.(rgbimg)
|
||||
save("data/bitmapOutputTest.ppm", greyimg)
|
||||
|
|
|
|||
130
Task/Bitmap-Read-a-PPM-file/Kotlin/bitmap-read-a-ppm-file.kotlin
Normal file
130
Task/Bitmap-Read-a-PPM-file/Kotlin/bitmap-read-a-ppm-file.kotlin
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
// Version 1.2.40
|
||||
|
||||
import java.awt.Color
|
||||
import java.awt.Graphics
|
||||
import java.awt.image.BufferedImage
|
||||
import java.io.FileInputStream
|
||||
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.ppm, created in the Bitmap/Write a PPM file task
|
||||
val pbis = PushbackInputStream(FileInputStream("output.ppm"), 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_gray.jpg")
|
||||
ImageIO.write(bbs.image, "jpg", grayFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
class Pixel { has UInt ($.R, $.G, $.B) }
|
||||
class Bitmap {
|
||||
has UInt ($.width, $.height);
|
||||
has Pixel @.data;
|
||||
}
|
||||
|
||||
role PGM {
|
||||
has @.GS;
|
||||
method P5 returns Blob {
|
||||
"P5\n{self.width} {self.height}\n255\n".encode('ascii')
|
||||
~ Blob.new: self.GS
|
||||
}
|
||||
}
|
||||
|
||||
sub load-ppm ( $ppm ) {
|
||||
my $fh = $ppm.IO.open( :enc('ISO-8859-1') );
|
||||
my $type = $fh.get;
|
||||
my ($width, $height) = $fh.get.split: ' ';
|
||||
my $depth = $fh.get;
|
||||
Bitmap.new( width => $width.Int, height => $height.Int,
|
||||
data => ( $fh.slurp.ords.rotor(3).map:
|
||||
{ Pixel.new(R => $_[0], G => $_[1], B => $_[2]) } )
|
||||
)
|
||||
}
|
||||
|
||||
sub grayscale ( Bitmap $bmp ) {
|
||||
$bmp.GS = map { (.R*0.2126 + .G*0.7152 + .B*0.0722).round(1) min 255 }, $bmp.data;
|
||||
}
|
||||
|
||||
my $filename = './camelia.ppm';
|
||||
|
||||
my Bitmap $b = load-ppm( $filename ) but PGM;
|
||||
|
||||
grayscale($b);
|
||||
|
||||
'./camelia-gs.pgm'.IO.open(:bin, :w).write: $b.P5;
|
||||
36
Task/Bitmap-Read-a-PPM-file/REXX/bitmap-read-a-ppm-file.rexx
Normal file
36
Task/Bitmap-Read-a-PPM-file/REXX/bitmap-read-a-ppm-file.rexx
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*REXX program reads a PPM formatted image file, and creates a gray─scale image of it. */
|
||||
parse arg iFN oFN /*obtain optional argument from the CL.*/
|
||||
if iFN=='' | iFN=="," then iFN= 'Lenna50' /*Not specified? Then use the default.*/
|
||||
if oFN=='' | oFN=="," then oFN= 'greyscale' /* " " " " " " */
|
||||
iFID= iFN'.ppm'; oFID= oFN'.ppm' /*complete the input and output FIDs.*/
|
||||
call charin iFID, 1, 0 /*set the position of the input file. */
|
||||
y=charin(iFID, , copies(9, digits() ) ) /*read the entire input file ───► X */
|
||||
parse var y id 3 c 4 3 width height # pixels /*extract header info from the PPM hdr.*/
|
||||
LF= 'a'x /*define a comment separator (in hdr).*/ /* ◄─── LF delimiters & comments*/
|
||||
if c==LF then do; commentEND=pos(LF, y, 4) /*point to the last char in the comment*/ /* ◄─── LF delimiters & comments*/
|
||||
parse var y =(commentEND) +1 width height # pixels /* ◄─── LF delimiters & comments*/
|
||||
end /* ◄─── LF delimiters & comments*/
|
||||
/* [↓] has an alternative delimiter? */ /* ◄─── LF delimiters & comments*/
|
||||
z=pos(LF, height); if z\==0 then parse var height height =(z) +1 # pixels /* ◄─── LF delimiters & comments*/
|
||||
z=pos(LF, # ); if z\==0 then parse var # # =(z) +1 pixels /* ◄─── LF delimiters & comments*/
|
||||
chunk=4000 /*chunk size to be written at one time.*/
|
||||
LenPixels= length(pixels)
|
||||
|
||||
do j=0 for 256; _=d2c(j); @._=j; @@.j=_ /*build two tables for fast conversions*/
|
||||
end /*j*/
|
||||
|
||||
call charout oFID, , 1 /*set the position of the output file. */
|
||||
call charout oFID, id || width height #' ' /*write the header followed by a blank.*/
|
||||
!=1
|
||||
do until !>=LenPixels; $= /*$: partial output string so far.*/
|
||||
do !=! by 3 for chunk /*chunk: # pixels converted at 1 time.*/
|
||||
parse var pixels =(!) r +1 g +1 b +1 /*obtain the next RGB of a PPM pixel.*/
|
||||
if r=='' then leave /*has the end─of─string been reached? */
|
||||
_=(.2126*@.r + .7152*@.g + .0722*@.b )%1 /*an integer RGB greyscale of a pixel. */
|
||||
$=$ || @@._ || @@._ || @@._ /*lump (grey) R G B pixels together. */
|
||||
end /*!*/ /* [↑] D2C converts decimal ───► char*/
|
||||
call charout oFID, $ /*write the next bunch of pixels. */
|
||||
end /*until*/
|
||||
|
||||
call charout oFID /*close the output file just to be safe*/
|
||||
say 'File ' oFID " was created." /*stick a fork in it, we're all done. */
|
||||
Loading…
Add table
Add a link
Reference in a new issue