PGM to PNG

Abishek GodaAbishek Goda
2 min read

I've been tinkering with ROS using ROS2Djs over ROS bridge and their excellent simulation environment. Along the way, I learnt that ROS saves its maps as a PGM file. An excellent idea, if you think about it. It is textual and lends itself well to algorithmic processing. But I am not aware of a way to display a PGM file on the browser like the image that it is.

I was initially experimenting with Python since ROS has excellent support for python. Then I tried to repeat my experiments using Common Lisp. ROS1 has pretty good support for CL, if not at Python levels. I used the excellent PIL API in python to get the conversion going. The code was as simple as this:

# python2. yikes!
buffer = cStringIO.StringIO()
pgm = Image.open(filename)
pgm.save(buffer, format="png")

I could have tried the same thing using Common Lisp libraries for image magick. But then, I wanted to give myself a little challenge. There is an excellent png library for common lisp and another excellent netpbm library for common lisp too. So I decided to write a simple glue code combining these two libraries with doing my bidding. Here is what that glue looks like:

;; damn, there is still no support for common lisp syntax? I should
;; move away I guess

(defun read-pgm (pgm-filename)
  "reads a pgm file and returns the data array"
  (netpbm:read-from-file pgm-filename))

(defun convert-to-1d-array (2d-data)
  "read-pgm returns a 2d simple-array. We need a 1d vector for png generation."
  (let* ((rows (array-dimension 2d-data 0))
         (cols (array-dimension 2d-data 1))
         (1d-data '()))
    (dotimes (r rows)
      (dotimes (c cols)
        (setf 1d-data (append 1d-data (list (aref 2d-data r c))))))
    (make-array (* rows cols) :initial-contents 1d-data :element-type '(unsigned-byte 8))))

(defun generate-png (pgm-filename)
  (let* ((pgm-data (read-pgm pgm-filename))
         (w (array-dimension pgm-data 0))
         (h (array-dimension pgm-data 1))
         (image-data (convert-to-1d-array pgm-data)))
    (type-of image-data)
    (make-instance 'zpng:png
      :color-type :grayscale
      :width w
      :height h
      :image-data image-data)))

(defun write-pngfile (pgm-filename png-filename)
  "reads in a pgm file and writes out a png image"
  (let ((png-data (generate-png pgm-filename)))
    (format t "generating png file.")
    (zpng:write-png png-data png-filename)))

I hope you find that helpful. I am considering making a package with these utilities: pgm -> png, jpg; files and base64 strings and releasing it into the wild.

0
Subscribe to my newsletter

Read articles from Abishek Goda directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Abishek Goda
Abishek Goda