{"id":715,"date":"2013-09-07T11:37:43","date_gmt":"2013-09-07T03:37:43","guid":{"rendered":"http:\/\/guoh.ai\/lifelog\/?p=715"},"modified":"2013-09-07T23:47:34","modified_gmt":"2013-09-07T15:47:34","slug":"nanojpeg-a-compact-jpeg-decoder","status":"publish","type":"post","link":"https:\/\/guoh.ai\/lifelog\/2013\/09\/nanojpeg-a-compact-jpeg-decoder\/","title":{"rendered":"NanoJPEG\uff0c\u4e00\u4e2a\u7b80\u5355\u7684JPEG\u89e3\u7801\u5668\u5206\u6790"},"content":{"rendered":"<p>\u81ea\u5df1\u5b66\u4e60\u4e86\u4e0b<a href=\"http:\/\/guoh.ai\/lifelog\/2013\/09\/memos-about-jpeg\/\" targe=\"_blank\">JPEG\u7406\u8bba\u77e5\u8bc6<\/a>\u4ee5\u540e\uff0c\u627e\u4e86\u4e2a\u7b80\u5355\u7684\u89e3\u7801\u5668(<a href=\"http:\/\/keyj.emphy.de\/nanojpeg\/\" target=\"_blank\">NanoJPEG<\/a>)\u8bd5\u8bd5\u770b\uff0c\u539f\u59cb\u5730\u5740\u5728\u8fd9\u91cc<a href=\"http:\/\/keyj.emphy.de\/nanojpeg\/\" target=\"_blank\">http:\/\/keyj.emphy.de\/nanojpeg\/<\/a>\uff0c\u77ed\u77ed\u51e0\u767e\u884c\uff0c\u8fd8\u662f\u6bd4\u8f83\u5bb9\u6613\u770b\u61c2\u7684\uff0c\u672c\u4eba\u7406\u89e3\u8be6\u7ec6\u53c2\u89c1\u4ee3\u7801\u6ce8\u91ca\uff0c\u5982\u7406\u89e3\u6709\u8bef\u6b22\u8fce\u6307\u51fa\uff0c\u6709\u95ee\u9898\/\u5174\u8da3\u4e5f\u53ef\u4ee5\u7559\u8a00\u548c\u6211\u8ba8\u8bba\u3002<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n$ gcc -O3 -D_NJ_EXAMPLE_PROGRAM -o nanojpeg nanojpeg.c\r\n$ .\/nanojpeg testorig.jpg \r\n<\/pre>\n<p>\u8ddf\u7740main\u51fd\u6570\uff0c\u8fb9\u7406\u8bba\u8fb9\u5b9e\u8df5\uff0c\u4e0d\u9519\u7684\u65b9\u6cd5\uff01<\/p>\n<p>\/\/ NanoJPEG &#8212; KeyJ&#8217;s Tiny Baseline JPEG Decoder<br \/>\n\/\/ version 1.3 (2012-03-05)<br \/>\n\/\/ by Martin J. Fiedler <martin.fiedler@gmx.net><br \/>\n\/\/<br \/>\n\/\/ This software is published under the terms of KeyJ&#8217;s Research License,<br \/>\n\/\/ version 0.2. Usage of this software is subject to the following conditions:<br \/>\n\/\/ 0. There&#8217;s no warranty whatsoever. The author(s) of this software can not<br \/>\n\/\/    be held liable for any damages that occur when using this software.<br \/>\n\/\/ 1. This software may be used freely for both non-commercial and commercial<br \/>\n\/\/    purposes.<br \/>\n\/\/ 2. This software may be redistributed freely as long as no fees are charged<br \/>\n\/\/    for the distribution and this license information is included.<br \/>\n\/\/ 3. This software may be modified freely except for this license information,<br \/>\n\/\/    which must not be changed in any way.<br \/>\n\/\/ 4. If anything other than configuration, indentation or comments have been<br \/>\n\/\/    altered in the code, the original author(s) must receive a copy of the<br \/>\n\/\/    modified code.<\/p>\n<p>\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/<br \/>\n\/\/ DOCUMENTATION SECTION                                                     \/\/<br \/>\n\/\/ read this if you want to know what this is all about                      \/\/<br \/>\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/<\/p>\n<p>\/\/ INTRODUCTION<br \/>\n\/\/ ============<br \/>\n\/\/<br \/>\n\/\/ This is a minimal decoder for baseline JPEG images. It accepts memory dumps<br \/>\n\/\/ of JPEG files as input and generates either 8-bit grayscale or packed 24-bit<br \/>\n\/\/ RGB images as output. It does not parse JFIF or Exif headers; all JPEG files<br \/>\n\/\/ are assumed to be either grayscale or YCbCr. CMYK or other color spaces are<br \/>\n\/\/ not supported. All YCbCr subsampling schemes with power-of-two ratios are<br \/>\n\/\/ supported, as are restart intervals. Progressive or lossless JPEG is not<br \/>\n\/\/ supported.<br \/>\n\/\/ Summed up, NanoJPEG should be able to decode all images from digital cameras<br \/>\n\/\/ and most common forms of other non-progressive JPEG images.<br \/>\n\/\/ The decoder is not optimized for speed, it&#8217;s optimized for simplicity and<br \/>\n\/\/ small code. Image quality should be at a reasonable level. A bicubic chroma<br \/>\n\/\/ upsampling filter ensures that subsampled YCbCr images are rendered in<br \/>\n\/\/ decent quality. The decoder is not meant to deal with broken JPEG files in<br \/>\n\/\/ a graceful manner; if anything is wrong with the bitstream, decoding will<br \/>\n\/\/ simply fail.<br \/>\n\/\/ The code should work with every modern C compiler without problems and<br \/>\n\/\/ should not emit any warnings. It uses only (at least) 32-bit integer<br \/>\n\/\/ arithmetic and is supposed to be endianness independent and 64-bit clean.<br \/>\n\/\/ However, it is not thread-safe.<\/p>\n<p>\/\/ COMPILE-TIME CONFIGURATION<br \/>\n\/\/ ==========================<br \/>\n\/\/<br \/>\n\/\/ The following aspects of NanoJPEG can be controlled with preprocessor<br \/>\n\/\/ defines:<br \/>\n\/\/<br \/>\n\/\/ _NJ_EXAMPLE_PROGRAM     = Compile a main() function with an example<br \/>\n\/\/                           program.<br \/>\n\/\/ _NJ_INCLUDE_HEADER_ONLY = Don&#8217;t compile anything, just act as a header<br \/>\n\/\/                           file for NanoJPEG. Example:<br \/>\n\/\/                               #define _NJ_INCLUDE_HEADER_ONLY<br \/>\n\/\/                               #include &#8220;nanojpeg.c&#8221;<br \/>\n\/\/                               int main(void) {<br \/>\n\/\/                                   njInit();<br \/>\n\/\/                                   \/\/ your code here<br \/>\n\/\/                                   njDone();<br \/>\n\/\/                               }<br \/>\n\/\/ NJ_USE_LIBC=1           = Use the malloc(), free(), memset() and memcpy()<br \/>\n\/\/                           functions from the standard C library (default).<br \/>\n\/\/ NJ_USE_LIBC=0           = Don&#8217;t use the standard C library. In this mode,<br \/>\n\/\/                           external functions njAlloc(), njFreeMem(),<br \/>\n\/\/                           njFillMem() and njCopyMem() need to be defined<br \/>\n\/\/                           and implemented somewhere.<br \/>\n\/\/ NJ_USE_WIN32=0          = Normal mode (default).<br \/>\n\/\/ NJ_USE_WIN32=1          = If compiling with MSVC for Win32 and<br \/>\n\/\/                           NJ_USE_LIBC=0, NanoJPEG will use its own<br \/>\n\/\/                           implementations of the required C library<br \/>\n\/\/                           functions (default if compiling with MSVC and<br \/>\n\/\/                           NJ_USE_LIBC=0).<br \/>\n\/\/ NJ_CHROMA_FILTER=1      = Use the bicubic chroma upsampling filter<br \/>\n\/\/                           (default). \/\/ \u56fe\u50cfresize\u7684\u4e00\u79cd\u7b97\u6cd5<br \/>\n\/\/ NJ_CHROMA_FILTER=0      = Use simple pixel repetition for chroma upsampling<br \/>\n\/\/                           (bad quality, but faster and less code).<\/p>\n<p>\/\/ API<br \/>\n\/\/ ===<br \/>\n\/\/<br \/>\n\/\/ For API documentation, read the &#8220;header section&#8221; below.<\/p>\n<p>\/\/ EXAMPLE<br \/>\n\/\/ =======<br \/>\n\/\/<br \/>\n\/\/ A few pages below, you can find an example program that uses NanoJPEG to<br \/>\n\/\/ convert JPEG files into PGM or PPM. To compile it, use something like<br \/>\n\/\/     gcc -O3 -D_NJ_EXAMPLE_PROGRAM -o nanojpeg nanojpeg.c<br \/>\n\/\/ You may also add -std=c99 -Wall -Wextra -pedantic -Werror, if you want \ud83d\ude42<\/p>\n<p>\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/<br \/>\n\/\/ HEADER SECTION                                                            \/\/<br \/>\n\/\/ copy and pase this into nanojpeg.h if you want                            \/\/<br \/>\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/<\/p>\n<p>#ifndef _NANOJPEG_H<br \/>\n#define _NANOJPEG_H<\/p>\n<p>\/\/ nj_result_t: Result codes for njDecode().<br \/>\ntypedef enum _nj_result {<br \/>\n    NJ_OK = 0,        \/\/ no error, decoding successful<br \/>\n    NJ_NO_JPEG,       \/\/ not a JPEG file<br \/>\n    NJ_UNSUPPORTED,   \/\/ unsupported format<br \/>\n    NJ_OUT_OF_MEM,    \/\/ out of memory<br \/>\n    NJ_INTERNAL_ERR,  \/\/ internal error<br \/>\n    NJ_SYNTAX_ERROR,  \/\/ syntax error<br \/>\n    __NJ_FINISHED,    \/\/ used internally, will never be reported<br \/>\n} nj_result_t;<\/p>\n<p>\/\/ njInit: Initialize NanoJPEG.<br \/>\n\/\/ For safety reasons, this should be called at least one time before using<br \/>\n\/\/ using any of the other NanoJPEG functions.<br \/>\nvoid njInit(void);<\/p>\n<p>\/\/ njDecode: Decode a JPEG image.<br \/>\n\/\/ Decodes a memory dump of a JPEG file into internal buffers.<br \/>\n\/\/ Parameters:<br \/>\n\/\/   jpeg = The pointer to the memory dump.<br \/>\n\/\/   size = The size of the JPEG file.<br \/>\n\/\/ Return value: The error code in case of failure, or NJ_OK (zero) on success.<br \/>\nnj_result_t njDecode(const void* jpeg, const int size);<\/p>\n<p>\/\/ njGetWidth: Return the width (in pixels) of the most recently decoded<br \/>\n\/\/ image. If njDecode() failed, the result of njGetWidth() is undefined.<br \/>\nint njGetWidth(void);<\/p>\n<p>\/\/ njGetHeight: Return the height (in pixels) of the most recently decoded<br \/>\n\/\/ image. If njDecode() failed, the result of njGetHeight() is undefined.<br \/>\nint njGetHeight(void);<\/p>\n<p>\/\/ njIsColor: Return 1 if the most recently decoded image is a color image<br \/>\n\/\/ (RGB) or 0 if it is a grayscale image. If njDecode() failed, the result<br \/>\n\/\/ of njGetWidth() is undefined.<br \/>\nint njIsColor(void);<\/p>\n<p>\/\/ njGetImage: Returns the decoded image data.<br \/>\n\/\/ Returns a pointer to the most recently image. The memory layout it byte-<br \/>\n\/\/ oriented, top-down, without any padding between lines. Pixels of color<br \/>\n\/\/ images will be stored as three consecutive bytes for the red, green and<br \/>\n\/\/ blue channels. This data format is thus compatible with the PGM or PPM<br \/>\n\/\/ file formats and the OpenGL texture formats GL_LUMINANCE8 or GL_RGB8.<br \/>\n\/\/ If njDecode() failed, the result of njGetImage() is undefined.<br \/>\nunsigned char* njGetImage(void);<\/p>\n<p>\/\/ njGetImageSize: Returns the size (in bytes) of the image data returned<br \/>\n\/\/ by njGetImage(). If njDecode() failed, the result of njGetImageSize() is<br \/>\n\/\/ undefined.<br \/>\nint njGetImageSize(void);<\/p>\n<p>\/\/ njDone: Uninitialize NanoJPEG.<br \/>\n\/\/ Resets NanoJPEG&#8217;s internal state and frees all memory that has been<br \/>\n\/\/ allocated at run-time by NanoJPEG. It is still possible to decode another<br \/>\n\/\/ image after a njDone() call.<br \/>\nvoid njDone(void);<\/p>\n<p>#endif\/\/_NANOJPEG_H<\/p>\n<p>\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/<br \/>\n\/\/ CONFIGURATION SECTION                                                     \/\/<br \/>\n\/\/ adjust the default settings for the NJ_ defines here                      \/\/<br \/>\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/<\/p>\n<p>#ifndef NJ_USE_LIBC<br \/>\n    #define NJ_USE_LIBC 1<br \/>\n#endif<\/p>\n<p>#ifndef NJ_USE_WIN32<br \/>\n  #ifdef _MSC_VER<br \/>\n    #define NJ_USE_WIN32 (!NJ_USE_LIBC)<br \/>\n  #else<br \/>\n    #define NJ_USE_WIN32 0<br \/>\n  #endif<br \/>\n#endif<\/p>\n<p>#ifndef NJ_CHROMA_FILTER<br \/>\n    #define NJ_CHROMA_FILTER 1<br \/>\n#endif<\/p>\n<p>\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/<br \/>\n\/\/ EXAMPLE PROGRAM                                                           \/\/<br \/>\n\/\/ just define _NJ_EXAMPLE_PROGRAM to compile this (requires NJ_USE_LIBC)    \/\/<br \/>\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/<\/p>\n<p>#ifdef  _NJ_EXAMPLE_PROGRAM<\/p>\n<p>#include <stdio.h><br \/>\n#include <stdlib.h><br \/>\n#include <string.h><\/p>\n<p>int main(int argc, char* argv[]) {<br \/>\n    int size;<br \/>\n    char *buf;<br \/>\n    FILE *f;<\/p>\n<p>    if (argc < 2) {\n        printf(\"Usage: %s <input.jpg> [<output.ppm>]\\n&#8221;, argv[0]);<br \/>\n        return 2;<br \/>\n    }<br \/>\n    f = fopen(argv[1], &#8220;rb&#8221;);<br \/>\n    if (!f) {<br \/>\n        printf(&#8220;Error opening the input file.\\n&#8221;);<br \/>\n        return 1;<br \/>\n    }<br \/>\n    fseek(f, 0, SEEK_END);<br \/>\n    size = (int) ftell(f); \/\/ \u5b57\u8282<br \/>\n    buf = malloc(size);<br \/>\n    fseek(f, 0, SEEK_SET);<br \/>\n    size = (int) fread(buf, 1, size, f); \/\/ \u8bfb\u53d6\u6574\u4e2a\u6587\u4ef6\u5185\u5bb9\u5230buf<br \/>\n    fclose(f);<\/p>\n<p>    njInit(); \/\/ \u521d\u59cb\u5316nj_context_t<br \/>\n    if (njDecode(buf, size)) {<br \/>\n        printf(&#8220;Error decoding the input file.\\n&#8221;);<br \/>\n        return 1;<br \/>\n    }<\/p>\n<p>    f = fopen((argc > 2) ? argv[2] : (njIsColor() ? &#8220;nanojpeg_out.ppm&#8221; : &#8220;nanojpeg_out.pgm&#8221;), &#8220;wb&#8221;);<br \/>\n    if (!f) {<br \/>\n        printf(&#8220;Error opening the output file.\\n&#8221;);<br \/>\n        return 1;<br \/>\n    }<br \/>\n    fprintf(f, &#8220;P%d\\n%d %d\\n255\\n&#8221;, njIsColor() ? 6 : 5, njGetWidth(), njGetHeight());<br \/>\n    fwrite(njGetImage(), 1, njGetImageSize(), f);<br \/>\n    fclose(f);<br \/>\n    njDone();<br \/>\n    return 0;<br \/>\n}<\/p>\n<p>#endif<\/p>\n<p>\/\/ \u89e3\u91ca\u4ec0\u4e48\u662fstride http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/aa473780(v=vs.85).aspx<\/p>\n<p>\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/<br \/>\n\/\/ IMPLEMENTATION SECTION                                                    \/\/<br \/>\n\/\/ you may stop reading here                                                 \/\/<br \/>\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/<\/p>\n<p>#ifndef _NJ_INCLUDE_HEADER_ONLY<\/p>\n<p>#ifdef _MSC_VER<br \/>\n    #define NJ_INLINE static __inline<br \/>\n    #define NJ_FORCE_INLINE static __forceinline<br \/>\n#else<br \/>\n    #define NJ_INLINE static inline<br \/>\n    #define NJ_FORCE_INLINE static inline<br \/>\n#endif<\/p>\n<p>#if NJ_USE_LIBC<br \/>\n    #include <stdlib.h><br \/>\n    #include <string.h><br \/>\n    #define njAllocMem malloc<br \/>\n    #define njFreeMem  free<br \/>\n    #define njFillMem  memset<br \/>\n    #define njCopyMem  memcpy<br \/>\n#elif NJ_USE_WIN32<br \/>\n    #include <windows.h><br \/>\n    #define njAllocMem(size) ((void*) LocalAlloc(LMEM_FIXED, (SIZE_T)(size)))<br \/>\n    #define njFreeMem(block) ((void) LocalFree((HLOCAL) block))<br \/>\n    NJ_INLINE void njFillMem(void* block, unsigned char value, int count) { __asm {<br \/>\n        mov edi, block<br \/>\n        mov al, value<br \/>\n        mov ecx, count<br \/>\n        rep stosb<br \/>\n    } }<br \/>\n    NJ_INLINE void njCopyMem(void* dest, const void* src, int count) { __asm {<br \/>\n        mov edi, dest<br \/>\n        mov esi, src<br \/>\n        mov ecx, count<br \/>\n        rep movsb<br \/>\n    } }<br \/>\n#else<br \/>\n    extern void* njAllocMem(int size);<br \/>\n    extern void njFreeMem(void* block);<br \/>\n    extern void njFillMem(void* block, unsigned char byte, int size);<br \/>\n    extern void njCopyMem(void* dest, const void* src, int size);<br \/>\n#endif<\/p>\n<p>typedef struct _nj_code {<br \/>\n    unsigned char bits, code;<br \/>\n} nj_vlc_code_t;<\/p>\n<p>typedef struct _nj_cmp {<br \/>\n    int cid;<br \/>\n    int ssx, ssy; \/\/ \u6c34\u5e73\/\u5782\u76f4\u56e0\u5b50<br \/>\n    int width, height;<br \/>\n    int stride;<br \/>\n    int qtsel; \/\/ Quantization Table\u91cf\u5316\u8868<br \/>\n    int actabsel, dctabsel; \/\/ AC\/DC Huffman Table<br \/>\n    int dcpred;<br \/>\n    unsigned char *pixels;<br \/>\n} nj_component_t; \/\/ \u989c\u8272\u5206\u91cf<\/p>\n<p>typedef struct _nj_ctx {<br \/>\n    nj_result_t error;<br \/>\n    const unsigned char *pos; \/\/ \u5f85\u89e3\u7801\u6570\u636e\u6307\u9488(\u6309\u5b57\u8282\u6765)<br \/>\n    int size; \/\/ \u6574\u4e2a\u6570\u636e\u7684\u957f\u5ea6<br \/>\n    int length; \/\/ \u67d0\u4e00\u4e2amarker\u5185\u5bb9\u7684\u957f\u5ea6<br \/>\n    int width, height; \/\/ \u56fe\u7247\u5bbd\u548c\u9ad8\u5ea6<br \/>\n    int mbwidth, mbheight; \/\/ MCU\u6c34\u5e73\/\u5782\u76f4\u4e2a\u6570<br \/>\n    int mbsizex, mbsizey; \/\/ MCU\u5bbd\/\u9ad8<br \/>\n    int ncomp; \/\/ \u989c\u8272\u5206\u91cf\u6570<br \/>\n    nj_component_t comp[3]; \/\/ YCbCr<br \/>\n    int qtused, qtavail; \/\/ \u8fd9\u4e24\u4e2a\u76ee\u524d\u770b\u4e0d\u51fa\u6765\u5f88\u5927\u7528\u5904<br \/>\n    unsigned char qtab[4][64]; \/\/ \u4f46\u662f\u76ee\u524d\u4f3c\u4e4e\u53ea\u67092\u4e2a<br \/>\n    nj_vlc_code_t vlctab[4][65536]; \/\/ \u6784\u9020\u6240\u670916\u4f4d\u6570\u7684Huffman\u57fa\u6570<br \/>\n\t\t\t\t\t\t\t\t\t\/\/ \u76ee\u524d\u57fa\u672c\u4e0a\u662f4\u4e2a(\u76f4\/\u4ea4\/0\/1)<br \/>\n    int buf, bufbits; \/\/ \u8fd9\u662f\u7528\u6765\u505a\u4ec0\u4e48\u7684 buf\u662f\u5b58\u653e\u5185\u5bb9\u7684 bufbits\u662f\u8ba1\u6570\u5668\uff0c\u5b58\u653e\u4e86\u591a\u5c11\u4e2abits<br \/>\n    int block[64];<br \/>\n    int rstinterval;<br \/>\n    unsigned char *rgb; \/\/ \u89e3\u6790\u51fa\u6765\u7684RGB\u6240\u8981\u5360\u7528\u7684\u5185\u5b58 \/\/ \u6bcf1\u4e2a\u70b9\u5305\u542b3\u4e2a\u5b57\u8282\uff0c\u6309\u627eRGB\u7684\u987a\u5e8f<br \/>\n} nj_context_t;<\/p>\n<p>static nj_context_t nj;<\/p>\n<p>static const char njZZ[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18,<br \/>\n11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35,<br \/>\n42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45,<br \/>\n38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 };<\/p>\n<p>\/*<br \/>\n0   1   2   3   4   5   6   7<\/p>\n<p>8   9   10  11  12  13  14  15<\/p>\n<p>16  17  18  19  20  21  22  23<\/p>\n<p>24  25  26  27  28  29  30  31<\/p>\n<p>32  33  34  35  36  37  38  39<\/p>\n<p>40  41  42  43  44  45  46  47<\/p>\n<p>48  49  50  51  52  53  54  55<\/p>\n<p>56  57  58  59  60  61  62  63<br \/>\n*\/<\/p>\n<p>NJ_FORCE_INLINE unsigned char njClip(const int x) { \/\/ \u9650\u5b9a\u8303\u56f4\u662f0 ~ 255\u4e4b\u95f4<br \/>\n    return (x < 0) ? 0 : ((x > 0xFF) ? 0xFF : (unsigned char) x);<br \/>\n}<\/p>\n<p>#define W1 2841<br \/>\n#define W2 2676<br \/>\n#define W3 2408<br \/>\n#define W5 1609<br \/>\n#define W6 1108<br \/>\n#define W7 565<\/p>\n<p>NJ_INLINE void njRowIDCT(int* blk) { \/\/ \u6309\u884c\u6765\u64cd\u4f5c\u7684 0 ~ 7 \/\/ 8 ~ 15<br \/>\n    int x0, x1, x2, x3, x4, x5, x6, x7, x8;<br \/>\n    if (!((x1 = blk[4] << 11)\n        | (x2 = blk[6])\n        | (x3 = blk[2])\n        | (x4 = blk[1])\n        | (x5 = blk[7])\n        | (x6 = blk[5])\n        | (x7 = blk[3])))\n    {\n        blk[0] = blk[1] = blk[2] = blk[3] = blk[4] = blk[5] = blk[6] = blk[7] = blk[0] << 3;\n        return;\n    }\n    x0 = (blk[0] << 11) + 128;\n    x8 = W7 * (x4 + x5);\n    x4 = x8 + (W1 - W7) * x4;\n    x5 = x8 - (W1 + W7) * x5;\n    x8 = W3 * (x6 + x7);\n    x6 = x8 - (W3 - W5) * x6;\n    x7 = x8 - (W3 + W5) * x7;\n    x8 = x0 + x1;\n    x0 -= x1;\n    x1 = W6 * (x3 + x2);\n    x2 = x1 - (W2 + W6) * x2;\n    x3 = x1 + (W2 - W6) * x3;\n    x1 = x4 + x6;\n    x4 -= x6;\n    x6 = x5 + x7;\n    x5 -= x7;\n    x7 = x8 + x3;\n    x8 -= x3;\n    x3 = x0 + x2;\n    x0 -= x2;\n    x2 = (181 * (x4 + x5) + 128) >> 8;<br \/>\n    x4 = (181 * (x4 &#8211; x5) + 128) >> 8;<br \/>\n    blk[0] = (x7 + x1) >> 8;<br \/>\n    blk[1] = (x3 + x2) >> 8;<br \/>\n    blk[2] = (x0 + x4) >> 8;<br \/>\n    blk[3] = (x8 + x6) >> 8;<br \/>\n    blk[4] = (x8 &#8211; x6) >> 8;<br \/>\n    blk[5] = (x0 &#8211; x4) >> 8;<br \/>\n    blk[6] = (x3 &#8211; x2) >> 8;<br \/>\n    blk[7] = (x7 &#8211; x1) >> 8;<br \/>\n}<\/p>\n<p>NJ_INLINE void njColIDCT(const int* blk, unsigned char *out, int stride) {<br \/>\n    int x0, x1, x2, x3, x4, x5, x6, x7, x8;<br \/>\n    if (!((x1 = blk[8*4] << 8)\n        | (x2 = blk[8*6])\n        | (x3 = blk[8*2])\n        | (x4 = blk[8*1])\n        | (x5 = blk[8*7])\n        | (x6 = blk[8*5])\n        | (x7 = blk[8*3])))\n    {\n        x1 = njClip(((blk[0] + 32) >> 6) + 128);<br \/>\n        for (x0 = 8;  x0;  &#8211;x0) {<br \/>\n            *out = (unsigned char) x1;<br \/>\n            out += stride;<br \/>\n        }<br \/>\n        return;<br \/>\n    }<br \/>\n    x0 = (blk[0] << 8) + 8192;\n    x8 = W7 * (x4 + x5) + 4;\n    x4 = (x8 + (W1 - W7) * x4) >> 3;<br \/>\n    x5 = (x8 &#8211; (W1 + W7) * x5) >> 3;<br \/>\n    x8 = W3 * (x6 + x7) + 4;<br \/>\n    x6 = (x8 &#8211; (W3 &#8211; W5) * x6) >> 3;<br \/>\n    x7 = (x8 &#8211; (W3 + W5) * x7) >> 3;<br \/>\n    x8 = x0 + x1;<br \/>\n    x0 -= x1;<br \/>\n    x1 = W6 * (x3 + x2) + 4;<br \/>\n    x2 = (x1 &#8211; (W2 + W6) * x2) >> 3;<br \/>\n    x3 = (x1 + (W2 &#8211; W6) * x3) >> 3;<br \/>\n    x1 = x4 + x6;<br \/>\n    x4 -= x6;<br \/>\n    x6 = x5 + x7;<br \/>\n    x5 -= x7;<br \/>\n    x7 = x8 + x3;<br \/>\n    x8 -= x3;<br \/>\n    x3 = x0 + x2;<br \/>\n    x0 -= x2;<br \/>\n    x2 = (181 * (x4 + x5) + 128) >> 8; \/\/ Y\uff0cCb\u548cCr\u7684\u503c\u90fd\u8303\u56f4\u90fd\u662f-128 ~ 127\uff0c\u5e76\u4e14\u5728FDCT\u7684\u65f6\u5019\u6709\u5148\u51cf\u53bb128\uff0c\u6240\u4ee5\u73b0\u5728\u8981IDCT\u4e4b\u540e\u518d\u52a0\u4e0a128<br \/>\n    x4 = (181 * (x4 &#8211; x5) + 128) >> 8;<br \/>\n    *out = njClip(((x7 + x1) >> 14) + 128);  out += stride;<br \/>\n    *out = njClip(((x3 + x2) >> 14) + 128);  out += stride;<br \/>\n    *out = njClip(((x0 + x4) >> 14) + 128);  out += stride;<br \/>\n    *out = njClip(((x8 + x6) >> 14) + 128);  out += stride;<br \/>\n    *out = njClip(((x8 &#8211; x6) >> 14) + 128);  out += stride;<br \/>\n    *out = njClip(((x0 &#8211; x4) >> 14) + 128);  out += stride;<br \/>\n    *out = njClip(((x3 &#8211; x2) >> 14) + 128);  out += stride;<br \/>\n    *out = njClip(((x7 &#8211; x1) >> 14) + 128);<br \/>\n}<\/p>\n<p>#define njThrow(e) do { nj.error = e; return; } while (0)<br \/>\n#define njCheckError() do { if (nj.error) return; } while (0)<\/p>\n<p>static int njShowBits(int bits) { \/\/ \u80fd\u653e\u5f97\u4e0b\u5927\u4e8e32\u4f4d\u7684\u503c\u4e48\uff1f<br \/>\n    unsigned char newbyte;<br \/>\n    if (!bits) return 0;<br \/>\n    while (nj.bufbits < bits) { \/\/ \u4e5f\u5c31\u662f\u8bf4\u8981buf\u7684\u4f4d\u6570\u5c0f\u4e8e\u5df2\u7ecfbuf\u7684\u4f4d\u6570\u7684\u65f6\u5019\uff0c\u5c31\u76f4\u63a5\u8bfb\u51fa\u6765\uff1f\n        if (nj.size <= 0) {\n            nj.buf = (nj.buf << 8) | 0xFF;\n            nj.bufbits += 8;\n            continue;\n        }\n        newbyte = *nj.pos++; \/\/ \u6570\u636e\u6307\u9488\u662f\u6309\u5b57\u8282\n        nj.size--;\n        nj.bufbits += 8;\n        nj.buf = (nj.buf << 8) | newbyte; \/\/ \u9ad8\u4f4d\u6700\u7ec8\u4f1a\u88ab\u8986\u76d6\u6389\uff0c\u6bd4\u5982\u6211\u8981buf\u4e00\u4e2a64\u4f4d\u7684\u503c\u600e\u4e48\u529e\uff1f\n        if (newbyte == 0xFF) {\n            if (nj.size) {\n                unsigned char marker = *nj.pos++;\n                nj.size--;\n                switch (marker) {\n                    case 0x00:\n                    case 0xFF:\n                        break;\n                    case 0xD9: nj.size = 0; break;\n                    default:\n                        if ((marker &#038; 0xF8) != 0xD0)\n                            nj.error = NJ_SYNTAX_ERROR;\n                        else {\n                            nj.buf = (nj.buf << 8) | marker;\n                            nj.bufbits += 8;\n                        }\n                }\n            } else\n                nj.error = NJ_SYNTAX_ERROR;\n        }\n    }\n    return (nj.buf >> (nj.bufbits &#8211; bits)) &#038; ((1 << bits) - 1);\n}\n\nNJ_INLINE void njSkipBits(int bits) {\n    if (nj.bufbits < bits)\n        (void) njShowBits(bits);\n    nj.bufbits -= bits;\n}\n\nNJ_INLINE int njGetBits(int bits) {\n    int res = njShowBits(bits);\n    njSkipBits(bits);\n    return res;\n}\n\nNJ_INLINE void njByteAlign(void) {\n    nj.bufbits &#038;= 0xF8; \/\/ (1111 1000)8\u7684\u500d\u6570\uff0c\u4e0d\u6ee18\u7684\u90e8\u5206\u4e22\u5f03\n}\n\nstatic void njSkip(int count) {\n    nj.pos += count; \/\/ \u6570\u636e\u6307\u9488\u589e\u52a0\n    nj.size -= count; \/\/ \u603b\u4f53\u6570\u636e\u5927\u5c0f\u51cf\u53bbcount\n    nj.length -= count; \/\/ \u5f53\u524dmarker\u957f\u5ea6\u51cf\u53bbcount\n    if (nj.size < 0) nj.error = NJ_SYNTAX_ERROR;\n}\n\nNJ_INLINE unsigned short njDecode16(const unsigned char *pos) {\n    return (pos[0] << 8) | pos[1]; \/\/ 00000000 00001101\n}\n\nstatic void njDecodeLength(void) { \/\/ decode\u957f\u5ea6\u5b57\u6bb5\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u8c03\u7528\u4e00\u822c\u90fd\u662f\u5df2\u7ecf\u8fdb\u5165\u5230\u7279\u5b9a\u7684marker\u4e4b\u540e\n    if (nj.size < 2) njThrow(NJ_SYNTAX_ERROR);\n    nj.length = njDecode16(nj.pos); \/\/ \u8be5marker\u7684\u957f\u5ea6(\u9664\u53bbmarker\u540d\u5b57\u6240\u5360\u7528\u76842\u4e2a\u5b57\u8282)\n    if (nj.length > nj.size) njThrow(NJ_SYNTAX_ERROR);<br \/>\n    njSkip(2);<br \/>\n}<\/p>\n<p>NJ_INLINE void njSkipMarker(void) {<br \/>\n    njDecodeLength();<br \/>\n    njSkip(nj.length);<br \/>\n}<\/p>\n<p>NJ_INLINE void njDecodeSOF(void) { \/\/ \u89e3\u6790Start of Frame\u7684\u65f6\u5019\u5c31\u4f1a\u628a\u6240\u9700\u8981\u7684\u5185\u5b58\u90fd\u5206\u914d\u597d<br \/>\n    int i, ssxmax = 0, ssymax = 0;<br \/>\n    nj_component_t* c;<br \/>\n    njDecodeLength(); \/\/ \u89e3\u6790\u957f\u5ea6\u5e76\u79fb\u52a8\u6570\u636e\u6307\u9488<br \/>\n    if (nj.length < 9) njThrow(NJ_SYNTAX_ERROR);\n    if (nj.pos[0] != 8) njThrow(NJ_UNSUPPORTED); \/\/ \u6837\u672c\u7cbe\u5ea6\uff0c\u4e00\u822c\u90fd\u662f8\n    nj.height = njDecode16(nj.pos + 1); \/\/ \u56fe\u7247\u9ad8\u5ea6\/\u5bbd\u5ea6\n    nj.width = njDecode16(nj.pos + 3);\n    nj.ncomp = nj.pos[5]; \/\/ \u989c\u8272\u5206\u91cf\u6570\u636e\uff0c\u4e00\u822c\u90fd\u662f3\n    njSkip(6); \/\/ \u4e4b\u524d\u51716\u4e2a\u5b57\u8282\u6570\u636e\uff0c\u6240\u4ee5\u79fb\u52a8\u6570\u636e\u6307\u94886\u4e2a\u5b57\u8282\n    switch (nj.ncomp) { \/\/ \u76ee\u524d\u53ea\u652f\u63011\u548c3\u8fd9\u4e24\u79cd\n        case 1:\n        case 3:\n            break;\n        default:\n            njThrow(NJ_UNSUPPORTED);\n    }\n    if (nj.length < (nj.ncomp * 3)) njThrow(NJ_SYNTAX_ERROR); \/\/ \u6570\u636e\u91cf\u80af\u5b9a\u662f\u8981\u5927\u4e8e\u989c\u8272\u5206\u91cf\u6570 multiply 3\uff0c\u56e0\u4e3a\u63a5\u7740\u5b58\u989c\u8272\u5206\u91cf\u4fe1\u606f\u7684\u6bcf\u4e2a\u7ed3\u6784\u53603\u4e2a\u5b57\u8282\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  \/\/ \u989c\u8272\u5206\u91cfID\u5360\u75281\u4e2a\u5b57\u8282\uff0c\u6c34\u5e73\/\u5782\u76f4\u56e0\u5b50\u5360\u75281\u4e2a\u5b57\u8282(\u9ad84\u4f4d\u6c34\u5e73\uff0c\u4f4e4\u4f4d\u5782\u76f4)\uff0c\u91cf\u5316\u8868\u5360\u75281\u4e2a\u5b57\u8282\n    for (i = 0, c = nj.comp;  i < nj.ncomp;  ++i, ++c) {\n        c->cid = nj.pos[0]; \/\/ \u989c\u8272\u5206\u91cfID<br \/>\n        if (!(c->ssx = nj.pos[1] >> 4)) njThrow(NJ_SYNTAX_ERROR); \/\/ \u9ad84\u4f4d(\u6c34\u5e73\u56e0\u5b50)<br \/>\n        if (c->ssx &#038; (c->ssx &#8211; 1)) njThrow(NJ_UNSUPPORTED);  \/\/ non-power of two<br \/>\n        if (!(c->ssy = nj.pos[1] &#038; 15)) njThrow(NJ_SYNTAX_ERROR); \/\/ (00001111)\u4f4e4\u4f4d(\u5782\u76f4\u56e0\u5b50)<br \/>\n        if (c->ssy &#038; (c->ssy &#8211; 1)) njThrow(NJ_UNSUPPORTED);  \/\/ non-power of two<br \/>\n        if ((c->qtsel = nj.pos[2]) &#038; 0xFC) njThrow(NJ_SYNTAX_ERROR); \/\/ (11111101) \u8fd9\u91cc0xFC\u662f\u7528\u5728\u8fd9\u91cc\u5e72\u4ec0\u4e48\u7684\uff1f<br \/>\n        njSkip(3); \/\/ \u79fb\u52a8\u6570\u636e\u6307\u9488\u5230\u4e0b\u4e00\u4e2a\u989c\u8272\u5206\u91cf<br \/>\n        nj.qtused |= 1 << c->qtsel; \/\/ \u8fd9\u91cc\u662f\u505a\u4ec0\u4e48\u7528\u7684\uff1f\u770b\u4e0d\u51fa\u6765<br \/>\n        if (c->ssx > ssxmax) ssxmax = c->ssx; \/\/ \u8bb0\u5f55\u6700\u5927\u6c34\u5e73\u56e0\u5b50<br \/>\n        if (c->ssy > ssymax) ssymax = c->ssy; \/\/ \u8bb0\u5f55\u6700\u5927\u5782\u76f4\u56e0\u5b50<br \/>\n    }<br \/>\n    if (nj.ncomp == 1) { \/\/ \u53ea\u6709\u4e00\u79cd\u989c\u8272\u5206\u91cf\u7684\u65f6\u5019\u5c31\u7b80\u5355\u5566<br \/>\n        c = nj.comp;<br \/>\n        c->ssx = c->ssy = ssxmax = ssymax = 1;<br \/>\n    }<br \/>\n    nj.mbsizex = ssxmax << 3; \/\/ MCU\u5bbd \u662f \u6c34\u5e73\u91c7\u6837\u56e0\u5b50\u6700\u5927\u503c multiply 8\n    nj.mbsizey = ssymax << 3; \/\/ MCU\u9ad8 \u662f \u5782\u76f4\u91c7\u6837\u56e0\u5b50\u6700\u5927\u503c multiply 8\n    nj.mbwidth = (nj.width + nj.mbsizex - 1) \/ nj.mbsizex; \/\/ \u5206\u5b50\u91c7\u7528+ nj.mbsizex - 1\u5c31\u53d6\u5230\u5927\u4e8e\u4f46\u662f\u6700\u63a5\u8fd1(\u7b49\u4e8e)\u5bbd\u5ea6\u7684\u503c\uff0c\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t   \/\/ \u5e76\u4e14\u8fd9\u4e2a\u503c\u662fMCU\u5bbd\u5ea6\u6574\u6570\u500d \/\/ \u8fd9\u91cc\u662f\u6c34\u5e73\u65b9\u5411MCU\u7684\u4e2a\u6570\n    nj.mbheight = (nj.height + nj.mbsizey - 1) \/ nj.mbsizey; \/\/ \u8fd9\u91cc\u662f\u5782\u76f4\u65b9\u5411MCU\u7684\u4e2a\u6570\n    for (i = 0, c = nj.comp;  i < nj.ncomp;  ++i, ++c) {\n        c->width = (nj.width * c->ssx + ssxmax &#8211; 1) \/ ssxmax; \/\/ \u91c7\u6837\u5bbd\u5ea6\uff1f \u6700\u5927\u6c34\u5e73\/\u5782\u76f4\u56e0\u5b50\u7684\u503c\u5c31\u662f\u56fe\u7247\u539f\u6765\u7684\u503c\uff0c\u5426\u5219\u5c31\u4f1a\u6839\u636e\u56e0\u5b50\u505a\u76f8\u5e94\u7684\u51cf\u5c11<br \/>\n        c->stride = (c->width + 7) &#038; 0x7FFFFFF8; \/\/ (0111 1111 1111 1111 1111 1111 1111 1000) \u505a\u4ec0\u4e48\uff1f\u4ee51234567\u7ed3\u5c3e\u7684\u90fd\u7701\u7565\u6389\uff1f<br \/>\n\t\t\t\t\t\t\t\t\t\t\t\t \/\/ \u53d8\u62108\u7684\u6574\u6570<br \/>\n\t\t\t\t\t\t\t\t\t\t\t\t \/\/ \u8865\u9f508\u4f4d\uff0c\u6ce8\u610f\u524d\u9762\u6709\u52a07\uff0c\u6240\u4ee5\u603b\u662f\u4e0d\u4f1a\u6bd4\u539f\u6765\u7684\u5c11\uff0c\u6bd4\u5982\u539f\u6765\u662f227\uff0c\u90a3\u4e48\u8fd9\u91cc\u5c31\u4f1a\u53d8\u6210232<br \/>\n\t\t\t\t\t\t\t\t\t\t\t\t \/\/ \u8fd9\u662f\u6309\u7167\u6570\u636e\u5355\u5143\u8ba1\u7b97\u7684\uff0c\u6240\u4ee5\u4e0d\u5bf9<br \/>\n\t\tprintf(&#8220;%d, stride %d\\n&#8221;, i, c->stride);<br \/>\n        c->height = (nj.height * c->ssy + ssymax &#8211; 1) \/ ssymax;<br \/>\n        c->stride = nj.mbwidth * nj.mbsizex * c->ssx \/ ssxmax; \/\/ \u518d\u8ba1\u7b97\u4e00\u904dstride\u6709\u4ec0\u4e48\u7528\uff1f\u524d\u9762\u8ba1\u7b97\u7684\u662f\u9519\u8bef\u7684\uff0c\u6ca1\u6709\u8003\u8651MCU\u5bbd\u5ea6<br \/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   \/\/ \u8fd9\u91cc\u90fd\u5df2\u7ecf\u662fround\u8fc7\u7684\u4e86\uff0c\u6240\u4ee5\u76f4\u63a5\u8ba1\u7b97<br \/>\n\t\tprintf(&#8220;%d, stride again %d\\n&#8221;, i, c->stride);<br \/>\n        if (((c->width < 3) &#038;&#038; (c->ssx != ssxmax)) || ((c->height < 3) &#038;&#038; (c->ssy != ssymax))) njThrow(NJ_UNSUPPORTED);<br \/>\n        if (!(c->pixels = njAllocMem(c->stride * (nj.mbheight * nj.mbsizey * c->ssy \/ ssymax)))) njThrow(NJ_OUT_OF_MEM); \/\/ \u4e3a\u5206\u91cf\u5206\u914d\u5185\u5b58<br \/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \/\/ \u5927\u5c0f\u662f\u6240\u6709MCU\u7684<br \/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \/\/ \u53ef\u80fd\u6bd4\u56fe\u7247\u5b9e\u9645<br \/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \/\/ \u5c3a\u5bf8\u5927<br \/>\n    }<br \/>\n    if (nj.ncomp == 3) { \/\/ \u53ea\u6709\u67093\u4e2a\u989c\u8272\u5206\u91cf\u7684\u65f6\u5019\u624d\u9700\u8981<br \/>\n        nj.rgb = njAllocMem(nj.width * nj.height * nj.ncomp);<br \/>\n        if (!nj.rgb) njThrow(NJ_OUT_OF_MEM);<br \/>\n    }<br \/>\n    njSkip(nj.length);<br \/>\n}<\/p>\n<p>NJ_INLINE void njDecodeDHT(void) {<br \/>\n    int codelen, currcnt, remain, spread, i, j;<br \/>\n    nj_vlc_code_t *vlc;<br \/>\n    static unsigned char counts[16]; \/\/ \u7801\u5b57<br \/>\n    njDecodeLength();<br \/>\n    while (nj.length >= 17) { \/\/ \u7801\u5b57\u7684\u6570\u91cf(16) + \u7c7b\u578b\u548cID(1)<br \/>\n        i = nj.pos[0]; \/\/ \u7c7b\u578b\u548cID<br \/>\n        if (i &#038; 0xEC) njThrow(NJ_SYNTAX_ERROR); \/\/ (11101100)<br \/>\n        if (i &#038; 0x02) njThrow(NJ_UNSUPPORTED); \/\/ (00000010)<br \/>\n        i = (i | (i >> 3)) &#038; 3;  \/\/ combined DC\/AC + tableid value<br \/>\n\t\t\t\t\t\t\t\t \/\/ \u76f4\u6d410\uff0c\u76f4\u6d411\uff0c\u4ea4\u6d410\uff0c\u4ea4\u6d411<br \/>\n        for (codelen = 1;  codelen <= 16;  ++codelen) \/\/ \u7801\u5b57\u957f\u5ea6\n            counts[codelen - 1] = nj.pos[codelen]; \/\/ \u8bfb\u53d6\u7801\u5b57\n        njSkip(17);\n        vlc = &#038;nj.vlctab[i][0];\n        remain = spread = 65536;\n        for (codelen = 1;  codelen <= 16;  ++codelen) {\n            spread >>= 1; \/\/ \u5e72\u4ec0\u4e48\uff1f<br \/>\n            currcnt = counts[codelen &#8211; 1];<br \/>\n            if (!currcnt) continue; \/\/ \u5982\u679c\u8be5\u4f4d\u6570\u6ca1\u6709\u7801\u5b57<br \/>\n            if (nj.length < currcnt) njThrow(NJ_SYNTAX_ERROR);\n            remain -= currcnt << (16 - codelen);\n            if (remain < 0) njThrow(NJ_SYNTAX_ERROR);\n            for (i = 0;  i < currcnt;  ++i) { \/\/ \u7801\u5b57\u4e2a\u6570\uff0c\u540c\u6837\u4f4d\u6570\u7684\u7801\u5b57\u53ef\u4ee5\u6709\u591a\u4e2a\n                register unsigned char code = nj.pos[i];\n                for (j = spread;  j;  --j) { \/\/ \u4fdd\u5b58\u8fd9\u4e48\u591a\u4e2a\u6709\u4ec0\u4e48\u4f5c\u7528\uff1f\n                    vlc->bits = (unsigned char) codelen; \/\/ \u7801\u5b57\u4f4d\u6570<br \/>\n                    vlc->code = code; \/\/ \u7801\u5b57\u503c<br \/>\n                    ++vlc;<br \/>\n                }<br \/>\n            }<br \/>\n            njSkip(currcnt);<br \/>\n        }<br \/>\n        while (remain&#8211;) {<br \/>\n            vlc->bits = 0;<br \/>\n            ++vlc;<br \/>\n        }<br \/>\n    }<br \/>\n    if (nj.length) njThrow(NJ_SYNTAX_ERROR);<br \/>\n}<\/p>\n<p>NJ_INLINE void njDecodeDQT(void) {<br \/>\n    int i;<br \/>\n    unsigned char *t;<br \/>\n    njDecodeLength();<br \/>\n    while (nj.length >= 65) {<br \/>\n        i = nj.pos[0]; \/\/ QT\u4fe1\u606f\uff0c\u9ad84\u4f4d\u4e3aQT\u7cbe\u5ea6\uff0c\u4f4e4\u4f4d\u4e3aQT\u53f7<br \/>\n        if (i &#038; 0xFC) njThrow(NJ_SYNTAX_ERROR); \/\/ (1111 1110)\u8fd9\u4e2a\u7528\u6765\u68c0\u6d4bQT\u53f7\u7801\u662f\u5426\u6b63\u786e\u7684\u5417\uff1f\u76ee\u524d\u7cbe\u5ea6\u597d\u50cf\u90fd\u4e3a0\uff0c\u6240\u4ee5\u8fd9\u4e48\u5199\uff1f<br \/>\n        nj.qtavail |= 1 << i; \/\/ XXX \u76f4\u63a5\u901a\u8fc7\u8fd9\u91cc\u8f6c\u6362\u4e3a\u6570\u91cf\uff1f\n        t = &#038;nj.qtab[i][0];\n        for (i = 0;  i < 64;  ++i)\n            t[i] = nj.pos[i + 1]; \/\/ \u8bfb\u53d6\u5230QT\u6570\u7ec4\u5f53\u4e2d\uff0c\u4f46\u5e94\u8be5\u8fd8\u662f\u6309\u7167\u6587\u4ef6\u6d41\u5f53\u4e2d\u7684\u6392\u5217\n        njSkip(65);\n    }\n    if (nj.length) njThrow(NJ_SYNTAX_ERROR);\n}\n\nNJ_INLINE void njDecodeDRI(void) {\n    njDecodeLength();\n    if (nj.length < 2) njThrow(NJ_SYNTAX_ERROR);\n    nj.rstinterval = njDecode16(nj.pos);\n    njSkip(nj.length);\n}\n\nstatic int njGetVLC(nj_vlc_code_t* vlc, unsigned char* code) { \/\/ Variable Length Coding\n    int value = njShowBits(16);\n    int bits = vlc[value].bits;\n    if (!bits) { nj.error = NJ_SYNTAX_ERROR; return 0; }\n    njSkipBits(bits);\n    value = vlc[value].code;\n    if (code) *code = (unsigned char) value;\n    bits = value &#038; 15;\n    if (!bits) return 0;\n    value = njGetBits(bits);\n    if (value < (1 << (bits - 1)))\n        value += ((-1) << bits) + 1;\n    return value;\n}\n\nNJ_INLINE void njDecodeBlock(nj_component_t* c, unsigned char* out) {\n    unsigned char code = 0;\n    int value, coef = 0;\n    njFillMem(nj.block, 0, sizeof(nj.block));\n    c->dcpred += njGetVLC(&#038;nj.vlctab[c->dctabsel][0], NULL); \/\/ DC 0\/1 \u4e0d\u4f1a\u548cAC\u91cd\u590d<br \/>\n    nj.block[0] = (c->dcpred) * nj.qtab[c->qtsel][0]; \/\/ DC \/\/ \u8fd9\u91cc\u662f\u53cd\u91cf\u5316\uff1f<br \/>\n    do {<br \/>\n        value = njGetVLC(&#038;nj.vlctab[c->actabsel][0], &#038;code); \/\/ DC 2\/3<br \/>\n        if (!code) break;  \/\/ EOB<br \/>\n        if (!(code &#038; 0x0F) &#038;&#038; (code != 0xF0)) njThrow(NJ_SYNTAX_ERROR);<br \/>\n        coef += (code >> 4) + 1; \/\/ coefficient \u7cfb\u6570<br \/>\n        if (coef > 63) njThrow(NJ_SYNTAX_ERROR);<br \/>\n        nj.block[(int) njZZ[coef]] = value * nj.qtab[c->qtsel][coef]; \/\/ AC \u8fd9\u91cc\u662f\u53cd\u91cf\u5316\uff1f<br \/>\n    } while (coef < 63);\n    for (coef = 0;  coef < 64;  coef += 8)\n        njRowIDCT(&#038;nj.block[coef]); \/\/ \u4e0a\u9762\u5148Huffman\u89e3\u7801\/\u53cd\u91cf\u5316\uff0c\u8fd9\u91cc\u884c(\u53cdDCT)\n    for (coef = 0;  coef < 8;  ++coef)\n        njColIDCT(&#038;nj.block[coef], &#038;out[coef], c->stride);<br \/>\n}<\/p>\n<p>NJ_INLINE void njDecodeScan(void) {<br \/>\n    int i, mbx, mby, sbx, sby;<br \/>\n    int rstcount = nj.rstinterval, nextrst = 0;<br \/>\n    nj_component_t* c;<br \/>\n    njDecodeLength();<br \/>\n    if (nj.length < (4 + 2 * nj.ncomp)) njThrow(NJ_SYNTAX_ERROR);\n    if (nj.pos[0] != nj.ncomp) njThrow(NJ_UNSUPPORTED);\n    njSkip(1); \/\/ \u989c\u8272\u5206\u91cf\u6570\u91cf\n    for (i = 0, c = nj.comp;  i < nj.ncomp;  ++i, ++c) {\n        if (nj.pos[0] != c->cid) njThrow(NJ_SYNTAX_ERROR); \/\/ \u989c\u8272\u5206\u91cfID<br \/>\n        if (nj.pos[1] &#038; 0xEE) njThrow(NJ_SYNTAX_ERROR);<br \/>\n        c->dctabsel = nj.pos[1] >> 4; \/\/ \u9ad84\u4f4d\u4e3a\u76f4\u6d41\u8868DC Table<br \/>\n        c->actabsel = (nj.pos[1] &#038; 1) | 2; \/\/ \u4f4e4\u4f4d\u4e3a\u4ea4\u6d41\u8868AC Table(\u8fd9\u91cc\u6709\u505a\u7279\u6b8a\u5904\u7406\uff0c\u6240\u4ee5AC\u7684\u8868\u540d\u4e0d\u4f1a\u548cDC\u76f8\u540c)<\/p>\n<p>\t\tprintf(&#8220;DC\/AC Huffman table ids: %d\/%d\\n&#8221;, c->dctabsel, c->actabsel);\t<\/p>\n<p>        njSkip(2);<br \/>\n    }<br \/>\n    if (nj.pos[0] || (nj.pos[1] != 63) || nj.pos[2]) njThrow(NJ_UNSUPPORTED);<br \/>\n    njSkip(nj.length); \/\/ \u5ffd\u75653\u4e2a\u5b57\u8282 \u901a\u5e38\u4e3a 00 3F 00<br \/>\n\t\t\t\t\t   \/\/ 2 + 1 + 6 + 3\u4e3a12\u5b57\u8282\uff0c\u8fd9\u4e2amarker\u7684\u957f\u5ea6\u521a\u597d\u4e3a12\u5b57\u8282<br \/>\n\t\t\t\t\t   \/\/ \u63a5\u4e0b\u6765\u90fd\u662f\u7f16\u7801\u8fc7\u7684\u56fe\u50cf\u6570\u636e<br \/>\n    for (mbx = mby = 0;;) {<br \/>\n        for (i = 0, c = nj.comp;  i < nj.ncomp;  ++i, ++c) \/\/ \u6bcf\u4e2a\u5206\u91cf\u90fd\u8981decode\n            for (sby = 0;  sby < c->ssy;  ++sby) \/\/ \u6c34\u5e73\/\u5782\u76f4\u56e0\u5b50<br \/>\n                for (sbx = 0;  sbx < c->ssx;  ++sbx) {<br \/>\n                    njDecodeBlock(c, &#038;c->pixels[((mby * c->ssy + sby) * c->stride + mbx * c->ssx + sbx) << 3]); \/\/ \u8bfb\u53d6\u539f\u59cb\u7f16\u7801\u8fc7\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ \u7684\u56fe\u7247\u6570\u636e\u5230block\u4e2d\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ \u5e76\u53cd\u91cf\u5316\uff0c\u53cd\u79bb\u6563\u4f59\u5f26\u53d8\u6362\n                    njCheckError();\n                }\n        if (++mbx >= nj.mbwidth) { \/\/ \u8bfb\u5b8c\u6240\u6709\u7684MCU\uff0c\u5230\u8fbe\u6700\u53f3\u5c31\u8fd4\u56de\u4ece\u4e0b\u4e00\u884c\u5f00\u59cb<br \/>\n            mbx = 0;<br \/>\n            if (++mby >= nj.mbheight) break; \/\/ \u5230\u8fbe\u6700\u5e95\u884c\u7684\u65f6\u5019\u63a8\u51fa\uff0cdecode\u7ed3\u675f<br \/>\n        }<br \/>\n        if (nj.rstinterval &#038;&#038; !(&#8211;rstcount)) { \/\/ restart marker<br \/>\n            njByteAlign();<br \/>\n            i = njGetBits(16);<br \/>\n            if (((i &#038; 0xFFF8) != 0xFFD0) || ((i &#038; 7) != nextrst)) njThrow(NJ_SYNTAX_ERROR);<br \/>\n            nextrst = (nextrst + 1) &#038; 7;<br \/>\n            rstcount = nj.rstinterval;<br \/>\n            for (i = 0;  i < 3;  ++i)\n                nj.comp[i].dcpred = 0;\n        }\n    }\n    nj.error = __NJ_FINISHED;\n}\n\n#if NJ_CHROMA_FILTER\n\n#define CF4A (-9)\n#define CF4B (111)\n#define CF4C (29)\n#define CF4D (-3)\n#define CF3A (28)\n#define CF3B (109)\n#define CF3C (-9)\n#define CF3X (104)\n#define CF3Y (27)\n#define CF3Z (-3)\n#define CF2A (139)\n#define CF2B (-11)\n#define CF(x) njClip(((x) + 64) >> 7)<\/p>\n<p>\/\/ \u901a\u5e38\u6211\u4eec\u653e\u5927\u56fe\u7247\u7684\u65f6\u5019\u5c31\u9700\u8981upsampling\uff0c\u7f29\u5c0f\u7684\u65f6\u5019\u5c31downsampling\uff0c\u901a\u79f0\u4e3aresampling<br \/>\n\/\/ \u8fd9\u91ccCb\/Cr\u5206\u91cf\u7684\u4f1a\u5c11\u4e9b\uff0c\u6240\u4ee5\u9700\u8981upsampling<\/p>\n<p>NJ_INLINE void njUpsampleH(nj_component_t* c) {<br \/>\n\tprintf(&#8220;njUpsampleH %d\\n&#8221;, c->cid);<br \/>\n    const int xmax = c->width &#8211; 3;<br \/>\n    unsigned char *out, *lin, *lout;<br \/>\n    int x, y;<br \/>\n    out = njAllocMem((c->width * c->height) << 1);\n    if (!out) njThrow(NJ_OUT_OF_MEM);\n    lin = c->pixels;<br \/>\n    lout = out;<br \/>\n    for (y = c->height;  y;  &#8211;y) {<br \/>\n        lout[0] = CF(CF2A * lin[0] + CF2B * lin[1]);<br \/>\n        lout[1] = CF(CF3X * lin[0] + CF3Y * lin[1] + CF3Z * lin[2]);<br \/>\n        lout[2] = CF(CF3A * lin[0] + CF3B * lin[1] + CF3C * lin[2]);<br \/>\n        for (x = 0;  x < xmax;  ++x) {\n            lout[(x << 1) + 3] = CF(CF4A * lin[x] + CF4B * lin[x + 1] + CF4C * lin[x + 2] + CF4D * lin[x + 3]);\n            lout[(x << 1) + 4] = CF(CF4D * lin[x] + CF4C * lin[x + 1] + CF4B * lin[x + 2] + CF4A * lin[x + 3]);\n        }\n        lin += c->stride;<br \/>\n        lout += c->width << 1;\n        lout[-3] = CF(CF3A * lin[-1] + CF3B * lin[-2] + CF3C * lin[-3]);\n        lout[-2] = CF(CF3X * lin[-1] + CF3Y * lin[-2] + CF3Z * lin[-3]);\n        lout[-1] = CF(CF2A * lin[-1] + CF2B * lin[-2]);\n    }\n    c->width <<= 1;\n    c->stride = c->width;<br \/>\n    njFreeMem(c->pixels);<br \/>\n    c->pixels = out;<br \/>\n}<\/p>\n<p>NJ_INLINE void njUpsampleV(nj_component_t* c) {<br \/>\n\tprintf(&#8220;njUpsampleV %d\\n&#8221;, c->cid);<br \/>\n    const int w = c->width, s1 = c->stride, s2 = s1 + s1;<br \/>\n    unsigned char *out, *cin, *cout;<br \/>\n    int x, y;<br \/>\n    out = njAllocMem((c->width * c->height) << 1);\n    if (!out) njThrow(NJ_OUT_OF_MEM);\n    for (x = 0;  x < w;  ++x) {\n        cin = &#038;c->pixels[x];<br \/>\n        cout = &#038;out[x];<br \/>\n        *cout = CF(CF2A * cin[0] + CF2B * cin[s1]);  cout += w;<br \/>\n        *cout = CF(CF3X * cin[0] + CF3Y * cin[s1] + CF3Z * cin[s2]);  cout += w;<br \/>\n        *cout = CF(CF3A * cin[0] + CF3B * cin[s1] + CF3C * cin[s2]);  cout += w;<br \/>\n        cin += s1;<br \/>\n        for (y = c->height &#8211; 3;  y;  &#8211;y) {<br \/>\n            *cout = CF(CF4A * cin[-s1] + CF4B * cin[0] + CF4C * cin[s1] + CF4D * cin[s2]);  cout += w;<br \/>\n            *cout = CF(CF4D * cin[-s1] + CF4C * cin[0] + CF4B * cin[s1] + CF4A * cin[s2]);  cout += w;<br \/>\n            cin += s1;<br \/>\n        }<br \/>\n        cin += s1;<br \/>\n        *cout = CF(CF3A * cin[0] + CF3B * cin[-s1] + CF3C * cin[-s2]);  cout += w;<br \/>\n        *cout = CF(CF3X * cin[0] + CF3Y * cin[-s1] + CF3Z * cin[-s2]);  cout += w;<br \/>\n        *cout = CF(CF2A * cin[0] + CF2B * cin[-s1]);<br \/>\n    }<br \/>\n    c->height <<= 1;\n    c->stride = c->width;<br \/>\n    njFreeMem(c->pixels);<br \/>\n    c->pixels = out;<br \/>\n}<\/p>\n<p>#else<\/p>\n<p>NJ_INLINE void njUpsample(nj_component_t* c) {<br \/>\n\tprintf(&#8220;njUpsample %d\\n&#8221;, c->cid);<br \/>\n    int x, y, xshift = 0, yshift = 0;<br \/>\n    unsigned char *out, *lin, *lout;<br \/>\n    while (c->width < nj.width) { c->width <<= 1; ++xshift; }\n    while (c->height < nj.height) { c->height <<= 1; ++yshift; }\n    out = njAllocMem(c->width * c->height); \/\/ \u653e\u5927\u540e\u7684\u5c3a\u5bf8<br \/>\n    if (!out) njThrow(NJ_OUT_OF_MEM);<br \/>\n    lin = c->pixels;<br \/>\n    lout = out;<br \/>\n    for (y = 0;  y < c->height;  ++y) {<br \/>\n        lin = &#038;c->pixels[(y >> yshift) * c->stride];<br \/>\n        for (x = 0;  x < c->width;  ++x)<br \/>\n            lout[x] = lin[x >> xshift];<br \/>\n        lout += c->width;<br \/>\n    }<br \/>\n    c->stride = c->width;<br \/>\n    njFreeMem(c->pixels);<br \/>\n    c->pixels = out;<br \/>\n}<\/p>\n<p>#endif<\/p>\n<p>NJ_INLINE void njConvert() {<br \/>\n    int i;<br \/>\n    nj_component_t* c;<br \/>\n    for (i = 0, c = nj.comp;  i < nj.ncomp;  ++i, ++c) { \/\/ \u5982\u679c\u9700\u8981\u7684\u8bdd\u5c31upsampling\n        #if NJ_CHROMA_FILTER\n            while ((c->width < nj.width) || (c->height < nj.height)) {\n                if (c->width < nj.width) njUpsampleH(c);\n                njCheckError();\n                if (c->height < nj.height) njUpsampleV(c);\n                njCheckError();\n            }\n        #else\n            if ((c->width < nj.width) || (c->height < nj.height))\n                njUpsample(c);\n        #endif\n        if ((c->width < nj.width) || (c->height < nj.height)) njThrow(NJ_INTERNAL_ERR);\n    }\n    if (nj.ncomp == 3) { \/\/ SEE njGetImage()\n        \/\/ convert to RGB\n        int x, yy;\n        unsigned char *prgb = nj.rgb;\n        const unsigned char *py  = nj.comp[0].pixels;\n        const unsigned char *pcb = nj.comp[1].pixels;\n        const unsigned char *pcr = nj.comp[2].pixels;\n\t\t\/\/ \u591a\u4f59\u7684\u6570\u636e(\u7f16\/\u89e3\u7801\u662f\u5bf9\u9f50\u7528\u7684)\u4f1a\u88ab\u4e22\u5f03\u5417\uff1f\n        for (yy = nj.height;  yy;  --yy) { \/\/ \u5217\n            for (x = 0;  x < nj.width;  ++x) { \/\/ \u884c\n                register int y = py[x] << 8; \/\/ \u8fd9\u662f\u4e3a\u4ec0\u4e48\uff1f \u8272\u5f69\u7a7a\u95f4\u8f6c\u6362\u516c\u5f0f\u8ba1\u7b97\u9700\u8981\n                register int cb = pcb[x] - 128; \/\/ YCbCr\u7684Cb\u548cCr\u4e00\u822c\u90fd\u662f\u6709\u7b26\u53f7\u6570\uff0c\u4f46\u662f\u5728JPEG\u5f53\u4e2d\u90fd\u662f\u65e0\u7b26\u53f7\u6570\n                register int cr = pcr[x] - 128;\n                *prgb++ = njClip((y            + 359 * cr + 128) >> 8); \/\/ \u8272\u5f69\u7a7a\u95f4\u8f6c\u6362\uff0cYCbCr\u5230RGB<br \/>\n                *prgb++ = njClip((y &#8211;  88 * cb &#8211; 183 * cr + 128) >> 8);<br \/>\n                *prgb++ = njClip((y + 454 * cb            + 128) >> 8);<br \/>\n            }<br \/>\n            py += nj.comp[0].stride; \/\/ \u79fb\u52a8YCbCr\u6570\u636e\u6307\u9488\uff0c\u6bcf\u4e00\u884c\u90fd\u662f\u6709stride\u7684\uff0c\u6240\u4ee5\u5f53\u9700\u8981\u7684\u6570\u636e\u90fd\u5f97\u5230\u65f6\uff0c\u540e\u9762\u7684\u5c31\u4e0d\u7ba1\uff0c\u76f4\u63a5\u4e22\u5f03\uff0c\u79fb\u52a8\u5230\u4e0b\u4e00\u884c<br \/>\n            pcb += nj.comp[1].stride;<br \/>\n            pcr += nj.comp[2].stride;<br \/>\n        }<br \/>\n    } else if (nj.comp[0].width != nj.comp[0].stride) { \/\/ \u5982\u679c\u5bbd\u5ea6\u548cstride\u90fd\u4e00\u6837\uff0c\u4ec0\u4e48\u90fd\u4e0d\u7528\u505a<br \/>\n        \/\/ grayscale -> only remove stride<br \/>\n        unsigned char *pin = &#038;nj.comp[0].pixels[nj.comp[0].stride];<br \/>\n        unsigned char *pout = &#038;nj.comp[0].pixels[nj.comp[0].width];<br \/>\n        int y;<br \/>\n        for (y = nj.comp[0].height &#8211; 1;  y;  &#8211;y) {<br \/>\n            njCopyMem(pout, pin, nj.comp[0].width);<br \/>\n            pin += nj.comp[0].stride;<br \/>\n            pout += nj.comp[0].width;<br \/>\n        }<br \/>\n        nj.comp[0].stride = nj.comp[0].width;<br \/>\n    }<br \/>\n}<\/p>\n<p>void njInit(void) {<br \/>\n    njFillMem(&#038;nj, 0, sizeof(nj_context_t)); \/\/ \u521d\u59cb\u5316nj_context_t<br \/>\n}<\/p>\n<p>void njDone(void) {<br \/>\n    int i;<br \/>\n    for (i = 0;  i < 3;  ++i)\n        if (nj.comp[i].pixels) njFreeMem((void*) nj.comp[i].pixels);\n    if (nj.rgb) njFreeMem((void*) nj.rgb);\n    njInit();\n}\n\nnj_result_t njDecode(const void* jpeg, const int size) {\n    njDone();\n    nj.pos = (const unsigned char*) jpeg;\n    nj.size = size &#038; 0x7FFFFFFF; \/\/ \uff1f\n    if (nj.size < 2) return NJ_NO_JPEG;\n    if ((nj.pos[0] ^ 0xFF) | (nj.pos[1] ^ 0xD8)) return NJ_NO_JPEG; \/\/ \u4e0d\u4ee50xFFD8\u6253\u5934(\u4e3a\u4ec0\u4e48\u8981\u7528\u5f02\u6216\u6765\u5224\u65ad\uff1f)\n    njSkip(2);\n    while (!nj.error) { \/\/ \u6709\u201c\u9519\u8bef\u201d\u7684\u65f6\u5019\u79bb\u5f00\n        if ((nj.size < 2) || (nj.pos[0] != 0xFF)) return NJ_SYNTAX_ERROR; \/\/ \u592a\u5c0f\uff0c\u6216\u8005\u4e0d\u4ee50xFF\u6253\u5934\n        njSkip(2); \/\/ \u79fb\u52a8\u5230\u6807\u7b7e\u7684\u540e\u9762(\u957f\u5ea6\u5b57\u6bb5\u7684\u524d\u9762)\n        switch (nj.pos[-1]) {\n            case 0xC0: njDecodeSOF();  break;\n            case 0xC4: njDecodeDHT();  break;\n            case 0xDB: njDecodeDQT();  break;\n            case 0xDD: njDecodeDRI();  break;\n            case 0xDA: njDecodeScan(); break;\n            case 0xFE: njSkipMarker(); break;\n            default:\n                if ((nj.pos[-1] &#038; 0xF0) == 0xE0) \/\/ JPG0\u548cAPP0\u5b57\u6bb5\uff0c\u76ee\u524d\u90fd\u5ffd\u7565\n                    njSkipMarker();\n                else\n                    return NJ_UNSUPPORTED;\n        }\n    }\n    if (nj.error != __NJ_FINISHED) return nj.error;\n    nj.error = NJ_OK;\n    njConvert();\n    return nj.error;\n}\n\nint njGetWidth(void)            { return nj.width; }\nint njGetHeight(void)           { return nj.height; }\nint njIsColor(void)             { return (nj.ncomp != 1); }\nunsigned char* njGetImage(void) { return (nj.ncomp == 1) ? nj.comp[0].pixels : nj.rgb; } \/\/ \u4e00\/\u4e09\u4e2a\u5206\u91cf\nint njGetImageSize(void)        { return nj.width * nj.height * nj.ncomp; }\n\n#endif \/\/ _NJ_INCLUDE_HEADER_ONLY\n[\/code]\n<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u81ea\u5df1\u5b66\u4e60\u4e86\u4e0bJPEG\u7406\u8bba\u77e5\u8bc6\u4ee5\u540e\uff0c\u627e\u4e86\u4e2a\u7b80\u5355\u7684\u89e3\u7801\u5668(NanoJPEG)\u8bd5\u8bd5\u770b\uff0c\u539f\u59cb\u5730\u5740\u5728\u8fd9\u91cchttp:\/\/keyj.emphy.de\/nanojpeg\/\uff0c\u77ed\u77ed\u51e0\u767e\u884c\uff0c\u8fd8\u662f\u6bd4\u8f83\u5bb9\u6613\u770b\u61c2\u7684\uff0c\u672c\u4eba\u7406\u89e3\u8be6\u7ec6\u53c2\u89c1\u4ee3\u7801\u6ce8\u91ca\uff0c\u5982\u7406\u89e3\u6709\u8bef\u6b22\u8fce\u6307\u51fa\uff0c\u6709\u95ee\u9898\/\u5174\u8da3\u4e5f\u53ef\u4ee5\u7559\u8a00\u548c\u6211\u8ba8\u8bba\u3002 $ gcc -O3 -D_NJ_EXAMPLE_PROGRAM -o nanojpeg nanojpeg.c $ .\/nanojpeg testorig.jpg \u8ddf\u7740main\u51fd\u6570\uff0c\u8fb9\u7406\u8bba\u8fb9\u5b9e\u8df5\uff0c\u4e0d\u9519\u7684\u65b9\u6cd5\uff01 \/\/ NanoJPEG &#8212; KeyJ&#8217;s Tiny Baseline JPEG Decoder \/\/ version 1.3 (2012-03-05) \/\/ by Martin J. Fiedler \/\/ \/\/ This software is published under the terms of KeyJ&#8217;s Research License, \/\/ version 0.2. Usage of this software is subject to the following conditions: &hellip; <a href=\"https:\/\/guoh.ai\/lifelog\/2013\/09\/nanojpeg-a-compact-jpeg-decoder\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">NanoJPEG\uff0c\u4e00\u4e2a\u7b80\u5355\u7684JPEG\u89e3\u7801\u5668\u5206\u6790<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_gfmr_meta_descriptions":[],"_gfmr_multilingual_taxonomy_terms":[],"footnotes":""},"categories":[29,34],"tags":[],"class_list":["post-715","post","type-post","status-publish","format-standard","hentry","category-c","category-multimedia"],"_links":{"self":[{"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/posts\/715","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/comments?post=715"}],"version-history":[{"count":6,"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/posts\/715\/revisions"}],"predecessor-version":[{"id":722,"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/posts\/715\/revisions\/722"}],"wp:attachment":[{"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/media?parent=715"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/categories?post=715"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/tags?post=715"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}