Using the data storage type defined on this page for raster images, read an image from a PPM file (binary P6 prefered).
(Read the definition of PPM file on Wikipedia.)

Task: Use write ppm file solution and grayscale image solution with this one in order to convert a color image to grayscale one.

functor
import
   Bitmap
   Open
export
   Read
   %% Write
define
   fun {Read Filename}
      F = {New Open.file init(name:Filename)}
 
      fun {ReadColor8 _}
	 Bytes = {F read(list:$ size:3)}
      in
	 {List.toTuple color Bytes}
      end
 
      fun {ReadColor16 _}
	 Bytes = {F read(list:$ size:6)}
      in
	 {List.toTuple color {Map {PairUp Bytes} FromBytes}}
      end
   in
      try
	 Magic = {F read(size:2 list:$)}
	 if Magic \= "P6" then raise bitmapIO(read unsupportedFormat(Magic)) end end
	 Width = {ReadNumber F}
	 Height = {ReadNumber F}
	 MaxVal = {ReadNumber F}
	 MaxVal =< 0xffff = true
	 Reader = if MaxVal =< 0xff then ReadColor8 else ReadColor16 end
	 B = {Bitmap.new Width Height}
      in
	 {Bitmap.transform B Reader}
	 B
      finally
	 {F close}
      end
   end
 
   fun {ReadNumber F}
      Ds
   in
      {SkipWS F}
      Ds = for collect:Collect break:Break do
	      [C] = {F read(list:$ size:1)}
	   in
	      if {Char.isDigit C} then {Collect C}
	      else {Break}
	      end
	   end
      {SkipWS F}
      {String.toInt Ds}
   end
 
   proc {SkipWS F}
      [C] = {F read(list:$ size:1)}
   in
      if {Char.isSpace C} then {SkipWS F}
      elseif C == &# then
	 {SkipLine F}
      else
	 {F seek(whence:current offset:~1)}
      end
   end
 
   proc {SkipLine F}
      [C] = {F read(list:$ size:1)}
   in
      if C \= &\n andthen  C \= &\r then {SkipLine F} end
   end
 
   fun {PairUp Xs}
      case Xs of X1|X2|Xr then [X1 X2]|{PairUp Xr}
      [] nil then nil
      end
   end
 
   fun {FromBytes [C1 C2]}
      C1 * 0x100 + C2
   end
 
   %% Omitted: Write
end