├── .gitignore ├── test.png ├── Makefile ├── LICENSE ├── src ├── buf.h ├── huff.h ├── buf.c ├── conf.h ├── enc.h ├── huff.c ├── conf.c └── enc.c ├── README.md ├── NOTICES ├── main.c └── include └── jpec.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | *.DS_Store 4 | jpec 5 | result.jpg 6 | -------------------------------------------------------------------------------- /test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Moodstocks/jpec/HEAD/test.png -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | rm=rm -f 2 | CC=cc 3 | AR=ar cq 4 | RANLIB=ranlib 5 | LIBNAME=libjpec.a 6 | CLINAME=jpec 7 | # LIB_BUILD_MODE: release or debug 8 | LIB_BUILD_MODE=release 9 | 10 | INCLUDES= -Isrc -Iinclude 11 | 12 | DEFINES= $(INCLUDES) 13 | _release_cflags= -Os -DNDEBUG 14 | _debug_cflags= -g -O0 15 | CFLAGS= $(DEFINES) -std=c99 -Wall -Werror 16 | CFLAGS+= $(_$(LIB_BUILD_MODE)_cflags) 17 | 18 | SRCS = $(wildcard src/*.c) 19 | OBJS = $(patsubst %.c,%.o,$(SRCS)) 20 | 21 | %.c.o: 22 | $(CC) $(CFLAGS) -c $*.c 23 | 24 | all: $(CLINAME) $(LIBNAME) 25 | 26 | $(LIBNAME): $(OBJS) 27 | $(rm) $@ 28 | $(AR) $@ $(OBJS) 29 | $(RANLIB) $@ 30 | 31 | $(CLINAME): $(LIBNAME) main.c 32 | $(CC) -o $@ main.c -std=c99 `pkg-config --cflags --libs opencv` -Iinclude -L. -l$@ 33 | 34 | clean: 35 | $(rm) $(OBJS) $(CLINAME) $(LIBNAME) 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2016 Moodstocks SAS 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /src/buf.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2016 Moodstocks SAS 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #ifndef JPEC_BUFFER_H 25 | #define JPEC_BUFFER_H 26 | 27 | #include 28 | 29 | /** Extensible byte buffer */ 30 | typedef struct jpec_buffer_t_ { 31 | uint8_t *stream; /* byte buffer */ 32 | int len; /* current length */ 33 | int siz; /* maximum size */ 34 | } jpec_buffer_t; 35 | 36 | jpec_buffer_t *jpec_buffer_new(void); 37 | jpec_buffer_t *jpec_buffer_new2(int siz); 38 | void jpec_buffer_del(jpec_buffer_t *b); 39 | void jpec_buffer_write_byte(jpec_buffer_t *b, int val); 40 | void jpec_buffer_write_2bytes(jpec_buffer_t *b, int val); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jpec - a JPEG encoder in C 2 | 3 | ## Overview 4 | 5 | jpec is a minimalistic JPEG encoder written in C with a focus on **simplicity**. 6 | 7 | It is both **portable** (tested on x86 and ARM) and **lightweight** (around 600 LOC). 8 | 9 | The library has no external dependencies. 10 | 11 | It is a perfect candidate if you have some embedded C code you need to extend with a JPEG encoder the easy way. 12 | 13 | ## Features 14 | 15 | The library allows you to write JPEG compressed images from input image data on memory. No more, no less. 16 | 17 | More precisely: 18 | 19 | * it works in **grayscale only** (monochrome JPEG file): there is no support for color so far, 20 | * it produces baseline, DCT-based (SOF0), JFIF 1.01 (APP0) JPEG-s, 21 | * it supports **8x8 blocks only**, 22 | * it includes default quantization and Huffman tables that are not customizable at runtime. 23 | 24 | ## Build 25 | 26 | Just type: 27 | 28 | make 29 | 30 | This produces: 31 | 32 | * `libjpec.a`: the static library, 33 | * `jpec`: a simple command-line tool used to test the library (see `main.c`) 34 | 35 | > **NOTE** the command-line tool depends on OpenCV 2 HighGUI module to easily read any kind of input image. You need to have OpenCV development libraries installed on your machine to use it (e.g. `brew install opencv` on Mac OS X with Homebrew). 36 | 37 | ## Usage 38 | 39 | If you want to embed the library into your own C code you are free to create the static library file, and include `jpec.h` main header, or to copy-paste the whole code into your project. 40 | 41 | Then, encoding a raw image is a matter of a few lines of code: 42 | 43 | ```C 44 | /* Create a JPEG encoder provided image data */ 45 | jpec_enc_t *e = jpec_enc_new(img, w, h); 46 | 47 | /* Compress */ 48 | int len; 49 | const uint8_t *jpeg = jpec_enc_run(e, &len); 50 | 51 | /* Do something with the JPEG blob (e.g. save into a file, etc) */ 52 | 53 | /* Release the encoder */ 54 | jpec_enc_del(e); 55 | ``` 56 | 57 | ## Authors 58 | 59 | [Maxime Brénon](https://github.com/mbrenon) & [Cédric Deltheil](http://about.me/deltheil). 60 | 61 | ## Copyright 62 | 63 | Copyright (c) 2012-2016 Moodstocks SAS 64 | -------------------------------------------------------------------------------- /src/huff.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2016 Moodstocks SAS 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #ifndef JPEC_HUFFMAN_H 25 | #define JPEC_HUFFMAN_H 26 | 27 | #include 28 | 29 | #include 30 | #include "enc.h" 31 | #include "buf.h" 32 | 33 | /** Entropy coding data that hold state along blocks */ 34 | typedef struct jpec_huff_state_t_ { 35 | int32_t buffer; /* bits buffer */ 36 | int nbits; /* number of bits remaining in buffer */ 37 | int dc; /* DC coefficient from previous block (or 0) */ 38 | jpec_buffer_t *buf; /* JPEG global buffer */ 39 | } jpec_huff_state_t; 40 | 41 | /** Type of an Huffman JPEG encoder */ 42 | typedef struct jpec_huff_t_ { 43 | jpec_huff_state_t state; /* state from previous block encoding */ 44 | } jpec_huff_t; 45 | 46 | /** Skeleton initialization */ 47 | void jpec_huff_skel_init(jpec_huff_skel_t *skel); 48 | 49 | jpec_huff_t *jpec_huff_new(void); 50 | 51 | void jpec_huff_del(jpec_huff_t *h); 52 | 53 | void jpec_huff_encode_block(jpec_huff_t *h, jpec_block_t *block, jpec_buffer_t *buf); 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/buf.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2016 Moodstocks SAS 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include "buf.h" 25 | #include "conf.h" 26 | 27 | #define JPEC_BUFFER_INIT_SIZ 65536 28 | 29 | jpec_buffer_t *jpec_buffer_new(void) { 30 | return jpec_buffer_new2(-1); 31 | } 32 | 33 | jpec_buffer_t *jpec_buffer_new2(int siz) { 34 | if (siz < 0) siz = 0; 35 | jpec_buffer_t *b = malloc(sizeof(*b)); 36 | b->stream = siz > 0 ? malloc(siz) : NULL; 37 | b->siz = siz; 38 | b->len = 0; 39 | return b; 40 | } 41 | 42 | void jpec_buffer_del(jpec_buffer_t *b) { 43 | assert(b); 44 | if (b->stream) free(b->stream); 45 | free(b); 46 | } 47 | 48 | void jpec_buffer_write_byte(jpec_buffer_t *b, int val) { 49 | assert(b); 50 | if (b->siz == b->len) { 51 | int nsiz = (b->siz > 0) ? 2 * b->siz : JPEC_BUFFER_INIT_SIZ; 52 | void* tmp = realloc(b->stream, nsiz); 53 | b->stream = (uint8_t *) tmp; 54 | b->siz = nsiz; 55 | } 56 | b->stream[b->len++] = (uint8_t) val; 57 | } 58 | 59 | void jpec_buffer_write_2bytes(jpec_buffer_t *b, int val) { 60 | assert(b); 61 | jpec_buffer_write_byte(b, (val >> 8) & 0xFF); 62 | jpec_buffer_write_byte(b, val & 0xFF); 63 | } 64 | -------------------------------------------------------------------------------- /src/conf.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2016 Moodstocks SAS 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #ifndef JPEC_CONF_H 25 | #define JPEC_CONF_H 26 | 27 | /* Common headers */ 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | /** Standard JPEG quantizing table */ 39 | extern const uint8_t jpec_qzr[64]; 40 | 41 | /** DCT coefficients */ 42 | extern const float jpec_dct[7]; 43 | 44 | /** Zig-zag order */ 45 | extern const int jpec_zz[64]; 46 | 47 | /** JPEG standard Huffman tables */ 48 | /** Luminance (Y) - DC */ 49 | extern const uint8_t jpec_dc_nodes[17]; 50 | extern const int jpec_dc_nb_vals; 51 | extern const uint8_t jpec_dc_vals[12]; 52 | /** Luminance (Y) - AC */ 53 | extern const uint8_t jpec_ac_nodes[17]; 54 | extern const int jpec_ac_nb_vals; 55 | extern const uint8_t jpec_ac_vals[162]; 56 | 57 | /** Huffman inverted tables */ 58 | /** Luminance (Y) - DC */ 59 | extern const uint8_t jpec_dc_len[12]; 60 | extern const int jpec_dc_code[12]; 61 | /** Luminance (Y) - AC */ 62 | extern const int8_t jpec_ac_len[256]; 63 | extern const int jpec_ac_code[256]; 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /NOTICES: -------------------------------------------------------------------------------- 1 | OpenCV 2 | ====== 3 | 4 | By downloading, copying, installing or using the software you agree to this license. 5 | If you do not agree to this license, do not download, install, 6 | copy or use the software. 7 | 8 | 9 | License Agreement 10 | For Open Source Computer Vision Library 11 | (3-clause BSD License) 12 | 13 | Copyright (C) 2000-2016, Intel Corporation, all rights reserved. 14 | Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. 15 | Copyright (C) 2009-2016, NVIDIA Corporation, all rights reserved. 16 | Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. 17 | Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved. 18 | Copyright (C) 2015-2016, Itseez Inc., all rights reserved. 19 | Third party copyrights are property of their respective owners. 20 | 21 | Redistribution and use in source and binary forms, with or without modification, 22 | are permitted provided that the following conditions are met: 23 | 24 | * Redistributions of source code must retain the above copyright notice, 25 | this list of conditions and the following disclaimer. 26 | 27 | * Redistributions in binary form must reproduce the above copyright notice, 28 | this list of conditions and the following disclaimer in the documentation 29 | and/or other materials provided with the distribution. 30 | 31 | * Neither the names of the copyright holders nor the names of the contributors 32 | may be used to endorse or promote products derived from this software 33 | without specific prior written permission. 34 | 35 | This software is provided by the copyright holders and contributors "as is" and 36 | any express or implied warranties, including, but not limited to, the implied 37 | warranties of merchantability and fitness for a particular purpose are disclaimed. 38 | In no event shall copyright holders or contributors be liable for any direct, 39 | indirect, incidental, special, exemplary, or consequential damages 40 | (including, but not limited to, procurement of substitute goods or services; 41 | loss of use, data, or profits; or business interruption) however caused 42 | and on any theory of liability, whether in contract, strict liability, 43 | or tort (including negligence or otherwise) arising in any way out of 44 | the use of this software, even if advised of the possibility of such damage. 45 | -------------------------------------------------------------------------------- /src/enc.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2016 Moodstocks SAS 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #ifndef JPEC_STREAM_H 25 | #define JPEC_STREAM_H 26 | 27 | #include 28 | 29 | #include 30 | #include "buf.h" 31 | 32 | /** Structure used to hold and process an image 8x8 block */ 33 | typedef struct jpec_block_t_ { 34 | float dct[64]; /* DCT coefficients */ 35 | int quant[64]; /* Quantization coefficients */ 36 | int zz[64]; /* Zig-Zag coefficients */ 37 | int len; /* Length of Zig-Zag coefficients */ 38 | } jpec_block_t; 39 | 40 | /** Skeleton for an Huffman entropy coder */ 41 | typedef struct jpec_huff_skel_t_ { 42 | void *opq; 43 | void (*del)(void *opq); 44 | void (*encode_block)(void *opq, jpec_block_t *block, jpec_buffer_t *buf); 45 | } jpec_huff_skel_t; 46 | 47 | /** JPEG encoder */ 48 | struct jpec_enc_t_ { 49 | /** Input image data */ 50 | const uint8_t *img; /* image buffer */ 51 | uint16_t w; /* image width */ 52 | uint16_t h; /* image height */ 53 | uint16_t w8; /* w rounded to upper multiple of 8 */ 54 | /** JPEG extensible byte buffer */ 55 | jpec_buffer_t *buf; 56 | /** Compression parameters */ 57 | int qual; /* JPEG quality factor */ 58 | int dqt[64]; /* scaled quantization matrix */ 59 | /** Current 8x8 block */ 60 | int bmax; /* maximum number of blocks (N) */ 61 | int bnum; /* block number in 0..N-1 */ 62 | uint16_t bx; /* block start X */ 63 | uint16_t by; /* block start Y */ 64 | jpec_block_t block; /* block data */ 65 | /** Huffman entropy coder */ 66 | jpec_huff_skel_t *hskel; 67 | }; 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2016 Moodstocks SAS 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | #include "jpec.h" 33 | 34 | /* Global variables */ 35 | const char *pname; 36 | 37 | /* Function prototypes */ 38 | int main(int argc, char **argv); 39 | uint8_t *load_image(const char *path, int *width, int *height); 40 | 41 | /* implementation */ 42 | int main(int argc, char** argv) { 43 | pname = argv[0]; 44 | if (argc == 2) { 45 | int w, h; 46 | uint8_t *img = load_image(argv[1], &w, &h); 47 | jpec_enc_t *e = jpec_enc_new(img, w, h); 48 | int len; 49 | const uint8_t *jpeg = jpec_enc_run(e, &len); 50 | FILE *file = fopen("result.jpg", "wb"); 51 | fwrite(jpeg, sizeof(uint8_t), len, file); 52 | fclose(file); 53 | printf("Done: result.jpg (%d bytes)\n", len); 54 | jpec_enc_del(e); 55 | free(img); 56 | } 57 | else { 58 | fprintf(stderr, "Usage:\n"); 59 | fprintf(stderr, " %s /path/to/img\n", pname); 60 | exit(1); 61 | } 62 | return 0; 63 | } 64 | 65 | uint8_t *load_image(const char *path, int *width, int *height) { 66 | assert(path); 67 | IplImage *img = cvLoadImage(path, 1); 68 | if (!img) return NULL; 69 | if (img->nChannels != 1) { 70 | IplImage *tmp = cvCreateImage(cvSize(img->width, img->height), IPL_DEPTH_8U, 1); 71 | cvCvtColor(img, tmp, CV_BGR2GRAY); 72 | cvReleaseImage(&img); 73 | img = tmp; 74 | } 75 | int w = img->width; 76 | int h = img->height; 77 | int bpr = img->widthStep; 78 | uint8_t *data = (uint8_t*)malloc(w*h*sizeof(uint8_t)); 79 | if (w == bpr) memcpy(data, img->imageData, w*h*sizeof(uint8_t)); 80 | else { 81 | for (int i = 0; i < h; ++i) { 82 | memcpy(data + i*w*sizeof(uint8_t), img->imageData + i*bpr*sizeof(uint8_t), 83 | w*sizeof(uint8_t)); 84 | } 85 | } 86 | cvReleaseImage(&img); 87 | *width = w; 88 | *height = h; 89 | return data; 90 | } 91 | -------------------------------------------------------------------------------- /include/jpec.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2016 Moodstocks SAS 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #ifndef JPEC_H 25 | #define JPEC_H 26 | 27 | #include 28 | 29 | /************************************************* 30 | * JPEG Encoder 31 | *************************************************/ 32 | 33 | /* ------------------------------------------------- 34 | * LIMITATIONS 35 | * ------------------------------------------------- 36 | * - Grayscale *only* (monochrome JPEG file): no support for color 37 | * - Baseline DCT-based (SOF0), JFIF 1.01 (APP0) JPEG 38 | * - Block size of 8x8 pixels *only* 39 | * - Default quantization and Huffman tables *only* 40 | * - No border filling support: the input image *MUST* represent an integer 41 | * number of blocks, i.e. each dimension must be a multiple of 8 42 | */ 43 | 44 | /** Type of a JPEG encoder object */ 45 | typedef struct jpec_enc_t_ jpec_enc_t; 46 | 47 | /* 48 | * Create a JPEG encoder with default quality factor 49 | * `img' specifies the pointer to aligned image data. 50 | * `w' specifies the image width in pixels. 51 | * `h' specifies the image height in pixels. 52 | * Because the returned encoder is allocated by this function, it should be 53 | * released with the `jpec_enc_del' call when it is no longer useful. 54 | * Note: for efficiency the image data is *NOT* copied and the encoder just 55 | * retains a pointer to it. Thus the image data must not be deleted 56 | * nor change until the encoder object gets deleted. 57 | */ 58 | jpec_enc_t *jpec_enc_new(const uint8_t *img, uint16_t w, uint16_t h); 59 | /* 60 | * `q` specifies the JPEG quality factor in 0..100 61 | */ 62 | jpec_enc_t *jpec_enc_new2(const uint8_t *img, uint16_t w, uint16_t h, int q); 63 | 64 | /* 65 | * Release a JPEG encoder object 66 | * `e` specifies the encoder object 67 | */ 68 | void jpec_enc_del(jpec_enc_t *e); 69 | 70 | /* 71 | * Run the JPEG encoding 72 | * `e` specifies the encoder object 73 | * `len` specifies the pointer to the variable into which the length of the 74 | * JPEG blob is assigned 75 | * If successful, the return value is the pointer to the JPEG blob. `NULL` is 76 | * returned if an error occurred. 77 | * Note: the caller should take care to copy or save the JPEG blob before 78 | * calling `jpec_enc_del` since the blob will no longer be maintained after. 79 | */ 80 | const uint8_t *jpec_enc_run(jpec_enc_t *e, int *len); 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /src/huff.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2016 Moodstocks SAS 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include "huff.h" 25 | #include "conf.h" 26 | 27 | #ifdef WORD_BIT 28 | #define JPEC_INT_WIDTH WORD_BIT 29 | #else 30 | #define JPEC_INT_WIDTH (int)(sizeof(int) * CHAR_BIT) 31 | #endif 32 | 33 | #if __GNUC__ 34 | #define JPEC_HUFF_NBITS(JPEC_nbits, JPEC_val) \ 35 | JPEC_nbits = (!JPEC_val) ? 0 : JPEC_INT_WIDTH - __builtin_clz(JPEC_val) 36 | #else 37 | #define JPEC_HUFF_NBITS(JPEC_nbits, JPEC_val) \ 38 | JPEC_nbits = 0; \ 39 | while (val) { \ 40 | JPEC_nbits++; \ 41 | val >>= 1; \ 42 | } 43 | #endif 44 | 45 | /* Private function prototypes */ 46 | static void jpec_huff_encode_block_impl(jpec_block_t *block, jpec_huff_state_t *s); 47 | static void jpec_huff_write_bits(jpec_huff_state_t *s, unsigned int bits, int n); 48 | 49 | void jpec_huff_skel_init(jpec_huff_skel_t *skel) { 50 | assert(skel); 51 | memset(skel, 0, sizeof(*skel)); 52 | skel->opq = jpec_huff_new(); 53 | skel->del = (void (*)(void *))jpec_huff_del; 54 | skel->encode_block = (void (*)(void *, jpec_block_t *, jpec_buffer_t *))jpec_huff_encode_block; 55 | } 56 | 57 | jpec_huff_t *jpec_huff_new(void) { 58 | jpec_huff_t *h = malloc(sizeof(*h)); 59 | h->state.buffer = 0; 60 | h->state.nbits = 0; 61 | h->state.dc = 0; 62 | h->state.buf = NULL; 63 | return h; 64 | } 65 | 66 | void jpec_huff_del(jpec_huff_t *h) { 67 | assert(h); 68 | /* Flush any remaining bits and fill in the incomple byte (if any) with 1-s */ 69 | jpec_huff_write_bits(&h->state, 0x7F, 7); 70 | free(h); 71 | } 72 | 73 | void jpec_huff_encode_block(jpec_huff_t *h, jpec_block_t *block, jpec_buffer_t *buf) { 74 | assert(h && block && buf); 75 | jpec_huff_state_t state; 76 | state.buffer = h->state.buffer; 77 | state.nbits = h->state.nbits; 78 | state.dc = h->state.dc; 79 | state.buf = buf; 80 | jpec_huff_encode_block_impl(block, &state); 81 | h->state.buffer = state.buffer; 82 | h->state.nbits = state.nbits; 83 | h->state.dc = state.dc; 84 | h->state.buf = state.buf; 85 | } 86 | 87 | static void jpec_huff_encode_block_impl(jpec_block_t *block, jpec_huff_state_t *s) { 88 | assert(block && s); 89 | int val, bits, nbits; 90 | /* DC coefficient encoding */ 91 | if (block->len > 0) { 92 | val = block->zz[0] - s->dc; 93 | s->dc = block->zz[0]; 94 | } 95 | else { 96 | val = -s->dc; 97 | s->dc = 0; 98 | } 99 | bits = val; 100 | if (val < 0) { 101 | val = -val; 102 | bits = ~val; 103 | } 104 | JPEC_HUFF_NBITS(nbits, val); 105 | jpec_huff_write_bits(s, jpec_dc_code[nbits], jpec_dc_len[nbits]); 106 | if (nbits) jpec_huff_write_bits(s, (unsigned int) bits, nbits); 107 | /* AC coefficients encoding (w/ RLE of zeros) */ 108 | int nz = 0; 109 | for (int i = 1; i < block->len; i++) { 110 | if ((val = block->zz[i]) == 0) nz++; 111 | else { 112 | while (nz >= 16) { 113 | jpec_huff_write_bits(s, jpec_ac_code[0xF0], jpec_ac_len[0xF0]); /* ZRL code */ 114 | nz -= 16; 115 | } 116 | bits = val; 117 | if (val < 0) { 118 | val = -val; 119 | bits = ~val; 120 | } 121 | JPEC_HUFF_NBITS(nbits, val); 122 | int j = (nz << 4) + nbits; 123 | jpec_huff_write_bits(s, jpec_ac_code[j], jpec_ac_len[j]); 124 | if (nbits) jpec_huff_write_bits(s, (unsigned int) bits, nbits); 125 | nz = 0; 126 | } 127 | } 128 | if (block->len < 64) { 129 | jpec_huff_write_bits(s, jpec_ac_code[0x00], jpec_ac_len[0x00]); /* EOB marker */ 130 | } 131 | } 132 | 133 | /* Write n bits into the JPEG buffer, with 0 < n <= 16. 134 | * 135 | * == Details 136 | * - 16 bits are large enough to hold any zig-zag coeff or the longest AC code 137 | * - bits are chunked into bytes before being written into the JPEG buffer 138 | * - any remaining bits are kept in memory by the Huffman state 139 | * - at most 7 bits can be kept in memory 140 | * - a 32-bit integer buffer is used internally 141 | * - only the right 24 bits part of this buffer are used 142 | * - the input bits and remaining bits (if any) are left-justified on this part 143 | * - a mask is used to mask off any extra bits: useful when the input value has been 144 | * first transformed by bitwise complement(|initial value|) 145 | * - if an 0xFF byte is detected a 0x00 stuff byte is automatically written right after 146 | */ 147 | static void jpec_huff_write_bits(jpec_huff_state_t *s, unsigned int bits, int n) { 148 | assert(s && n > 0 && n <= 16); 149 | int32_t mask = (((int32_t) 1) << n) - 1; 150 | int32_t buffer = (int32_t) bits; 151 | int nbits = s->nbits + n; 152 | buffer &= mask; 153 | buffer <<= 24 - nbits; 154 | buffer |= s->buffer; 155 | while (nbits >= 8) { 156 | int chunk = (int) ((buffer >> 16) & 0xFF); 157 | jpec_buffer_write_byte(s->buf, chunk); 158 | if (chunk == 0xFF) jpec_buffer_write_byte(s->buf, 0x00); 159 | buffer <<= 8; 160 | nbits -= 8; 161 | } 162 | s->buffer = buffer; 163 | s->nbits = nbits; 164 | } 165 | -------------------------------------------------------------------------------- /src/conf.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2016 Moodstocks SAS 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include "conf.h" 25 | 26 | const uint8_t jpec_qzr[64] = { 27 | 16, 11, 10, 16, 24, 40, 51, 61, 28 | 12, 12, 14, 19, 26, 58, 60, 55, 29 | 14, 13, 16, 24, 40, 57, 69, 56, 30 | 14, 17, 22, 29, 51, 87, 80, 62, 31 | 18, 22, 37, 56, 68,109,103, 77, 32 | 24, 35, 55, 64, 81,104,113, 92, 33 | 49, 64, 78, 87,103,121,120,101, 34 | 72, 92, 95, 98,112,100,103, 99 35 | }; 36 | 37 | const float jpec_dct[7] = { 38 | 0.49039, 0.46194, 0.41573, 0.35355, 39 | 0.27779, 0.19134, 0.09755 40 | }; 41 | 42 | const int jpec_zz[64] = { 43 | 0, 1, 8, 16, 9, 2, 3, 10, 44 | 17, 24, 32, 25, 18, 11, 4, 5, 45 | 12, 19, 26, 33, 40, 48, 41, 34, 46 | 27, 20, 13, 6, 7, 14, 21, 28, 47 | 35, 42, 49, 56, 57, 50, 43, 36, 48 | 29, 22, 15, 23, 30, 37, 44, 51, 49 | 58, 59, 52, 45, 38, 31, 39, 46, 50 | 53, 60, 61, 54, 47, 55, 62, 63 51 | }; 52 | 53 | const uint8_t jpec_dc_nodes[17] = { 0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0 }; 54 | const int jpec_dc_nb_vals = 12; /* sum of dc_nodes */ 55 | const uint8_t jpec_dc_vals[12] = { 0,1,2,3,4,5,6,7,8,9,10,11 }; 56 | 57 | const uint8_t jpec_ac_nodes[17] = { 0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d }; 58 | const int jpec_ac_nb_vals = 162; /* sum of ac_nodes */ 59 | const uint8_t jpec_ac_vals[162] = { 60 | 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12, /* 0x00: EOB */ 61 | 0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07, 62 | 0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, 63 | 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0, /* 0xf0: ZRL */ 64 | 0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16, 65 | 0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, 66 | 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39, 67 | 0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49, 68 | 0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, 69 | 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69, 70 | 0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79, 71 | 0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, 72 | 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98, 73 | 0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7, 74 | 0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, 75 | 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5, 76 | 0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4, 77 | 0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, 78 | 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea, 79 | 0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8, 80 | 0xf9,0xfa 81 | }; 82 | 83 | const uint8_t jpec_dc_len[12] = { 2,3,3,3,3,3,4,5,6,7,8,9 }; 84 | const int jpec_dc_code[12] = { 85 | 0x000,0x002,0x003,0x004,0x005,0x006, 86 | 0x00e,0x01e,0x03e,0x07e,0x0fe,0x1fe 87 | }; 88 | 89 | const int8_t jpec_ac_len[256] = { 90 | 4, 2, 2, 3, 4, 5, 7, 8, 91 | 10,16,16, 0, 0, 0, 0, 0, 92 | 0, 4, 5, 7, 9,11,16,16, 93 | 16,16,16, 0, 0, 0, 0, 0, 94 | 0, 5, 8,10,12,16,16,16, 95 | 16,16,16, 0, 0, 0, 0, 0, 96 | 0, 6, 9,12,16,16,16,16, 97 | 16,16,16, 0, 0, 0, 0, 0, 98 | 0, 6,10,16,16,16,16,16, 99 | 16,16,16, 0, 0, 0, 0, 0, 100 | 0, 7,11,16,16,16,16,16, 101 | 16,16,16, 0, 0, 0, 0, 0, 102 | 0, 7,12,16,16,16,16,16, 103 | 16,16,16, 0, 0, 0, 0, 0, 104 | 0, 8,12,16,16,16,16,16, 105 | 16,16,16, 0, 0, 0, 0, 0, 106 | 0, 9,15,16,16,16,16,16, 107 | 16,16,16, 0, 0, 0, 0, 0, 108 | 0, 9,16,16,16,16,16,16, 109 | 16,16,16, 0, 0, 0, 0, 0, 110 | 0, 9,16,16,16,16,16,16, 111 | 16,16,16, 0, 0, 0, 0, 0, 112 | 0,10,16,16,16,16,16,16, 113 | 16,16,16, 0, 0, 0, 0, 0, 114 | 0,10,16,16,16,16,16,16, 115 | 16,16,16, 0, 0, 0, 0, 0, 116 | 0,11,16,16,16,16,16,16, 117 | 16,16,16, 0, 0, 0, 0, 0, 118 | 0,16,16,16,16,16,16,16, 119 | 16,16,16, 0, 0, 0, 0, 0, 120 | 11,16,16,16,16,16,16,16, 121 | 16,16,16, 0, 0, 0, 0, 0 122 | }; 123 | 124 | const int jpec_ac_code[256] = { 125 | 0x000a,0x0000,0x0001,0x0004,0x000b,0x001a,0x0078,0x00f8, 126 | 0x03f6,0xff82,0xff83,0x0000,0x0000,0x0000,0x0000,0x0000, 127 | 0x0000,0x000c,0x001b,0x0079,0x01f6,0x07f6,0xff84,0xff85, 128 | 0xff86,0xff87,0xff88,0x0000,0x0000,0x0000,0x0000,0x0000, 129 | 0x0000,0x001c,0x00f9,0x03f7,0x0ff4,0xff89,0xff8a,0xff8b, 130 | 0xff8c,0xff8d,0xff8e,0x0000,0x0000,0x0000,0x0000,0x0000, 131 | 0x0000,0x003a,0x01f7,0x0ff5,0xff8f,0xff90,0xff91,0xff92, 132 | 0xff93,0xff94,0xff95,0x0000,0x0000,0x0000,0x0000,0x0000, 133 | 0x0000,0x003b,0x03f8,0xff96,0xff97,0xff98,0xff99,0xff9a, 134 | 0xff9b,0xff9c,0xff9d,0x0000,0x0000,0x0000,0x0000,0x0000, 135 | 0x0000,0x007a,0x07f7,0xff9e,0xff9f,0xffa0,0xffa1,0xffa2, 136 | 0xffa3,0xffa4,0xffa5,0x0000,0x0000,0x0000,0x0000,0x0000, 137 | 0x0000,0x007b,0x0ff6,0xffa6,0xffa7,0xffa8,0xffa9,0xffaa, 138 | 0xffab,0xffac,0xffad,0x0000,0x0000,0x0000,0x0000,0x0000, 139 | 0x0000,0x00fa,0x0ff7,0xffae,0xffaf,0xffb0,0xffb1,0xffb2, 140 | 0xffb3,0xffb4,0xffb5,0x0000,0x0000,0x0000,0x0000,0x0000, 141 | 0x0000,0x01f8,0x7fc0,0xffb6,0xffb7,0xffb8,0xffb9,0xffba, 142 | 0xffbb,0xffbc,0xffbd,0x0000,0x0000,0x0000,0x0000,0x0000, 143 | 0x0000,0x01f9,0xffbe,0xffbf,0xffc0,0xffc1,0xffc2,0xffc3, 144 | 0xffc4,0xffc5,0xffc6,0x0000,0x0000,0x0000,0x0000,0x0000, 145 | 0x0000,0x01fa,0xffc7,0xffc8,0xffc9,0xffca,0xffcb,0xffcc, 146 | 0xffcd,0xffce,0xffcf,0x0000,0x0000,0x0000,0x0000,0x0000, 147 | 0x0000,0x03f9,0xffd0,0xffd1,0xffd2,0xffd3,0xffd4,0xffd5, 148 | 0xffd6,0xffd7,0xffd8,0x0000,0x0000,0x0000,0x0000,0x0000, 149 | 0x0000,0x03fa,0xffd9,0xffda,0xffdb,0xffdc,0xffdd,0xffde, 150 | 0xffdf,0xffe0,0xffe1,0x0000,0x0000,0x0000,0x0000,0x0000, 151 | 0x0000,0x07f8,0xffe2,0xffe3,0xffe4,0xffe5,0xffe6,0xffe7, 152 | 0xffe8,0xffe9,0xffea,0x0000,0x0000,0x0000,0x0000,0x0000, 153 | 0x0000,0xffeb,0xffec,0xffed,0xffee,0xffef,0xfff0,0xfff1, 154 | 0xfff2,0xfff3,0xfff4,0x0000,0x0000,0x0000,0x0000,0x0000, 155 | 0x07f9,0xfff5,0xfff6,0xfff7,0xfff8,0xfff9,0xfffa,0xfffb, 156 | 0xfffc,0xfffd,0xfffe,0x0000,0x0000,0x0000,0x0000,0x0000 157 | }; 158 | -------------------------------------------------------------------------------- /src/enc.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2016 Moodstocks SAS 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include "enc.h" 25 | #include "huff.h" 26 | #include "conf.h" 27 | 28 | #define JPEG_ENC_DEF_QUAL 93 /* default quality factor */ 29 | #define JPEC_ENC_HEAD_SIZ 330 /* header typical size in bytes */ 30 | #define JPEC_ENC_BLOCK_SIZ 30 /* 8x8 entropy coded block typical size in bytes */ 31 | 32 | /* Private function prototypes */ 33 | static void jpec_enc_init_dqt(jpec_enc_t *e); 34 | static void jpec_enc_open(jpec_enc_t *e); 35 | static void jpec_enc_close(jpec_enc_t *e); 36 | static void jpec_enc_write_soi(jpec_enc_t *e); 37 | static void jpec_enc_write_app0(jpec_enc_t *e); 38 | static void jpec_enc_write_dqt(jpec_enc_t *e); 39 | static void jpec_enc_write_sof0(jpec_enc_t *e); 40 | static void jpec_enc_write_dht(jpec_enc_t *e); 41 | static void jpec_enc_write_sos(jpec_enc_t *e); 42 | static int jpec_enc_next_block(jpec_enc_t *e); 43 | static void jpec_enc_block_dct(jpec_enc_t *e); 44 | static void jpec_enc_block_quant(jpec_enc_t *e); 45 | static void jpec_enc_block_zz(jpec_enc_t *e); 46 | 47 | jpec_enc_t *jpec_enc_new(const uint8_t *img, uint16_t w, uint16_t h) { 48 | return jpec_enc_new2(img, w, h, JPEG_ENC_DEF_QUAL); 49 | } 50 | 51 | jpec_enc_t *jpec_enc_new2(const uint8_t *img, uint16_t w, uint16_t h, int q) { 52 | assert(img && w > 0 && !(w & 0x7) && h > 0 && !(h & 0x7)); 53 | jpec_enc_t *e = malloc(sizeof(*e)); 54 | e->img = img; 55 | e->w = w; 56 | e->w8 = (((w-1)>>3)+1)<<3; 57 | e->h = h; 58 | e->qual = q; 59 | e->bmax = (((w-1)>>3)+1) * (((h-1)>>3)+1); 60 | e->bnum = -1; 61 | e->bx = -1; 62 | e->by = -1; 63 | int bsiz = JPEC_ENC_HEAD_SIZ + e->bmax * JPEC_ENC_BLOCK_SIZ; 64 | e->buf = jpec_buffer_new2(bsiz); 65 | e->hskel = malloc(sizeof(*e->hskel)); 66 | return e; 67 | } 68 | 69 | void jpec_enc_del(jpec_enc_t *e) { 70 | assert(e); 71 | if (e->buf) jpec_buffer_del(e->buf); 72 | free(e->hskel); 73 | free(e); 74 | } 75 | 76 | const uint8_t *jpec_enc_run(jpec_enc_t *e, int *len) { 77 | assert(e && len); 78 | jpec_enc_open(e); 79 | while (jpec_enc_next_block(e)) { 80 | jpec_enc_block_dct(e); 81 | jpec_enc_block_quant(e); 82 | jpec_enc_block_zz(e); 83 | e->hskel->encode_block(e->hskel->opq, &e->block, e->buf); 84 | } 85 | jpec_enc_close(e); 86 | *len = e->buf->len; 87 | return e->buf->stream; 88 | } 89 | 90 | /* Update the internal quantization matrix according to the asked quality */ 91 | static void jpec_enc_init_dqt(jpec_enc_t *e) { 92 | assert(e); 93 | float qualf = (float) e->qual; 94 | float scale = (e->qual < 50) ? (50/qualf) : (2 - qualf/50); 95 | for (int i = 0; i < 64; i++) { 96 | int a = (int) ((float) jpec_qzr[i]*scale + 0.5); 97 | a = (a < 1) ? 1 : ((a > 255) ? 255 : a); 98 | e->dqt[i] = a; 99 | } 100 | } 101 | 102 | static void jpec_enc_open(jpec_enc_t *e) { 103 | assert(e); 104 | jpec_huff_skel_init(e->hskel); 105 | jpec_enc_init_dqt(e); 106 | jpec_enc_write_soi(e); 107 | jpec_enc_write_app0(e); 108 | jpec_enc_write_dqt(e); 109 | jpec_enc_write_sof0(e); 110 | jpec_enc_write_dht(e); 111 | jpec_enc_write_sos(e); 112 | } 113 | 114 | static void jpec_enc_close(jpec_enc_t *e) { 115 | assert(e); 116 | e->hskel->del(e->hskel->opq); 117 | jpec_buffer_write_2bytes(e->buf, 0xFFD9); /* EOI marker */ 118 | } 119 | 120 | static void jpec_enc_write_soi(jpec_enc_t *e) { 121 | assert(e); 122 | jpec_buffer_write_2bytes(e->buf, 0xFFD8); /* SOI marker */ 123 | } 124 | 125 | static void jpec_enc_write_app0(jpec_enc_t *e) { 126 | assert(e); 127 | jpec_buffer_write_2bytes(e->buf, 0xFFE0); /* APP0 marker */ 128 | jpec_buffer_write_2bytes(e->buf, 0x0010); /* segment length */ 129 | jpec_buffer_write_byte(e->buf, 0x4A); /* 'J' */ 130 | jpec_buffer_write_byte(e->buf, 0x46); /* 'F' */ 131 | jpec_buffer_write_byte(e->buf, 0x49); /* 'I' */ 132 | jpec_buffer_write_byte(e->buf, 0x46); /* 'F' */ 133 | jpec_buffer_write_byte(e->buf, 0x00); /* '\0' */ 134 | jpec_buffer_write_2bytes(e->buf, 0x0101); /* v1.1 */ 135 | jpec_buffer_write_byte(e->buf, 0x00); /* no density unit */ 136 | jpec_buffer_write_2bytes(e->buf, 0x0001); /* X density = 1 */ 137 | jpec_buffer_write_2bytes(e->buf, 0x0001); /* Y density = 1 */ 138 | jpec_buffer_write_byte(e->buf, 0x00); /* thumbnail width = 0 */ 139 | jpec_buffer_write_byte(e->buf, 0x00); /* thumbnail height = 0 */ 140 | } 141 | 142 | static void jpec_enc_write_dqt(jpec_enc_t *e) { 143 | assert(e); 144 | jpec_buffer_write_2bytes(e->buf, 0xFFDB); /* DQT marker */ 145 | jpec_buffer_write_2bytes(e->buf, 0x0043); /* segment length */ 146 | jpec_buffer_write_byte(e->buf, 0x00); /* table 0, 8-bit precision (0) */ 147 | for (int i = 0; i < 64; i++) { 148 | jpec_buffer_write_byte(e->buf, e->dqt[jpec_zz[i]]); 149 | } 150 | } 151 | 152 | static void jpec_enc_write_sof0(jpec_enc_t *e) { 153 | assert(e); 154 | jpec_buffer_write_2bytes(e->buf, 0xFFC0); /* SOF0 marker */ 155 | jpec_buffer_write_2bytes(e->buf, 0x000B); /* segment length */ 156 | jpec_buffer_write_byte(e->buf, 0x08); /* 8-bit precision */ 157 | jpec_buffer_write_2bytes(e->buf, e->h); 158 | jpec_buffer_write_2bytes(e->buf, e->w); 159 | jpec_buffer_write_byte(e->buf, 0x01); /* 1 component only (grayscale) */ 160 | jpec_buffer_write_byte(e->buf, 0x01); /* component ID = 1 */ 161 | jpec_buffer_write_byte(e->buf, 0x11); /* no subsampling */ 162 | jpec_buffer_write_byte(e->buf, 0x00); /* quantization table 0 */ 163 | } 164 | 165 | static void jpec_enc_write_dht(jpec_enc_t *e) { 166 | assert(e); 167 | jpec_buffer_write_2bytes(e->buf, 0xFFC4); /* DHT marker */ 168 | jpec_buffer_write_2bytes(e->buf, 19 + jpec_dc_nb_vals); /* segment length */ 169 | jpec_buffer_write_byte(e->buf, 0x00); /* table 0 (DC), type 0 (0 = Y, 1 = UV) */ 170 | for (int i = 0; i < 16; i++) { 171 | jpec_buffer_write_byte(e->buf, jpec_dc_nodes[i+1]); 172 | } 173 | for (int i = 0; i < jpec_dc_nb_vals; i++) { 174 | jpec_buffer_write_byte(e->buf, jpec_dc_vals[i]); 175 | } 176 | jpec_buffer_write_2bytes(e->buf, 0xFFC4); /* DHT marker */ 177 | jpec_buffer_write_2bytes(e->buf, 19 + jpec_ac_nb_vals); 178 | jpec_buffer_write_byte(e->buf, 0x10); /* table 1 (AC), type 0 (0 = Y, 1 = UV) */ 179 | for (int i = 0; i < 16; i++) { 180 | jpec_buffer_write_byte(e->buf, jpec_ac_nodes[i+1]); 181 | } 182 | for (int i = 0; i < jpec_ac_nb_vals; i++) { 183 | jpec_buffer_write_byte(e->buf, jpec_ac_vals[i]); 184 | } 185 | } 186 | 187 | static void jpec_enc_write_sos(jpec_enc_t *e) { 188 | assert(e); 189 | jpec_buffer_write_2bytes(e->buf, 0xFFDA); /* SOS marker */ 190 | jpec_buffer_write_2bytes(e->buf, 8); /* segment length */ 191 | jpec_buffer_write_byte(e->buf, 0x01); /* nb. components */ 192 | jpec_buffer_write_byte(e->buf, 0x01); /* Y component ID */ 193 | jpec_buffer_write_byte(e->buf, 0x00); /* Y HT = 0 */ 194 | /* segment end */ 195 | jpec_buffer_write_byte(e->buf, 0x00); 196 | jpec_buffer_write_byte(e->buf, 0x3F); 197 | jpec_buffer_write_byte(e->buf, 0x00); 198 | } 199 | 200 | static int jpec_enc_next_block(jpec_enc_t *e) { 201 | assert(e); 202 | int rv = (++e->bnum >= e->bmax) ? 0 : 1; 203 | if (rv) { 204 | e->bx = (e->bnum << 3) % e->w8; 205 | e->by = ( (e->bnum << 3) / e->w8 ) << 3; 206 | } 207 | return rv; 208 | } 209 | 210 | static void jpec_enc_block_dct(jpec_enc_t *e) { 211 | assert(e && e->bnum >= 0); 212 | #define JPEC_BLOCK(col,row) e->img[(((e->by + row) < e->h) ? e->by + row : e->h-1) * \ 213 | e->w + (((e->bx + col) < e->w) ? e->bx + col : e->w-1)] 214 | const float* coeff = jpec_dct; 215 | float tmp[64]; 216 | for (int row = 0; row < 8; row++) { 217 | /* NOTE: the shift by 256 allows resampling from [0 255] to [–128 127] */ 218 | float s0 = (float) (JPEC_BLOCK(0, row) + JPEC_BLOCK(7, row) - 256); 219 | float s1 = (float) (JPEC_BLOCK(1, row) + JPEC_BLOCK(6, row) - 256); 220 | float s2 = (float) (JPEC_BLOCK(2, row) + JPEC_BLOCK(5, row) - 256); 221 | float s3 = (float) (JPEC_BLOCK(3, row) + JPEC_BLOCK(4, row) - 256); 222 | 223 | float d0 = (float) (JPEC_BLOCK(0, row) - JPEC_BLOCK(7, row)); 224 | float d1 = (float) (JPEC_BLOCK(1, row) - JPEC_BLOCK(6, row)); 225 | float d2 = (float) (JPEC_BLOCK(2, row) - JPEC_BLOCK(5, row)); 226 | float d3 = (float) (JPEC_BLOCK(3, row) - JPEC_BLOCK(4, row)); 227 | 228 | tmp[8 * row] = coeff[3]*(s0+s1+s2+s3); 229 | tmp[8 * row + 1] = coeff[0]*d0+coeff[2]*d1+coeff[4]*d2+coeff[6]*d3; 230 | tmp[8 * row + 2] = coeff[1]*(s0-s3)+coeff[5]*(s1-s2); 231 | tmp[8 * row + 3] = coeff[2]*d0-coeff[6]*d1-coeff[0]*d2-coeff[4]*d3; 232 | tmp[8 * row + 4] = coeff[3]*(s0-s1-s2+s3); 233 | tmp[8 * row + 5] = coeff[4]*d0-coeff[0]*d1+coeff[6]*d2+coeff[2]*d3; 234 | tmp[8 * row + 6] = coeff[5]*(s0-s3)+coeff[1]*(s2-s1); 235 | tmp[8 * row + 7] = coeff[6]*d0-coeff[4]*d1+coeff[2]*d2-coeff[0]*d3; 236 | } 237 | for (int col = 0; col < 8; col++) { 238 | float s0 = tmp[ col] + tmp[56 + col]; 239 | float s1 = tmp[ 8 + col] + tmp[48 + col]; 240 | float s2 = tmp[16 + col] + tmp[40 + col]; 241 | float s3 = tmp[24 + col] + tmp[32 + col]; 242 | 243 | float d0 = tmp[ col] - tmp[56 + col]; 244 | float d1 = tmp[ 8 + col] - tmp[48 + col]; 245 | float d2 = tmp[16 + col] - tmp[40 + col]; 246 | float d3 = tmp[24 + col] - tmp[32 + col]; 247 | 248 | e->block.dct[ col] = coeff[3]*(s0+s1+s2+s3); 249 | e->block.dct[ 8 + col] = coeff[0]*d0+coeff[2]*d1+coeff[4]*d2+coeff[6]*d3; 250 | e->block.dct[16 + col] = coeff[1]*(s0-s3)+coeff[5]*(s1-s2); 251 | e->block.dct[24 + col] = coeff[2]*d0-coeff[6]*d1-coeff[0]*d2-coeff[4]*d3; 252 | e->block.dct[32 + col] = coeff[3]*(s0-s1-s2+s3); 253 | e->block.dct[40 + col] = coeff[4]*d0-coeff[0]*d1+coeff[6]*d2+coeff[2]*d3; 254 | e->block.dct[48 + col] = coeff[5]*(s0-s3)+coeff[1]*(s2-s1); 255 | e->block.dct[56 + col] = coeff[6]*d0-coeff[4]*d1+coeff[2]*d2-coeff[0]*d3; 256 | } 257 | #undef JPEC_BLOCK 258 | } 259 | 260 | static void jpec_enc_block_quant(jpec_enc_t *e) { 261 | assert(e && e->bnum >= 0); 262 | for (int i = 0; i < 64; i++) { 263 | e->block.quant[i] = (int) (e->block.dct[i]/e->dqt[i]); 264 | } 265 | } 266 | 267 | static void jpec_enc_block_zz(jpec_enc_t *e) { 268 | assert(e && e->bnum >= 0); 269 | e->block.len = 0; 270 | for (int i = 0; i < 64; i++) { 271 | if ((e->block.zz[i] = e->block.quant[jpec_zz[i]])) e->block.len = i + 1; 272 | } 273 | } 274 | --------------------------------------------------------------------------------