Bitmap/Read a PPM file: Difference between revisions

Updated to work with Nim version 1.4; changed header parsing to conform to PPM specs; added integrity checks.
(Updated to work with Nim version 1.4; changed header parsing to conform to PPM specs; added integrity checks.)
Line 1,355:
=={{header|Nim}}==
<lang nim>import strutils
import bitmap
 
type FormatError = object of CatchableError
proc readPPM(f: TFile): Image =
if f.readLine != "P6":
raise newException(E_base, "Invalid file format")
 
# States used to parse the header.
var line = ""
type State = enum waitingMagic, waitingWidth, waitingHeight, waitingColors
while f.readLine(line):
 
if line[0] != '#':
#---------------------------------------------------------------------------------------------------
 
iterator tokens(f: File): tuple[value: string, lastInLine: bool] =
## Yield the tokens in the header.
varfor line =in ""f.lines:
if not line[0] != .startsWith('#'):
let fields = line.splitWhitespace()
for i, t in fields:
yield (t, i == fields.high)
 
#---------------------------------------------------------------------------------------------------
 
proc getInt(s: string): int {.inline.} =
## Try to parse an int. Raise an exception if not an integer.
try:
result = s.parseInt()
except ValueError:
raise newException(FormatError, "Invalid value")
 
#---------------------------------------------------------------------------------------------------
 
proc header(f: File): tuple[width, height: Index] =
## Read the header and retrun the image width and height.
var state = waitingMagic
for (token, lastInLine) in f.tokens:
case state
of waitingMagic:
if f.readLinetoken != "P6":
raise newException(E_baseFormatError, "Invalid file formatheader")
of waitingWidth:
result.width = token.getInt()
of waitingHeight:
result.height = token.getInt()
of waitingColors:
if ftoken.readLinegetInt() != "255":
raise newException(E_baseFormatError, "Invalid filenumber of formatcolors")
if not lastInLine:
raise newException(FormatError, "Invalid data after number of colors")
break
state = succ(state)
 
#---------------------------------------------------------------------------------------------------
var parts = line.split(" ")
result = img(parseInt parts[0], parseInt parts[1])
 
proc readPPM(f: TFileFile): Image =
if f.readLine != "255":
## Read a PPM file into an image.
raise newException(E_base, "Invalid file format")
 
let header = f.header()
result = initImage(header.width, header.height)
 
var
Line 1,377 ⟶ 1,417:
 
while read != 0:
for i in 0 .. < read:
case pos mod 3
of 0: result.pixels[pos div 3].r = arr[i].uint8
Line 1,383 ⟶ 1,423:
of 2: result.pixels[pos div 3].b = arr[i].uint8
else: discard
 
inc pos
 
read = f.readBytes(arr, 0, 256)</lang>
 
if pos != 3 * result.w * result.h:
raise newException(FormatError, "Truncated file")
 
#---------------------------------------------------------------------------------------------------
 
proc readPPM*(filename: string): Image =
## Load a PPM file into an image.
 
var file = open(filename, fmRead)
result = file.readPPM()
file.close()</lang>
 
=={{header|OCaml}}==
Anonymous user