1 // NanoJPEG -- KeyJ's Tiny Baseline JPEG Decoder
2 // version 1.3.5 (2016-11-14)
3 // Copyright (c) 2009-2016 Martin J. Fiedler <martin.fiedler@gmx.net>
4 // published under the terms of the MIT license
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to
8 // deal in the Software without restriction, including without limitation the
9 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 // sell copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
23 
24 
25 ///////////////////////////////////////////////////////////////////////////////
26 // DOCUMENTATION SECTION                                                     //
27 // read this if you want to know what this is all about                      //
28 ///////////////////////////////////////////////////////////////////////////////
29 
30 // INTRODUCTION
31 // ============
32 //
33 // This is a minimal decoder for baseline JPEG images. It accepts memory dumps
34 // of JPEG files as input and generates either 8-bit grayscale or packed 24-bit
35 // RGB images as output. It does not parse JFIF or Exif headers; all JPEG files
36 // are assumed to be either grayscale or YCbCr. CMYK or other color spaces are
37 // not supported. All YCbCr subsampling schemes with power-of-two ratios are
38 // supported, as are restart intervals. Progressive or lossless JPEG is not
39 // supported.
40 // Summed up, NanoJPEG should be able to decode all images from digital cameras
41 // and most common forms of other non-progressive JPEG images.
42 // The decoder is not optimized for speed, it's optimized for simplicity and
43 // small code. Image quality should be at a reasonable level. A bicubic chroma
44 // upsampling filter ensures that subsampled YCbCr images are rendered in
45 // decent quality. The decoder is not meant to deal with broken JPEG files in
46 // a graceful manner; if anything is wrong with the bitstream, decoding will
47 // simply fail.
48 // The code should work with every modern C compiler without problems and
49 // should not emit any warnings. It uses only (at least) 32-bit integer
50 // arithmetic and is supposed to be endianness independent and 64-bit clean.
51 // However, it is not thread-safe.
52 
53 
54 // COMPILE-TIME CONFIGURATION
55 // ==========================
56 //
57 // The following aspects of NanoJPEG can be controlled with preprocessor
58 // defines:
59 //
60 // _NJ_EXAMPLE_PROGRAM     = Compile a main() function with an example
61 //                           program.
62 // _NJ_INCLUDE_HEADER_ONLY = Don't compile anything, just act as a header
63 //                           file for NanoJPEG. Example:
64 //                               #define _NJ_INCLUDE_HEADER_ONLY
65 //                               #include "nanojpeg.c"
66 //                               int main(void) {
67 //                                   njInit();
68 //                                   // your code here
69 //                                   njDone();
70 //                               }
71 // NJ_USE_LIBC=1           = Use the malloc(), free(), memset() and memcpy()
72 //                           functions from the standard C library (default).
73 // NJ_USE_LIBC=0           = Don't use the standard C library. In this mode,
74 //                           external functions njAlloc(), njFreeMem(),
75 //                           njFillMem() and njCopyMem() need to be defined
76 //                           and implemented somewhere.
77 // NJ_USE_WIN32=0          = Normal mode (default).
78 // NJ_USE_WIN32=1          = If compiling with MSVC for Win32 and
79 //                           NJ_USE_LIBC=0, NanoJPEG will use its own
80 //                           implementations of the required C library
81 //                           functions (default if compiling with MSVC and
82 //                           NJ_USE_LIBC=0).
83 // NJ_CHROMA_FILTER=1      = Use the bicubic chroma upsampling filter
84 //                           (default).
85 // NJ_CHROMA_FILTER=0      = Use simple pixel repetition for chroma upsampling
86 //                           (bad quality, but faster and less code).
87 
88 
89 // API
90 // ===
91 //
92 // For API documentation, read the "header section" below.
93 
94 
95 // EXAMPLE
96 // =======
97 //
98 // A few pages below, you can find an example program that uses NanoJPEG to
99 // convert JPEG files into PGM or PPM. To compile it, use something like
100 //     gcc -O3 -D_NJ_EXAMPLE_PROGRAM -o nanojpeg nanojpeg.c
101 // You may also add -std=c99 -Wall -Wextra -pedantic -Werror, if you want :)
102 // The only thing you might need is -Wno-shift-negative-value, because this
103 // code relies on the target machine using two's complement arithmetic, but
104 // the C standard does not, even though *any* practically useful machine
105 // nowadays uses two's complement.
106 
107 
108 ///////////////////////////////////////////////////////////////////////////////
109 // HEADER SECTION                                                            //
110 // copy and paste this into nanojpeg.h if you want                            //
111 ///////////////////////////////////////////////////////////////////////////////
112 
113 #ifndef _NANOJPEG_H
114 #define _NANOJPEG_H
115 
116 // nj_result_t: Result codes for njDecode().
117 typedef enum _nj_result {
118     NJ_OK = 0,        // no error, decoding successful
119     NJ_NO_JPEG,       // not a JPEG file
120     NJ_UNSUPPORTED,   // unsupported format
121     NJ_OUT_OF_MEM,    // out of memory
122     NJ_INTERNAL_ERR,  // internal error
123     NJ_SYNTAX_ERROR,  // syntax error
124     __NJ_FINISHED,    // used internally, will never be reported
125 } nj_result_t;
126 
127 // njInit: Initialize NanoJPEG.
128 // For safety reasons, this should be called at least one time before using
129 // using any of the other NanoJPEG functions.
130 void njInit(void);
131 
132 // njDecode: Decode a JPEG image.
133 // Decodes a memory dump of a JPEG file into internal buffers.
134 // Parameters:
135 //   jpeg = The pointer to the memory dump.
136 //   size = The size of the JPEG file.
137 // Return value: The error code in case of failure, or NJ_OK (zero) on success.
138 nj_result_t njDecode(const void* jpeg, const int size);
139 
140 // njGetWidth: Return the width (in pixels) of the most recently decoded
141 // image. If njDecode() failed, the result of njGetWidth() is undefined.
142 int njGetWidth(void);
143 
144 // njGetHeight: Return the height (in pixels) of the most recently decoded
145 // image. If njDecode() failed, the result of njGetHeight() is undefined.
146 int njGetHeight(void);
147 
148 // njIsColor: Return 1 if the most recently decoded image is a color image
149 // (RGB) or 0 if it is a grayscale image. If njDecode() failed, the result
150 // of njGetWidth() is undefined.
151 int njIsColor(void);
152 
153 // njGetImage: Returns the decoded image data.
154 // Returns a pointer to the most recently image. The memory layout it byte-
155 // oriented, top-down, without any padding between lines. Pixels of color
156 // images will be stored as three consecutive bytes for the red, green and
157 // blue channels. This data format is thus compatible with the PGM or PPM
158 // file formats and the OpenGL texture formats GL_LUMINANCE8 or GL_RGB8.
159 // If njDecode() failed, the result of njGetImage() is undefined.
160 unsigned char* njGetImage(void);
161 
162 // njGetImageSize: Returns the size (in bytes) of the image data returned
163 // by njGetImage(). If njDecode() failed, the result of njGetImageSize() is
164 // undefined.
165 int njGetImageSize(void);
166 
167 // njDone: Uninitialize NanoJPEG.
168 // Resets NanoJPEG's internal state and frees all memory that has been
169 // allocated at run-time by NanoJPEG. It is still possible to decode another
170 // image after a njDone() call.
171 void njDone(void);
172 
173 #endif//_NANOJPEG_H
174 
175 
176 ///////////////////////////////////////////////////////////////////////////////
177 // CONFIGURATION SECTION                                                     //
178 // adjust the default settings for the NJ_ defines here                      //
179 ///////////////////////////////////////////////////////////////////////////////
180 
181 #ifndef NJ_USE_LIBC
182     #define NJ_USE_LIBC 1
183 #endif
184 
185 #ifndef NJ_USE_WIN32
186   #ifdef _MSC_VER
187     #define NJ_USE_WIN32 (!NJ_USE_LIBC)
188   #else
189     #define NJ_USE_WIN32 0
190   #endif
191 #endif
192 
193 #ifndef NJ_CHROMA_FILTER
194     #define NJ_CHROMA_FILTER 1
195 #endif
196 
197 
198 ///////////////////////////////////////////////////////////////////////////////
199 // EXAMPLE PROGRAM                                                           //
200 // just define _NJ_EXAMPLE_PROGRAM to compile this (requires NJ_USE_LIBC)    //
201 ///////////////////////////////////////////////////////////////////////////////
202 
203 #ifdef  _NJ_EXAMPLE_PROGRAM
204 
205 #include <stdio.h>
206 #include <stdlib.h>
207 #include <string.h>
208 
main(int argc,char * argv[])209 int main(int argc, char* argv[]) {
210     int size;
211     char *buf;
212     FILE *f;
213 
214     if (argc < 2) {
215         printf("Usage: %s <input.jpg> [<output.ppm>]\n", argv[0]);
216         return 2;
217     }
218     f = fopen(argv[1], "rb");
219     if (!f) {
220         printf("Error opening the input file.\n");
221         return 1;
222     }
223     fseek(f, 0, SEEK_END);
224     size = (int) ftell(f);
225     buf = (char*) malloc(size);
226     fseek(f, 0, SEEK_SET);
227     size = (int) fread(buf, 1, size, f);
228     fclose(f);
229 
230     njInit();
231     if (njDecode(buf, size)) {
232         free((void*)buf);
233         printf("Error decoding the input file.\n");
234         return 1;
235     }
236     free((void*)buf);
237 
238     f = fopen((argc > 2) ? argv[2] : (njIsColor() ? "nanojpeg_out.ppm" : "nanojpeg_out.pgm"), "wb");
239     if (!f) {
240         printf("Error opening the output file.\n");
241         return 1;
242     }
243     fprintf(f, "P%d\n%d %d\n255\n", njIsColor() ? 6 : 5, njGetWidth(), njGetHeight());
244     fwrite(njGetImage(), 1, njGetImageSize(), f);
245     fclose(f);
246     njDone();
247     return 0;
248 }
249 
250 #endif
251 
252 
253 ///////////////////////////////////////////////////////////////////////////////
254 // IMPLEMENTATION SECTION                                                    //
255 // you may stop reading here                                                 //
256 ///////////////////////////////////////////////////////////////////////////////
257 
258 #ifndef _NJ_INCLUDE_HEADER_ONLY
259 
260 #ifdef _MSC_VER
261     #define NJ_INLINE static __inline
262     #define NJ_FORCE_INLINE static __forceinline
263 #else
264     #define NJ_INLINE static inline
265     #define NJ_FORCE_INLINE static inline
266 #endif
267 
268 #if NJ_USE_LIBC
269     #include <stdlib.h>
270     #include <string.h>
271     #define njAllocMem malloc
272     #define njFreeMem  free
273     #define njFillMem  memset
274     #define njCopyMem  memcpy
275 #elif NJ_USE_WIN32
276     #include <windows.h>
277     #define njAllocMem(size) ((void*) LocalAlloc(LMEM_FIXED, (SIZE_T)(size)))
278     #define njFreeMem(block) ((void) LocalFree((HLOCAL) block))
njFillMem(void * block,unsigned char value,int count)279     NJ_INLINE void njFillMem(void* block, unsigned char value, int count) { __asm {
280         mov edi, block
281         mov al, value
282         mov ecx, count
283         rep stosb
284     } }
njCopyMem(void * dest,const void * src,int count)285     NJ_INLINE void njCopyMem(void* dest, const void* src, int count) { __asm {
286         mov edi, dest
287         mov esi, src
288         mov ecx, count
289         rep movsb
290     } }
291 #else
292     extern void* njAllocMem(int size);
293     extern void njFreeMem(void* block);
294     extern void njFillMem(void* block, unsigned char byte, int size);
295     extern void njCopyMem(void* dest, const void* src, int size);
296 #endif
297 
298 typedef struct _nj_code {
299     unsigned char bits, code;
300 } nj_vlc_code_t;
301 
302 typedef struct _nj_cmp {
303     int cid;
304     int ssx, ssy;
305     int width, height;
306     int stride;
307     int qtsel;
308     int actabsel, dctabsel;
309     int dcpred;
310     unsigned char *pixels;
311 } nj_component_t;
312 
313 typedef struct _nj_ctx {
314     nj_result_t error;
315     const unsigned char *pos;
316     int size;
317     int length;
318     int width, height;
319     int mbwidth, mbheight;
320     int mbsizex, mbsizey;
321     int ncomp;
322     nj_component_t comp[3];
323     int qtused, qtavail;
324     unsigned char qtab[4][64];
325     nj_vlc_code_t vlctab[4][65536];
326     int buf, bufbits;
327     int block[64];
328     int rstinterval;
329     unsigned char *rgb;
330 } nj_context_t;
331 
332 static nj_context_t nj;
333 
334 static const char njZZ[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18,
335 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35,
336 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45,
337 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 };
338 
njClip(const int x)339 NJ_FORCE_INLINE unsigned char njClip(const int x) {
340     return (x < 0) ? 0 : ((x > 0xFF) ? 0xFF : (unsigned char) x);
341 }
342 
343 #define W1 2841
344 #define W2 2676
345 #define W3 2408
346 #define W5 1609
347 #define W6 1108
348 #define W7 565
349 
350 #ifdef USING_R
shiftLeft(int i,int p)351 NJ_INLINE int shiftLeft(int i, int p) {
352     unsigned u = *(unsigned *)(&i);
353     u <<= p;
354     return int(u);
355 }
356 #else
357 #define shiftLeft(i,p) (i) << (p)
358 #endif
359 
njRowIDCT(int * blk)360 NJ_INLINE void njRowIDCT(int* blk) {
361     int x0, x1, x2, x3, x4, x5, x6, x7, x8;
362     if (!((x1 = shiftLeft(blk[4], 11))
363         | (x2 = blk[6])
364         | (x3 = blk[2])
365         | (x4 = blk[1])
366         | (x5 = blk[7])
367         | (x6 = blk[5])
368         | (x7 = blk[3])))
369     {
370         blk[0] = blk[1] = blk[2] = blk[3] = blk[4] = blk[5] = blk[6] = blk[7] = shiftLeft(blk[0], 3);
371         return;
372     }
373     x0 = shiftLeft(blk[0], 11);
374     x0 += 128;
375     x8 = W7 * (x4 + x5);
376     x4 = x8 + (W1 - W7) * x4;
377     x5 = x8 - (W1 + W7) * x5;
378     x8 = W3 * (x6 + x7);
379     x6 = x8 - (W3 - W5) * x6;
380     x7 = x8 - (W3 + W5) * x7;
381     x8 = x0 + x1;
382     x0 -= x1;
383     x1 = W6 * (x3 + x2);
384     x2 = x1 - (W2 + W6) * x2;
385     x3 = x1 + (W2 - W6) * x3;
386     x1 = x4 + x6;
387     x4 -= x6;
388     x6 = x5 + x7;
389     x5 -= x7;
390     x7 = x8 + x3;
391     x8 -= x3;
392     x3 = x0 + x2;
393     x0 -= x2;
394     x2 = (181 * (x4 + x5) + 128) >> 8;
395     x4 = (181 * (x4 - x5) + 128) >> 8;
396     blk[0] = (x7 + x1) >> 8;
397     blk[1] = (x3 + x2) >> 8;
398     blk[2] = (x0 + x4) >> 8;
399     blk[3] = (x8 + x6) >> 8;
400     blk[4] = (x8 - x6) >> 8;
401     blk[5] = (x0 - x4) >> 8;
402     blk[6] = (x3 - x2) >> 8;
403     blk[7] = (x7 - x1) >> 8;
404 }
405 
njColIDCT(const int * blk,unsigned char * out,int stride)406 NJ_INLINE void njColIDCT(const int* blk, unsigned char *out, int stride) {
407     int x0, x1, x2, x3, x4, x5, x6, x7, x8;
408     if (!((x1 = shiftLeft(blk[8*4], 8))
409         | (x2 = blk[8*6])
410         | (x3 = blk[8*2])
411         | (x4 = blk[8*1])
412         | (x5 = blk[8*7])
413         | (x6 = blk[8*5])
414         | (x7 = blk[8*3])))
415     {
416         x1 = njClip(((blk[0] + 32) >> 6) + 128);
417         for (x0 = 8;  x0;  --x0) {
418             *out = (unsigned char) x1;
419             out += stride;
420         }
421         return;
422     }
423     x0 = shiftLeft(blk[0], 8);
424     x0 += 8192;
425     x8 = W7 * (x4 + x5) + 4;
426     x4 = (x8 + (W1 - W7) * x4) >> 3;
427     x5 = (x8 - (W1 + W7) * x5) >> 3;
428     x8 = W3 * (x6 + x7) + 4;
429     x6 = (x8 - (W3 - W5) * x6) >> 3;
430     x7 = (x8 - (W3 + W5) * x7) >> 3;
431     x8 = x0 + x1;
432     x0 -= x1;
433     x1 = W6 * (x3 + x2) + 4;
434     x2 = (x1 - (W2 + W6) * x2) >> 3;
435     x3 = (x1 + (W2 - W6) * x3) >> 3;
436     x1 = x4 + x6;
437     x4 -= x6;
438     x6 = x5 + x7;
439     x5 -= x7;
440     x7 = x8 + x3;
441     x8 -= x3;
442     x3 = x0 + x2;
443     x0 -= x2;
444     x2 = (181 * (x4 + x5) + 128) >> 8;
445     x4 = (181 * (x4 - x5) + 128) >> 8;
446     *out = njClip(((x7 + x1) >> 14) + 128);  out += stride;
447     *out = njClip(((x3 + x2) >> 14) + 128);  out += stride;
448     *out = njClip(((x0 + x4) >> 14) + 128);  out += stride;
449     *out = njClip(((x8 + x6) >> 14) + 128);  out += stride;
450     *out = njClip(((x8 - x6) >> 14) + 128);  out += stride;
451     *out = njClip(((x0 - x4) >> 14) + 128);  out += stride;
452     *out = njClip(((x3 - x2) >> 14) + 128);  out += stride;
453     *out = njClip(((x7 - x1) >> 14) + 128);
454 }
455 
456 #define njThrow(e) do { nj.error = e; return; } while (0)
457 #define njCheckError() do { if (nj.error) return; } while (0)
458 
njShowBits(int bits)459 static int njShowBits(int bits) {
460     unsigned char newbyte;
461     if (!bits) return 0;
462     while (nj.bufbits < bits) {
463         if (nj.size <= 0) {
464             nj.buf = shiftLeft(nj.buf, 8) | 0xFF;
465             nj.bufbits += 8;
466             continue;
467         }
468         newbyte = *nj.pos++;
469         nj.size--;
470         nj.bufbits += 8;
471         nj.buf = shiftLeft(nj.buf, 8) | newbyte;
472         if (newbyte == 0xFF) {
473             if (nj.size) {
474                 unsigned char marker = *nj.pos++;
475                 nj.size--;
476                 switch (marker) {
477                     case 0x00:
478                     case 0xFF:
479                         break;
480                     case 0xD9: nj.size = 0; break;
481                     default:
482                         if ((marker & 0xF8) != 0xD0)
483                             nj.error = NJ_SYNTAX_ERROR;
484                         else {
485                             nj.buf = shiftLeft(nj.buf, 8) | marker;
486                             nj.bufbits += 8;
487                         }
488                 }
489             } else
490                 nj.error = NJ_SYNTAX_ERROR;
491         }
492     }
493     return (nj.buf >> (nj.bufbits - bits)) & ((1 << bits) - 1);
494 }
495 
njSkipBits(int bits)496 NJ_INLINE void njSkipBits(int bits) {
497     if (nj.bufbits < bits)
498         (void) njShowBits(bits);
499     nj.bufbits -= bits;
500 }
501 
njGetBits(int bits)502 NJ_INLINE int njGetBits(int bits) {
503     int res = njShowBits(bits);
504     njSkipBits(bits);
505     return res;
506 }
507 
njByteAlign(void)508 NJ_INLINE void njByteAlign(void) {
509     nj.bufbits &= 0xF8;
510 }
511 
njSkip(int count)512 static void njSkip(int count) {
513     nj.pos += count;
514     nj.size -= count;
515     nj.length -= count;
516     if (nj.size < 0) nj.error = NJ_SYNTAX_ERROR;
517 }
518 
njDecode16(const unsigned char * pos)519 NJ_INLINE unsigned short njDecode16(const unsigned char *pos) {
520     return (pos[0] << 8) | pos[1];
521 }
522 
njDecodeLength(void)523 static void njDecodeLength(void) {
524     if (nj.size < 2) njThrow(NJ_SYNTAX_ERROR);
525     nj.length = njDecode16(nj.pos);
526     if (nj.length > nj.size) njThrow(NJ_SYNTAX_ERROR);
527     njSkip(2);
528 }
529 
njSkipMarker(void)530 NJ_INLINE void njSkipMarker(void) {
531     njDecodeLength();
532     njSkip(nj.length);
533 }
534 
njDecodeSOF(void)535 NJ_INLINE void njDecodeSOF(void) {
536     int i, ssxmax = 0, ssymax = 0;
537     nj_component_t* c;
538     njDecodeLength();
539     njCheckError();
540     if (nj.length < 9) njThrow(NJ_SYNTAX_ERROR);
541     if (nj.pos[0] != 8) njThrow(NJ_UNSUPPORTED);
542     nj.height = njDecode16(nj.pos+1);
543     nj.width = njDecode16(nj.pos+3);
544     if (!nj.width || !nj.height) njThrow(NJ_SYNTAX_ERROR);
545     nj.ncomp = nj.pos[5];
546     njSkip(6);
547     switch (nj.ncomp) {
548         case 1:
549         case 3:
550             break;
551         default:
552             njThrow(NJ_UNSUPPORTED);
553     }
554     if (nj.length < (nj.ncomp * 3)) njThrow(NJ_SYNTAX_ERROR);
555     for (i = 0, c = nj.comp;  i < nj.ncomp;  ++i, ++c) {
556         c->cid = nj.pos[0];
557         if (!(c->ssx = nj.pos[1] >> 4)) njThrow(NJ_SYNTAX_ERROR);
558         if (c->ssx & (c->ssx - 1)) njThrow(NJ_UNSUPPORTED);  // non-power of two
559         if (!(c->ssy = nj.pos[1] & 15)) njThrow(NJ_SYNTAX_ERROR);
560         if (c->ssy & (c->ssy - 1)) njThrow(NJ_UNSUPPORTED);  // non-power of two
561         if ((c->qtsel = nj.pos[2]) & 0xFC) njThrow(NJ_SYNTAX_ERROR);
562         njSkip(3);
563         nj.qtused |= 1 << c->qtsel;
564         if (c->ssx > ssxmax) ssxmax = c->ssx;
565         if (c->ssy > ssymax) ssymax = c->ssy;
566     }
567     if (nj.ncomp == 1) {
568         c = nj.comp;
569         c->ssx = c->ssy = ssxmax = ssymax = 1;
570     }
571     nj.mbsizex = shiftLeft(ssxmax, 3);
572     nj.mbsizey = shiftLeft(ssymax, 3);
573     nj.mbwidth = (nj.width + nj.mbsizex - 1) / nj.mbsizex;
574     nj.mbheight = (nj.height + nj.mbsizey - 1) / nj.mbsizey;
575     for (i = 0, c = nj.comp;  i < nj.ncomp;  ++i, ++c) {
576         c->width = (nj.width * c->ssx + ssxmax - 1) / ssxmax;
577         c->height = (nj.height * c->ssy + ssymax - 1) / ssymax;
578         c->stride = nj.mbwidth * shiftLeft(c->ssx, 3);
579         if (((c->width < 3) && (c->ssx != ssxmax)) || ((c->height < 3) && (c->ssy != ssymax))) njThrow(NJ_UNSUPPORTED);
580         if (!(c->pixels = (unsigned char*) njAllocMem(c->stride * nj.mbheight * shiftLeft(c->ssy, 3)))) njThrow(NJ_OUT_OF_MEM);
581     }
582     if (nj.ncomp == 3) {
583         nj.rgb = (unsigned char*) njAllocMem(nj.width * nj.height * nj.ncomp);
584         if (!nj.rgb) njThrow(NJ_OUT_OF_MEM);
585     }
586     njSkip(nj.length);
587 }
588 
njDecodeDHT(void)589 NJ_INLINE void njDecodeDHT(void) {
590     int codelen, currcnt, remain, spread, i, j;
591     nj_vlc_code_t *vlc;
592     static unsigned char counts[16];
593     njDecodeLength();
594     njCheckError();
595     while (nj.length >= 17) {
596         i = nj.pos[0];
597         if (i & 0xEC) njThrow(NJ_SYNTAX_ERROR);
598         if (i & 0x02) njThrow(NJ_UNSUPPORTED);
599         i = (i | (i >> 3)) & 3;  // combined DC/AC + tableid value
600         for (codelen = 1;  codelen <= 16;  ++codelen)
601             counts[codelen - 1] = nj.pos[codelen];
602         njSkip(17);
603         vlc = &nj.vlctab[i][0];
604         remain = spread = 65536;
605         for (codelen = 1;  codelen <= 16;  ++codelen) {
606             spread >>= 1;
607             currcnt = counts[codelen - 1];
608             if (!currcnt) continue;
609             if (nj.length < currcnt) njThrow(NJ_SYNTAX_ERROR);
610             remain -= shiftLeft(currcnt, 16 - codelen);
611             if (remain < 0) njThrow(NJ_SYNTAX_ERROR);
612             for (i = 0;  i < currcnt;  ++i) {
613                 unsigned char code = nj.pos[i];
614                 for (j = spread;  j;  --j) {
615                     vlc->bits = (unsigned char) codelen;
616                     vlc->code = code;
617                     ++vlc;
618                 }
619             }
620             njSkip(currcnt);
621         }
622         while (remain--) {
623             vlc->bits = 0;
624             ++vlc;
625         }
626     }
627     if (nj.length) njThrow(NJ_SYNTAX_ERROR);
628 }
629 
njDecodeDQT(void)630 NJ_INLINE void njDecodeDQT(void) {
631     int i;
632     unsigned char *t;
633     njDecodeLength();
634     njCheckError();
635     while (nj.length >= 65) {
636         i = nj.pos[0];
637         if (i & 0xFC) njThrow(NJ_SYNTAX_ERROR);
638         nj.qtavail |= 1 << i;
639         t = &nj.qtab[i][0];
640         for (i = 0;  i < 64;  ++i)
641             t[i] = nj.pos[i + 1];
642         njSkip(65);
643     }
644     if (nj.length) njThrow(NJ_SYNTAX_ERROR);
645 }
646 
njDecodeDRI(void)647 NJ_INLINE void njDecodeDRI(void) {
648     njDecodeLength();
649     njCheckError();
650     if (nj.length < 2) njThrow(NJ_SYNTAX_ERROR);
651     nj.rstinterval = njDecode16(nj.pos);
652     njSkip(nj.length);
653 }
654 
njGetVLC(nj_vlc_code_t * vlc,unsigned char * code)655 static int njGetVLC(nj_vlc_code_t* vlc, unsigned char* code) {
656     int value = njShowBits(16);
657     int bits = vlc[value].bits;
658     if (!bits) { nj.error = NJ_SYNTAX_ERROR; return 0; }
659     njSkipBits(bits);
660     value = vlc[value].code;
661     if (code) *code = (unsigned char) value;
662     bits = value & 15;
663     if (!bits) return 0;
664     value = njGetBits(bits);
665     if (value < (1 << (bits - 1)))
666         value += (shiftLeft(-1, bits)) + 1;
667     return value;
668 }
669 
njDecodeBlock(nj_component_t * c,unsigned char * out)670 NJ_INLINE void njDecodeBlock(nj_component_t* c, unsigned char* out) {
671     unsigned char code = 0;
672     int value, coef = 0;
673     njFillMem(nj.block, 0, sizeof(nj.block));
674     c->dcpred += njGetVLC(&nj.vlctab[c->dctabsel][0], NULL);
675     nj.block[0] = (c->dcpred) * nj.qtab[c->qtsel][0];
676     do {
677         value = njGetVLC(&nj.vlctab[c->actabsel][0], &code);
678         if (!code) break;  // EOB
679         if (!(code & 0x0F) && (code != 0xF0)) njThrow(NJ_SYNTAX_ERROR);
680         coef += (code >> 4) + 1;
681         if (coef > 63) njThrow(NJ_SYNTAX_ERROR);
682         nj.block[(int) njZZ[coef]] = value * nj.qtab[c->qtsel][coef];
683     } while (coef < 63);
684     for (coef = 0;  coef < 64;  coef += 8)
685         njRowIDCT(&nj.block[coef]);
686     for (coef = 0;  coef < 8;  ++coef)
687         njColIDCT(&nj.block[coef], &out[coef], c->stride);
688 }
689 
njDecodeScan(void)690 NJ_INLINE void njDecodeScan(void) {
691     int i, mbx, mby, sbx, sby;
692     int rstcount = nj.rstinterval, nextrst = 0;
693     nj_component_t* c;
694     njDecodeLength();
695     njCheckError();
696     if (nj.length < (4 + 2 * nj.ncomp)) njThrow(NJ_SYNTAX_ERROR);
697     if (nj.pos[0] != nj.ncomp) njThrow(NJ_UNSUPPORTED);
698     njSkip(1);
699     for (i = 0, c = nj.comp;  i < nj.ncomp;  ++i, ++c) {
700         if (nj.pos[0] != c->cid) njThrow(NJ_SYNTAX_ERROR);
701         if (nj.pos[1] & 0xEE) njThrow(NJ_SYNTAX_ERROR);
702         c->dctabsel = nj.pos[1] >> 4;
703         c->actabsel = (nj.pos[1] & 1) | 2;
704         njSkip(2);
705     }
706     if (nj.pos[0] || (nj.pos[1] != 63) || nj.pos[2]) njThrow(NJ_UNSUPPORTED);
707     njSkip(nj.length);
708     for (mbx = mby = 0;;) {
709         for (i = 0, c = nj.comp;  i < nj.ncomp;  ++i, ++c)
710             for (sby = 0;  sby < c->ssy;  ++sby)
711                 for (sbx = 0;  sbx < c->ssx;  ++sbx) {
712                     njDecodeBlock(c, &c->pixels[shiftLeft((mby * c->ssy + sby) * c->stride + mbx * c->ssx + sbx, 3)]);
713                     njCheckError();
714                 }
715         if (++mbx >= nj.mbwidth) {
716             mbx = 0;
717             if (++mby >= nj.mbheight) break;
718         }
719         if (nj.rstinterval && !(--rstcount)) {
720             njByteAlign();
721             i = njGetBits(16);
722             if (((i & 0xFFF8) != 0xFFD0) || ((i & 7) != nextrst)) njThrow(NJ_SYNTAX_ERROR);
723             nextrst = (nextrst + 1) & 7;
724             rstcount = nj.rstinterval;
725             for (i = 0;  i < 3;  ++i)
726                 nj.comp[i].dcpred = 0;
727         }
728     }
729     nj.error = __NJ_FINISHED;
730 }
731 
732 #if NJ_CHROMA_FILTER
733 
734 #define CF4A (-9)
735 #define CF4B (111)
736 #define CF4C (29)
737 #define CF4D (-3)
738 #define CF3A (28)
739 #define CF3B (109)
740 #define CF3C (-9)
741 #define CF3X (104)
742 #define CF3Y (27)
743 #define CF3Z (-3)
744 #define CF2A (139)
745 #define CF2B (-11)
746 #define CF(x) njClip(((x) + 64) >> 7)
747 
njUpsampleH(nj_component_t * c)748 NJ_INLINE void njUpsampleH(nj_component_t* c) {
749     const int xmax = c->width - 3;
750     unsigned char *out, *lin, *lout;
751     int x, y;
752     out = (unsigned char*) njAllocMem((c->width * c->height) << 1);
753     if (!out) njThrow(NJ_OUT_OF_MEM);
754     lin = c->pixels;
755     lout = out;
756     for (y = c->height;  y;  --y) {
757         lout[0] = CF(CF2A * lin[0] + CF2B * lin[1]);
758         lout[1] = CF(CF3X * lin[0] + CF3Y * lin[1] + CF3Z * lin[2]);
759         lout[2] = CF(CF3A * lin[0] + CF3B * lin[1] + CF3C * lin[2]);
760         for (x = 0;  x < xmax;  ++x) {
761             lout[(x << 1) + 3] = CF(CF4A * lin[x] + CF4B * lin[x + 1] + CF4C * lin[x + 2] + CF4D * lin[x + 3]);
762             lout[(x << 1) + 4] = CF(CF4D * lin[x] + CF4C * lin[x + 1] + CF4B * lin[x + 2] + CF4A * lin[x + 3]);
763         }
764         lin += c->stride;
765         lout += c->width << 1;
766         lout[-3] = CF(CF3A * lin[-1] + CF3B * lin[-2] + CF3C * lin[-3]);
767         lout[-2] = CF(CF3X * lin[-1] + CF3Y * lin[-2] + CF3Z * lin[-3]);
768         lout[-1] = CF(CF2A * lin[-1] + CF2B * lin[-2]);
769     }
770     c->width <<= 1;
771     c->stride = c->width;
772     njFreeMem((void*)c->pixels);
773     c->pixels = out;
774 }
775 
njUpsampleV(nj_component_t * c)776 NJ_INLINE void njUpsampleV(nj_component_t* c) {
777     const int w = c->width, s1 = c->stride, s2 = s1 + s1;
778     unsigned char *out, *cin, *cout;
779     int x, y;
780     out = (unsigned char*) njAllocMem((c->width * c->height) << 1);
781     if (!out) njThrow(NJ_OUT_OF_MEM);
782     for (x = 0;  x < w;  ++x) {
783         cin = &c->pixels[x];
784         cout = &out[x];
785         *cout = CF(CF2A * cin[0] + CF2B * cin[s1]);  cout += w;
786         *cout = CF(CF3X * cin[0] + CF3Y * cin[s1] + CF3Z * cin[s2]);  cout += w;
787         *cout = CF(CF3A * cin[0] + CF3B * cin[s1] + CF3C * cin[s2]);  cout += w;
788         cin += s1;
789         for (y = c->height - 3;  y;  --y) {
790             *cout = CF(CF4A * cin[-s1] + CF4B * cin[0] + CF4C * cin[s1] + CF4D * cin[s2]);  cout += w;
791             *cout = CF(CF4D * cin[-s1] + CF4C * cin[0] + CF4B * cin[s1] + CF4A * cin[s2]);  cout += w;
792             cin += s1;
793         }
794         cin += s1;
795         *cout = CF(CF3A * cin[0] + CF3B * cin[-s1] + CF3C * cin[-s2]);  cout += w;
796         *cout = CF(CF3X * cin[0] + CF3Y * cin[-s1] + CF3Z * cin[-s2]);  cout += w;
797         *cout = CF(CF2A * cin[0] + CF2B * cin[-s1]);
798     }
799     c->height <<= 1;
800     c->stride = c->width;
801     njFreeMem((void*) c->pixels);
802     c->pixels = out;
803 }
804 
805 #else
806 
njUpsample(nj_component_t * c)807 NJ_INLINE void njUpsample(nj_component_t* c) {
808     int x, y, xshift = 0, yshift = 0;
809     unsigned char *out, *lin, *lout;
810     while (c->width < nj.width) { c->width <<= 1; ++xshift; }
811     while (c->height < nj.height) { c->height <<= 1; ++yshift; }
812     out = (unsigned char*) njAllocMem(c->width * c->height);
813     if (!out) njThrow(NJ_OUT_OF_MEM);
814     lin = c->pixels;
815     lout = out;
816     for (y = 0;  y < c->height;  ++y) {
817         lin = &c->pixels[(y >> yshift) * c->stride];
818         for (x = 0;  x < c->width;  ++x)
819             lout[x] = lin[x >> xshift];
820         lout += c->width;
821     }
822     c->stride = c->width;
823     njFreeMem((void*) c->pixels);
824     c->pixels = out;
825 }
826 
827 #endif
828 
njConvert(void)829 NJ_INLINE void njConvert(void) {
830     int i;
831     nj_component_t* c;
832     for (i = 0, c = nj.comp;  i < nj.ncomp;  ++i, ++c) {
833         #if NJ_CHROMA_FILTER
834             while ((c->width < nj.width) || (c->height < nj.height)) {
835                 if (c->width < nj.width) njUpsampleH(c);
836                 njCheckError();
837                 if (c->height < nj.height) njUpsampleV(c);
838                 njCheckError();
839             }
840         #else
841             if ((c->width < nj.width) || (c->height < nj.height))
842                 njUpsample(c);
843         #endif
844         if ((c->width < nj.width) || (c->height < nj.height)) njThrow(NJ_INTERNAL_ERR);
845     }
846     if (nj.ncomp == 3) {
847         // convert to RGB
848         int x, yy;
849         unsigned char *prgb = nj.rgb;
850         const unsigned char *py  = nj.comp[0].pixels;
851         const unsigned char *pcb = nj.comp[1].pixels;
852         const unsigned char *pcr = nj.comp[2].pixels;
853         for (yy = nj.height;  yy;  --yy) {
854             for (x = 0;  x < nj.width;  ++x) {
855                 int y = py[x] << 8;
856                 int cb = pcb[x] - 128;
857                 int cr = pcr[x] - 128;
858                 *prgb++ = njClip((y            + 359 * cr + 128) >> 8);
859                 *prgb++ = njClip((y -  88 * cb - 183 * cr + 128) >> 8);
860                 *prgb++ = njClip((y + 454 * cb            + 128) >> 8);
861             }
862             py += nj.comp[0].stride;
863             pcb += nj.comp[1].stride;
864             pcr += nj.comp[2].stride;
865         }
866     } else if (nj.comp[0].width != nj.comp[0].stride) {
867         // grayscale -> only remove stride
868         unsigned char *pin = &nj.comp[0].pixels[nj.comp[0].stride];
869         unsigned char *pout = &nj.comp[0].pixels[nj.comp[0].width];
870         int y;
871         for (y = nj.comp[0].height - 1;  y;  --y) {
872             njCopyMem(pout, pin, nj.comp[0].width);
873             pin += nj.comp[0].stride;
874             pout += nj.comp[0].width;
875         }
876         nj.comp[0].stride = nj.comp[0].width;
877     }
878 }
879 
njInit(void)880 void njInit(void) {
881     njFillMem(&nj, 0, sizeof(nj_context_t));
882 }
883 
njDone(void)884 void njDone(void) {
885     int i;
886     for (i = 0;  i < 3;  ++i)
887         if (nj.comp[i].pixels) njFreeMem((void*) nj.comp[i].pixels);
888     if (nj.rgb) njFreeMem((void*) nj.rgb);
889     njInit();
890 }
891 
njDecode(const void * jpeg,const int size)892 nj_result_t njDecode(const void* jpeg, const int size) {
893     njDone();
894     nj.pos = (const unsigned char*) jpeg;
895     nj.size = size & 0x7FFFFFFF;
896     if (nj.size < 2) return NJ_NO_JPEG;
897     if ((nj.pos[0] ^ 0xFF) | (nj.pos[1] ^ 0xD8)) return NJ_NO_JPEG;
898     njSkip(2);
899     while (!nj.error) {
900         if ((nj.size < 2) || (nj.pos[0] != 0xFF)) return NJ_SYNTAX_ERROR;
901         njSkip(2);
902         switch (nj.pos[-1]) {
903             case 0xC0: njDecodeSOF();  break;
904             case 0xC4: njDecodeDHT();  break;
905             case 0xDB: njDecodeDQT();  break;
906             case 0xDD: njDecodeDRI();  break;
907             case 0xDA: njDecodeScan(); break;
908             case 0xFE: njSkipMarker(); break;
909             default:
910                 if ((nj.pos[-1] & 0xF0) == 0xE0)
911                     njSkipMarker();
912                 else
913                     return NJ_UNSUPPORTED;
914         }
915     }
916     if (nj.error != __NJ_FINISHED) return nj.error;
917     nj.error = NJ_OK;
918     njConvert();
919     return nj.error;
920 }
921 
njGetWidth(void)922 int njGetWidth(void)            { return nj.width; }
njGetHeight(void)923 int njGetHeight(void)           { return nj.height; }
njIsColor(void)924 int njIsColor(void)             { return (nj.ncomp != 1); }
njGetImage(void)925 unsigned char* njGetImage(void) { return (nj.ncomp == 1) ? nj.comp[0].pixels : nj.rgb; }
njGetImageSize(void)926 int njGetImageSize(void)        { return nj.width * nj.height * nj.ncomp; }
927 
928 #endif // _NJ_INCLUDE_HEADER_ONLY