Coder Social home page Coder Social logo

cl-jpeg's Introduction

Build Status

CL-JPEG

Baseline JPEG codec written in Common Lisp. Up-to-date source is hosted on GitHub.

Written by Eugene Zaikonnikov, 1999-2017. Valuable contributors, in no particular order: Henry Harrington, Kenan Bölükbaşı, Manuel Giraud, Cyrus Harmon and William Halliburton.

Image Format

  • B, G, R pixels in case of colorspace-converted three component image
  • Y, Cb, Cr pixels in case where colorspace conversion of three component image was disabled
  • array of grayscale pixels in case of single component
  • array of 2 or 4 pixels in the case of two or four component image respectively

Decoding

(DECODE-IMAGE FILENAME &KEY BUFFER (COLORSPACE-CONVERSION T) CACHED-SOURCE-P)

  • FILENAME - jpeg file name
  • BUFFER - optional reusable storage for output image
  • COLORSPACE-CONVERSION controls if YUV to RGB should be performed
  • CACHED-SOURCE-P - the file input layer behaviour

Returns (multiple-valued) decoded IMAGE array in the same format as encoder source image, image HEIGHT and image WIDTH.

(DECODE-STREAM STREAM &KEY BUFFER (COLORSPACE-CONVERSION T) DESCRIPTOR CACHED-SOURCE-P)

  • STREAM - jpeg image stream or NIL in case where the buffer is pre-allocated in DESCRIPTOR
  • BUFFER - optional reusable storage for output image
  • COLORSPACE-CONVERSION controls if YUV to RGB should be performed
  • DESCRIPTOR is a JPEG:DESCRIPTOR structure. Can be reused for performance reasons bulk processing applications
  • CACHED-SOURCE-P - the file input layer behaviour

Returns (multiple-valued) decoded IMAGE array in the same format as encoder source image, image HEIGHT and image WIDTH.

(ALLOCATE-BUFFER HEIGHT WIDTH NCOMP)

  • HEIGHT - image height
  • WIDTH - image width
  • NCOMP - number of image components

Allocates and retruns a buffer suitable for storage of the output image in the specified geometry.

(JPEG-FILE-DIMENSIONS FILENAME)

  • FILENAME - the file to be probed

Returns image height, width, number of components, and the type of Adobe colorpsace transform encoded in the image (:YCBCR-RGB, :YCCK-CMYK).

(CONVERT-CMYK-TO-RGB BUFFER H W &key RGB-BUFFER)

  • BUFFER - the input CMYK pixel buffer
  • H,W - image dimensions
  • RGB-BUFFER - optional reusable storage for output RGB image

Returns an RGB conversion of the supplied CMYK image.

###(JPEG-TO-BMP &key INFILE OUTFILE)

Converts JPEG file to BMP file.

Encoding

(ENCODE-IMAGE FILENAME IMAGE NCOMP H W &key SAMPLING Q-TABS Q-FACTOR)

  • FILENAME - output file name
  • IMAGE - input array of pixels
  • NCOMP - number of components in the image
  • H, W - image dimensions
  • SAMPLING - sampling frequency for ncomp components by X and Y axis, e.g. '((2 2) (1 1) (1 1)) for three components, can be omitted for grayscale and RGB images
  • Q-TABS - specifies quantization tables vector, should be 1 for 1, 2 for 2, 2 for 3 and 4 entries for 4 components
  • Q-FACTOR - quality specifier (1-64), default is 64

Encodes the supplied image using the sampling specifier, quantization tables and quantization factor.

(ENCODING-WRAPPER FILENAME IMAGE NCOMP H W &key (QUALITY 4))

  • FILENAME - output file name
  • IMAGE - input array of pixels
  • NCOMP - number of components in the image
  • H, W - image dimensions
  • QUALITY - quality factor on scale from 1 to 5

TODO

  • Add progressive JPEG support in decoder

cl-jpeg's People

Contributors

froggey avatar mgi avatar slyrus avatar varjagg avatar whalliburton avatar xach avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cl-jpeg's Issues

How to convert base64 into JPEG image?

Hi,
I'm working on a third-party application in common lisp. In application on request, the server returns base64 string of user profile photo.

I want to generate an image from this base64 encoded string.

I tried byte array from base64 string using cl-base64 library's base64-string-to-usb8-array and passed it in cl-jpeg's encode-image but it creates a distorted image.

(let* ((base64-string "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")
       (byte-array (base64:base64-string-to-usb8-array base64-string))
       (output-file-spec "/tmp/image.jpeg")
       (height 618)
       (width 1000)
       (ncomp 3))
  (cl-jpeg:encode-image output-file-spec byte-array ncomp height width))

