slyrus / opticl

An image processing library for Common Lisp
Other
182 stars 35 forks source link

Read CMYK jpeg files. #19

Closed knobo closed 2 years ago

knobo commented 7 years ago

With the latest cl-jpeg package we can read cmyk files. Here is an example on how to do it:

--- jpeg.lisp.orig  2017-01-16 11:22:39.029990889 +0100
+++ jpeg.lisp   2017-01-16 11:41:02.245207289 +0100
@@ -5,6 +5,7 @@

 (defconstant +ncomp-gray+ 1)
 (defconstant +ncomp-rgb+ 3)
+(defconstant +ncomp-cmyk+ 4)

 (defparameter *rgb-sampling* '((1 1)(1 1)(1 1)))
 (defparameter *rgb-q-tabs* (vector jpeg::+q-luminance-hi+
@@ -16,9 +17,12 @@
 (defun read-jpeg-stream (stream)
   (multiple-value-bind (buffer height width ncomp)
       (jpeg:decode-stream stream)
-    (cond
-      ((= ncomp +ncomp-rgb+)
-       (let ((image (make-8-bit-rgb-image height width)))
+    (ecase ncomp
+      ((#.+ncomp-rgb+ #.+ncomp-cmyk+)
+       (let ((image (make-8-bit-rgb-image height width))
+             (buffer (if (eql +ncomp-cmyk+ ncomp)
+                         (jpeg:convert-cmyk-to-rgb buffer height width)
+                         buffer)))
          (declare (type 8-bit-rgb-image image))
          (loop for i below height
             do 
@@ -30,7 +34,7 @@
                                    (aref buffer (+ 1 pixoff))
                                    (aref buffer  pixoff))))))
          image))
-      ((= ncomp 1)
+      (#.+ncomp-gray+
        (let ((image (make-8-bit-gray-image height width))
              (pixoff 0))
          (declare (type 8-bit-gray-image image))
knobo commented 7 years ago

I was not able to compile the master branch so I did not provide a pull request. There was a missing tiff2 package.

slyrus commented 7 years ago

@knobo tiff2 is in the latest retrospectiff. thanks for the patch. i'll take a look in more detail later today.

slyrus commented 7 years ago

@knobo do you have any sample CMYK jpeg images? I don't think cl-jpeg lets me write CMYK images.

knobo commented 7 years ago

You can create with ImageMagick convert -colorspace CMYK file-rbg.jpg file-cmyk.jpg

$ convert -colorspace RGB -size 100x100 xc:#990000 test-rgb.jpg
$ convert -colorspace CMYK -size 100x100 xc:#990000 test-cmyk.jpg
$ identify -verbose test-* | grep -i colorspace
  Colorspace: CMYK
    jpeg:colorspace: 4
  Colorspace: sRGB
    jpeg:colorspace: 2
knobo commented 5 years ago

In the example in my comment I used ImageMagics command "convert" In case you don't have ImageMagic installed, I send the files here:

test-cmyk: test-cmyk test-rgb test-rgb

slyrus commented 2 years ago

Thanks for the suggestion. I've adapted your approach, modified it a bit and committed it.

knobo commented 2 years ago

Just out of curiosity, why do you use let instead of for

(loop for j below width
      do
         (let ((pixoff (* +ncomp-rgb+ (+ (* i width) j))))
           (setf (pixel image i j)
                 (values (aref buffer (+ 2 pixoff))
                         (aref buffer (+ 1 pixoff))
                         (aref buffer  pixoff)))))

instead of

(loop for j below width
      for pixoff = (* +ncomp-rgb+ (+ (* i width) j))
      do
         (setf (pixel image i j)
               (values (aref buffer (+ 2 pixoff))
                       (aref buffer (+ 1 pixoff))
                       (aref buffer  pixoff)))))

here: https://github.com/slyrus/opticl/commit/62f0cac8d0fd1a5b8ec8e91050fa2d8a27672274#diff-40c7cdb2998710d4b087f70030ca3b661c44a7bbccffcba0044c9befdbe87da2R27

If I was not going to use loop features, then I'd use dotimes instead

(dotimes (j width)
  (let ((pixoff (* +ncomp-rgb+ (+ (* i width) j))))
    (setf (pixel image i j)
          (values (aref buffer (+ 2 pixoff))
                  (aref buffer (+ 1 pixoff))
                  (aref buffer  pixoff)))))