lilimg 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/nanojpeg.h ADDED
@@ -0,0 +1,928 @@
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 pase 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
+ #include "jo_gif.h"
209
+
210
+ int main(int argc, char* argv[]) {
211
+ int size;
212
+ char *buf;
213
+ FILE *f;
214
+
215
+ if (argc < 2) {
216
+ printf("Usage: %s <input.jpg> [<output.ppm>]\n", argv[0]);
217
+ return 2;
218
+ }
219
+ f = fopen(argv[1], "rb");
220
+ if (!f) {
221
+ printf("Error opening the input file.\n");
222
+ return 1;
223
+ }
224
+ fseek(f, 0, SEEK_END);
225
+ size = (int) ftell(f);
226
+ buf = (char*) malloc(size);
227
+ fseek(f, 0, SEEK_SET);
228
+ size = (int) fread(buf, 1, size, f);
229
+ fclose(f);
230
+
231
+ njInit();
232
+ if (njDecode(buf, size)) {
233
+ free((void*)buf);
234
+ printf("Error decoding the input file.\n");
235
+ return 1;
236
+ }
237
+ free((void*)buf);
238
+
239
+ unsigned char * pixels = njGetImage();
240
+
241
+ // width/height | the same for every frame
242
+ // repeat | 0 = loop forever, 1 = loop once, etc...
243
+ // palSize | must be power of 2 - 1. so, 255 not 256.
244
+ jo_gif_t gif = jo_gif_start("foo.gif", njGetWidth(), njGetHeight(), 0, 3);
245
+ jo_gif_frame(&gif, pixels, 0, 0);
246
+ jo_gif_end(&gif);
247
+
248
+ // f = fopen((argc > 2) ? argv[2] : (njIsColor() ? "nanojpeg_out.ppm" : "nanojpeg_out.pgm"), "wb");
249
+ // if (!f) {
250
+ // printf("Error opening the output file.\n");
251
+ // return 1;
252
+ // }
253
+
254
+ // fprintf(f, "P%d\n%d %d\n255\n", njIsColor() ? 6 : 5, njGetWidth(), njGetHeight());
255
+ // fwrite(njGetImage(), 1, njGetImageSize(), f);
256
+ // fclose(f);
257
+
258
+ njDone();
259
+ return 0;
260
+ }
261
+
262
+ #endif
263
+
264
+
265
+ ///////////////////////////////////////////////////////////////////////////////
266
+ // IMPLEMENTATION SECTION //
267
+ // you may stop reading here //
268
+ ///////////////////////////////////////////////////////////////////////////////
269
+
270
+ #ifndef _NJ_INCLUDE_HEADER_ONLY
271
+
272
+ #ifdef _MSC_VER
273
+ #define NJ_INLINE static __inline
274
+ #define NJ_FORCE_INLINE static __forceinline
275
+ #else
276
+ #define NJ_INLINE static inline
277
+ #define NJ_FORCE_INLINE static inline
278
+ #endif
279
+
280
+ #if NJ_USE_LIBC
281
+ #include <stdlib.h>
282
+ #include <string.h>
283
+ #define njAllocMem malloc
284
+ #define njFreeMem free
285
+ #define njFillMem memset
286
+ #define njCopyMem memcpy
287
+ #elif NJ_USE_WIN32
288
+ #include <windows.h>
289
+ #define njAllocMem(size) ((void*) LocalAlloc(LMEM_FIXED, (SIZE_T)(size)))
290
+ #define njFreeMem(block) ((void) LocalFree((HLOCAL) block))
291
+ NJ_INLINE void njFillMem(void* block, unsigned char value, int count) { __asm {
292
+ mov edi, block
293
+ mov al, value
294
+ mov ecx, count
295
+ rep stosb
296
+ } }
297
+ NJ_INLINE void njCopyMem(void* dest, const void* src, int count) { __asm {
298
+ mov edi, dest
299
+ mov esi, src
300
+ mov ecx, count
301
+ rep movsb
302
+ } }
303
+ #else
304
+ extern void* njAllocMem(int size);
305
+ extern void njFreeMem(void* block);
306
+ extern void njFillMem(void* block, unsigned char byte, int size);
307
+ extern void njCopyMem(void* dest, const void* src, int size);
308
+ #endif
309
+
310
+ typedef struct _nj_code {
311
+ unsigned char bits, code;
312
+ } nj_vlc_code_t;
313
+
314
+ typedef struct _nj_cmp {
315
+ int cid;
316
+ int ssx, ssy;
317
+ int width, height;
318
+ int stride;
319
+ int qtsel;
320
+ int actabsel, dctabsel;
321
+ int dcpred;
322
+ unsigned char *pixels;
323
+ } nj_component_t;
324
+
325
+ typedef struct _nj_ctx {
326
+ nj_result_t error;
327
+ const unsigned char *pos;
328
+ int size;
329
+ int length;
330
+ int width, height;
331
+ int mbwidth, mbheight;
332
+ int mbsizex, mbsizey;
333
+ int ncomp;
334
+ nj_component_t comp[3];
335
+ int qtused, qtavail;
336
+ unsigned char qtab[4][64];
337
+ nj_vlc_code_t vlctab[4][65536];
338
+ int buf, bufbits;
339
+ int block[64];
340
+ int rstinterval;
341
+ unsigned char *rgb;
342
+ } nj_context_t;
343
+
344
+ static nj_context_t nj;
345
+
346
+ static const char njZZ[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18,
347
+ 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35,
348
+ 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45,
349
+ 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 };
350
+
351
+ NJ_FORCE_INLINE unsigned char njClip(const int x) {
352
+ return (x < 0) ? 0 : ((x > 0xFF) ? 0xFF : (unsigned char) x);
353
+ }
354
+
355
+ #define W1 2841
356
+ #define W2 2676
357
+ #define W3 2408
358
+ #define W5 1609
359
+ #define W6 1108
360
+ #define W7 565
361
+
362
+ NJ_INLINE void njRowIDCT(int* blk) {
363
+ int x0, x1, x2, x3, x4, x5, x6, x7, x8;
364
+ if (!((x1 = blk[4] << 11)
365
+ | (x2 = blk[6])
366
+ | (x3 = blk[2])
367
+ | (x4 = blk[1])
368
+ | (x5 = blk[7])
369
+ | (x6 = blk[5])
370
+ | (x7 = blk[3])))
371
+ {
372
+ blk[0] = blk[1] = blk[2] = blk[3] = blk[4] = blk[5] = blk[6] = blk[7] = blk[0] << 3;
373
+ return;
374
+ }
375
+ x0 = (blk[0] << 11) + 128;
376
+ x8 = W7 * (x4 + x5);
377
+ x4 = x8 + (W1 - W7) * x4;
378
+ x5 = x8 - (W1 + W7) * x5;
379
+ x8 = W3 * (x6 + x7);
380
+ x6 = x8 - (W3 - W5) * x6;
381
+ x7 = x8 - (W3 + W5) * x7;
382
+ x8 = x0 + x1;
383
+ x0 -= x1;
384
+ x1 = W6 * (x3 + x2);
385
+ x2 = x1 - (W2 + W6) * x2;
386
+ x3 = x1 + (W2 - W6) * x3;
387
+ x1 = x4 + x6;
388
+ x4 -= x6;
389
+ x6 = x5 + x7;
390
+ x5 -= x7;
391
+ x7 = x8 + x3;
392
+ x8 -= x3;
393
+ x3 = x0 + x2;
394
+ x0 -= x2;
395
+ x2 = (181 * (x4 + x5) + 128) >> 8;
396
+ x4 = (181 * (x4 - x5) + 128) >> 8;
397
+ blk[0] = (x7 + x1) >> 8;
398
+ blk[1] = (x3 + x2) >> 8;
399
+ blk[2] = (x0 + x4) >> 8;
400
+ blk[3] = (x8 + x6) >> 8;
401
+ blk[4] = (x8 - x6) >> 8;
402
+ blk[5] = (x0 - x4) >> 8;
403
+ blk[6] = (x3 - x2) >> 8;
404
+ blk[7] = (x7 - x1) >> 8;
405
+ }
406
+
407
+ NJ_INLINE void njColIDCT(const int* blk, unsigned char *out, int stride) {
408
+ int x0, x1, x2, x3, x4, x5, x6, x7, x8;
409
+ if (!((x1 = blk[8*4] << 8)
410
+ | (x2 = blk[8*6])
411
+ | (x3 = blk[8*2])
412
+ | (x4 = blk[8*1])
413
+ | (x5 = blk[8*7])
414
+ | (x6 = blk[8*5])
415
+ | (x7 = blk[8*3])))
416
+ {
417
+ x1 = njClip(((blk[0] + 32) >> 6) + 128);
418
+ for (x0 = 8; x0; --x0) {
419
+ *out = (unsigned char) x1;
420
+ out += stride;
421
+ }
422
+ return;
423
+ }
424
+ x0 = (blk[0] << 8) + 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
+
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 = (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 = (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 = (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
+
496
+ NJ_INLINE void njSkipBits(int bits) {
497
+ if (nj.bufbits < bits)
498
+ (void) njShowBits(bits);
499
+ nj.bufbits -= bits;
500
+ }
501
+
502
+ NJ_INLINE int njGetBits(int bits) {
503
+ int res = njShowBits(bits);
504
+ njSkipBits(bits);
505
+ return res;
506
+ }
507
+
508
+ NJ_INLINE void njByteAlign(void) {
509
+ nj.bufbits &= 0xF8;
510
+ }
511
+
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
+
519
+ NJ_INLINE unsigned short njDecode16(const unsigned char *pos) {
520
+ return (pos[0] << 8) | pos[1];
521
+ }
522
+
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
+
530
+ NJ_INLINE void njSkipMarker(void) {
531
+ njDecodeLength();
532
+ njSkip(nj.length);
533
+ }
534
+
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 = ssxmax << 3;
572
+ nj.mbsizey = 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 * 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 * 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
+
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 -= currcnt << (16 - codelen);
611
+ if (remain < 0) njThrow(NJ_SYNTAX_ERROR);
612
+ for (i = 0; i < currcnt; ++i) {
613
+ register 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
+
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
+
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
+
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 += ((-1) << bits) + 1;
667
+ return value;
668
+ }
669
+
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
+
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[((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
+
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
+
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
+
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
+
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
+ register int y = py[x] << 8;
856
+ register int cb = pcb[x] - 128;
857
+ register 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
+
880
+ void njInit(void) {
881
+ njFillMem(&nj, 0, sizeof(nj_context_t));
882
+ }
883
+
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
+
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
+
922
+ int njGetWidth(void) { return nj.width; }
923
+ int njGetHeight(void) { return nj.height; }
924
+ int njIsColor(void) { return (nj.ncomp != 1); }
925
+ unsigned char* njGetImage(void) { return (nj.ncomp == 1) ? nj.comp[0].pixels : nj.rgb; }
926
+ int njGetImageSize(void) { return nj.width * nj.height * nj.ncomp; }
927
+
928
+ #endif // _NJ_INCLUDE_HEADER_ONLY