Any suggestion will be helpful.

Thanks.

Git repo vs c-l.net?

This mirror is mainly for quicklisp, am I correct? Any idea how many pulls it gets vs the upstream repository directly?

Does it make sense to keep both, or should we move it here?

Wrong type declaration in crop-image

crop-image declares outbuf to be a uint16-2d-array when it gets passed an sint16-2d-array. This works by accident when we have safety 0, but is wrong. AFAICT, crop-image is only called from one place and always gets an sint16-2d-array.

Inter-dependent forms inside eval-when

Eval this to reproduce the bug:

  • (load "~/quicklisp/dists/quicklisp/software/cl-jpeg-20170124-git/package.lisp")
  • (load "~/quicklisp/dists/quicklisp/software/cl-jpeg-20170124-git/jpeg.lisp")

+q-luminance+ is unbound

To fix it separate the macro forms that are dependent upon each other. Perhaps the define-constant macro also needs to be wrapped in an eval-when.

encoding image to bytes in memory?

Would it be possible to export the encode-image-stream method to encode the image into a flexi-streams or some such type? I am trying to use this library to generate base64 images on the fly. Also, am a newb to common lisp. So please point to an alternative approach to temp/in-memory files that I can use with encode-image if there is one. Thanks!

Expose decode-frame and friends

My retrosspectiff package uses cl-jepg for decoding jpeg-encoded TIFF images. These images have the jpeg-tables info split up from the frame info, so I can't just call decode-stream on them. It would be nice if there were stable, exported interfaces I could use instead of having to do:

(defvar *jpeg-stream*)

(defun jpeg-stream-reader ()
  (read-byte *jpeg-stream*))

(defun read-jpeg-tables (jpeg-image-info)
  (let* ((*jpeg-stream* (flexi-streams:make-in-memory-input-stream
                         (jpeg-tables jpeg-image-info))))
    (let ((image (jpeg::make-descriptor
                  :byte-reader #'jpeg-stream-reader)))
      (unless (= (jpeg::read-marker image) jpeg::+M_SOI+)
        (error "Unrecognized JPEG format"))
      (let ((marker (jpeg::interpret-markers image 0)))
        (unless (= marker jpeg::+M_EOI+)
          (error "Unrecognized JPEG format")))
      (setf (jpeg-image jpeg-image-info) image))))

(defun jpeg-decode (compressed-vector jpeg-image-info)
  ;;  NOTE: we currently read the jpeg-tables every time through. We
  ;;  should be able to cache this, but we don't as its state gets
  ;;  modified by the JPEG reading stuff and we can't just reuse it
  ;;  each time through. So..., for the moment at least, we make a new
  ;;  one each time through.
  (read-jpeg-tables jpeg-image-info)
  (let ((image (jpeg-image jpeg-image-info)))
    (let ((*jpeg-stream* (flexi-streams:make-in-memory-input-stream compressed-vector)))
      (unless (= (jpeg::read-marker image) jpeg::+M_SOI+)
        (error "Unrecognized JPEG format"))
      (let* ((marker (jpeg::interpret-markers image 0)))
        (cond ((= jpeg::+M_SOF0+ marker)
               (jpeg::decode-frame image nil)
               (jpeg::descriptor-buffer image))
              (t (error "Unsupported JPEG format: ~A" marker)))))))

Safety 0 is a bad idea

Turning safety to 0 for so much of the code is a bad idea, and can mask real bugs. See next issue...

encoding grayscale jpeg images is broken

The following should make a uniform gray image when test-encode is called:

(cl:defpackage :jpeg-test
  (:use #:cl #:jpeg))

(cl:in-package :jpeg-test)

(defun test-image (filename)
  (reduce #'merge-pathnames (list filename "images/")
          :from-end t
          :initial-value (asdf:component-pathname
                          (asdf:find-system "cl-jpeg"))))

(ensure-directories-exist (output-image ""))

(defparameter *gray-q-tabs* (vector jpeg::+q-luminance+))

(defun test-encode (&optional (output (test-image "simple.jpeg")))
  (let ((width 32)
        (height 32))
    (let ((buf (make-array (* width height) :initial-element 42)))
      (time (encode-image output buf 1 width height
                          :q-tabs *gray-q-tabs*)))))

This should give a uniform gray image, but doesn't.

a little suggestion

As we can see, there is no dct library written by common lisp. So if you can offer some inferface about dct, this project will be used more widely.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.