nanojpeg.c 30 KB

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