1/*
2 * Copyright 2007 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8
9#include "SkImageDecoder.h"
10#include "SkImageEncoder.h"
11#include "SkJpegUtility.h"
12#include "SkColorPriv.h"
13#include "SkDither.h"
14#include "SkScaledBitmapSampler.h"
15#include "SkStream.h"
16#include "SkTemplates.h"
17#include "SkTime.h"
18#include "SkUtils.h"
19#include "SkRTConf.h"
20#include "SkRect.h"
21#include "SkCanvas.h"
22
23
24#include <stdio.h>
25extern "C" {
26    #include "jpeglib.h"
27    #include "jerror.h"
28}
29
30// These enable timing code that report milliseconds for an encoding/decoding
31//#define TIME_ENCODE
32//#define TIME_DECODE
33
34// this enables our rgb->yuv code, which is faster than libjpeg on ARM
35#define WE_CONVERT_TO_YUV
36
37// If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offers
38// support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565.
39
40#if defined(SK_DEBUG)
41#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS false
42#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS false
43#else  // !defined(SK_DEBUG)
44#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS true
45#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS true
46#endif  // defined(SK_DEBUG)
47SK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderWarnings,
48                "images.jpeg.suppressDecoderWarnings",
49                DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS,
50                "Suppress most JPG warnings when calling decode functions.");
51SK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderErrors,
52                "images.jpeg.suppressDecoderErrors",
53                DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS,
54                "Suppress most JPG error messages when decode "
55                "function fails.");
56
57//////////////////////////////////////////////////////////////////////////
58//////////////////////////////////////////////////////////////////////////
59
60static void overwrite_mem_buffer_size(jpeg_decompress_struct* cinfo) {
61#ifdef SK_BUILD_FOR_ANDROID
62    /* Check if the device indicates that it has a large amount of system memory
63     * if so, increase the memory allocation to 30MB instead of the default 5MB.
64     */
65#ifdef ANDROID_LARGE_MEMORY_DEVICE
66    cinfo->mem->max_memory_to_use = 30 * 1024 * 1024;
67#else
68    cinfo->mem->max_memory_to_use = 5 * 1024 * 1024;
69#endif
70#endif // SK_BUILD_FOR_ANDROID
71}
72
73//////////////////////////////////////////////////////////////////////////
74//////////////////////////////////////////////////////////////////////////
75
76static void do_nothing_emit_message(jpeg_common_struct*, int) {
77    /* do nothing */
78}
79static void do_nothing_output_message(j_common_ptr) {
80    /* do nothing */
81}
82
83static void initialize_info(jpeg_decompress_struct* cinfo, skjpeg_source_mgr* src_mgr) {
84    SkASSERT(cinfo != NULL);
85    SkASSERT(src_mgr != NULL);
86    jpeg_create_decompress(cinfo);
87    overwrite_mem_buffer_size(cinfo);
88    cinfo->src = src_mgr;
89    /* To suppress warnings with a SK_DEBUG binary, set the
90     * environment variable "skia_images_jpeg_suppressDecoderWarnings"
91     * to "true".  Inside a program that links to skia:
92     * SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true); */
93    if (c_suppressJPEGImageDecoderWarnings) {
94        cinfo->err->emit_message = &do_nothing_emit_message;
95    }
96    /* To suppress error messages with a SK_DEBUG binary, set the
97     * environment variable "skia_images_jpeg_suppressDecoderErrors"
98     * to "true".  Inside a program that links to skia:
99     * SK_CONF_SET("images.jpeg.suppressDecoderErrors", true); */
100    if (c_suppressJPEGImageDecoderErrors) {
101        cinfo->err->output_message = &do_nothing_output_message;
102    }
103}
104
105#ifdef SK_BUILD_FOR_ANDROID
106class SkJPEGImageIndex {
107public:
108    SkJPEGImageIndex(SkStreamRewindable* stream, SkImageDecoder* decoder)
109        : fSrcMgr(stream, decoder)
110        , fInfoInitialized(false)
111        , fHuffmanCreated(false)
112        , fDecompressStarted(false)
113        {
114            SkDEBUGCODE(fReadHeaderSucceeded = false;)
115        }
116
117    ~SkJPEGImageIndex() {
118        if (fHuffmanCreated) {
119            // Set to false before calling the libjpeg function, in case
120            // the libjpeg function calls longjmp. Our setjmp handler may
121            // attempt to delete this SkJPEGImageIndex, thus entering this
122            // destructor again. Setting fHuffmanCreated to false first
123            // prevents an infinite loop.
124            fHuffmanCreated = false;
125            jpeg_destroy_huffman_index(&fHuffmanIndex);
126        }
127        if (fDecompressStarted) {
128            // Like fHuffmanCreated, set to false before calling libjpeg
129            // function to prevent potential infinite loop.
130            fDecompressStarted = false;
131            jpeg_finish_decompress(&fCInfo);
132        }
133        if (fInfoInitialized) {
134            this->destroyInfo();
135        }
136    }
137
138    /**
139     *  Destroy the cinfo struct.
140     *  After this call, if a huffman index was already built, it
141     *  can be used after calling initializeInfoAndReadHeader
142     *  again. Must not be called after startTileDecompress except
143     *  in the destructor.
144     */
145    void destroyInfo() {
146        SkASSERT(fInfoInitialized);
147        SkASSERT(!fDecompressStarted);
148        // Like fHuffmanCreated, set to false before calling libjpeg
149        // function to prevent potential infinite loop.
150        fInfoInitialized = false;
151        jpeg_destroy_decompress(&fCInfo);
152        SkDEBUGCODE(fReadHeaderSucceeded = false;)
153    }
154
155    /**
156     *  Initialize the cinfo struct.
157     *  Calls jpeg_create_decompress, makes customizations, and
158     *  finally calls jpeg_read_header. Returns true if jpeg_read_header
159     *  returns JPEG_HEADER_OK.
160     *  If cinfo was already initialized, destroyInfo must be called to
161     *  destroy the old one. Must not be called after startTileDecompress.
162     */
163    bool initializeInfoAndReadHeader() {
164        SkASSERT(!fInfoInitialized && !fDecompressStarted);
165        initialize_info(&fCInfo, &fSrcMgr);
166        fInfoInitialized = true;
167        const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true));
168        SkDEBUGCODE(fReadHeaderSucceeded = success;)
169        return success;
170    }
171
172    jpeg_decompress_struct* cinfo() { return &fCInfo; }
173
174    huffman_index* huffmanIndex() { return &fHuffmanIndex; }
175
176    /**
177     *  Build the index to be used for tile based decoding.
178     *  Must only be called after a successful call to
179     *  initializeInfoAndReadHeader and must not be called more
180     *  than once.
181     */
182    bool buildHuffmanIndex() {
183        SkASSERT(fReadHeaderSucceeded);
184        SkASSERT(!fHuffmanCreated);
185        jpeg_create_huffman_index(&fCInfo, &fHuffmanIndex);
186        SkASSERT(1 == fCInfo.scale_num && 1 == fCInfo.scale_denom);
187        fHuffmanCreated = jpeg_build_huffman_index(&fCInfo, &fHuffmanIndex);
188        return fHuffmanCreated;
189    }
190
191    /**
192     *  Start tile based decoding. Must only be called after a
193     *  successful call to buildHuffmanIndex, and must only be
194     *  called once.
195     */
196    bool startTileDecompress() {
197        SkASSERT(fHuffmanCreated);
198        SkASSERT(fReadHeaderSucceeded);
199        SkASSERT(!fDecompressStarted);
200        if (jpeg_start_tile_decompress(&fCInfo)) {
201            fDecompressStarted = true;
202            return true;
203        }
204        return false;
205    }
206
207private:
208    skjpeg_source_mgr  fSrcMgr;
209    jpeg_decompress_struct fCInfo;
210    huffman_index fHuffmanIndex;
211    bool fInfoInitialized;
212    bool fHuffmanCreated;
213    bool fDecompressStarted;
214    SkDEBUGCODE(bool fReadHeaderSucceeded;)
215};
216#endif
217
218class SkJPEGImageDecoder : public SkImageDecoder {
219public:
220#ifdef SK_BUILD_FOR_ANDROID
221    SkJPEGImageDecoder() {
222        fImageIndex = NULL;
223        fImageWidth = 0;
224        fImageHeight = 0;
225    }
226
227    virtual ~SkJPEGImageDecoder() {
228        SkDELETE(fImageIndex);
229    }
230#endif
231
232    virtual Format getFormat() const {
233        return kJPEG_Format;
234    }
235
236protected:
237#ifdef SK_BUILD_FOR_ANDROID
238    virtual bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) SK_OVERRIDE;
239    virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE;
240#endif
241    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
242
243private:
244#ifdef SK_BUILD_FOR_ANDROID
245    SkJPEGImageIndex* fImageIndex;
246    int fImageWidth;
247    int fImageHeight;
248#endif
249
250    /**
251     *  Determine the appropriate bitmap colortype and out_color_space based on
252     *  both the preference of the caller and the jpeg_color_space on the
253     *  jpeg_decompress_struct passed in.
254     *  Must be called after jpeg_read_header.
255     */
256    SkColorType getBitmapColorType(jpeg_decompress_struct*);
257
258    typedef SkImageDecoder INHERITED;
259};
260
261//////////////////////////////////////////////////////////////////////////
262
263/* Automatically clean up after throwing an exception */
264class JPEGAutoClean {
265public:
266    JPEGAutoClean(): cinfo_ptr(NULL) {}
267    ~JPEGAutoClean() {
268        if (cinfo_ptr) {
269            jpeg_destroy_decompress(cinfo_ptr);
270        }
271    }
272    void set(jpeg_decompress_struct* info) {
273        cinfo_ptr = info;
274    }
275private:
276    jpeg_decompress_struct* cinfo_ptr;
277};
278
279///////////////////////////////////////////////////////////////////////////////
280
281/*  If we need to better match the request, we might examine the image and
282     output dimensions, and determine if the downsampling jpeg provided is
283     not sufficient. If so, we can recompute a modified sampleSize value to
284     make up the difference.
285
286     To skip this additional scaling, just set sampleSize = 1; below.
287 */
288static int recompute_sampleSize(int sampleSize,
289                                const jpeg_decompress_struct& cinfo) {
290    return sampleSize * cinfo.output_width / cinfo.image_width;
291}
292
293static bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) {
294    /* These are initialized to 0, so if they have non-zero values, we assume
295       they are "valid" (i.e. have been computed by libjpeg)
296     */
297    return 0 != cinfo.output_width && 0 != cinfo.output_height;
298}
299
300static bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, int count) {
301    for (int i = 0; i < count; i++) {
302        JSAMPLE* rowptr = (JSAMPLE*)buffer;
303        int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1);
304        if (1 != row_count) {
305            return false;
306        }
307    }
308    return true;
309}
310
311#ifdef SK_BUILD_FOR_ANDROID
312static bool skip_src_rows_tile(jpeg_decompress_struct* cinfo,
313                               huffman_index *index, void* buffer, int count) {
314    for (int i = 0; i < count; i++) {
315        JSAMPLE* rowptr = (JSAMPLE*)buffer;
316        int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr);
317        if (1 != row_count) {
318            return false;
319        }
320    }
321    return true;
322}
323#endif
324
325// This guy exists just to aid in debugging, as it allows debuggers to just
326// set a break-point in one place to see all error exists.
327static bool return_false(const jpeg_decompress_struct& cinfo,
328                         const SkBitmap& bm, const char caller[]) {
329    if (!(c_suppressJPEGImageDecoderErrors)) {
330        char buffer[JMSG_LENGTH_MAX];
331        cinfo.err->format_message((const j_common_ptr)&cinfo, buffer);
332        SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n",
333                 cinfo.err->msg_code, buffer, caller, bm.width(), bm.height());
334    }
335    return false;   // must always return false
336}
337
338// Convert a scanline of CMYK samples to RGBX in place. Note that this
339// method moves the "scanline" pointer in its processing
340static void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) {
341    // At this point we've received CMYK pixels from libjpeg. We
342    // perform a crude conversion to RGB (based on the formulae
343    // from easyrgb.com):
344    //  CMYK -> CMY
345    //    C = ( C * (1 - K) + K )      // for each CMY component
346    //  CMY -> RGB
347    //    R = ( 1 - C ) * 255          // for each RGB component
348    // Unfortunately we are seeing inverted CMYK so all the original terms
349    // are 1-. This yields:
350    //  CMYK -> CMY
351    //    C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K
352    // The conversion from CMY->RGB remains the same
353    for (unsigned int x = 0; x < width; ++x, scanline += 4) {
354        scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]);
355        scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]);
356        scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]);
357        scanline[3] = 255;
358    }
359}
360
361/**
362 *  Common code for setting the error manager.
363 */
364static void set_error_mgr(jpeg_decompress_struct* cinfo, skjpeg_error_mgr* errorManager) {
365    SkASSERT(cinfo != NULL);
366    SkASSERT(errorManager != NULL);
367    cinfo->err = jpeg_std_error(errorManager);
368    errorManager->error_exit = skjpeg_error_exit;
369}
370
371/**
372 *  Common code for turning off upsampling and smoothing. Turning these
373 *  off helps performance without showing noticable differences in the
374 *  resulting bitmap.
375 */
376static void turn_off_visual_optimizations(jpeg_decompress_struct* cinfo) {
377    SkASSERT(cinfo != NULL);
378    /* this gives about 30% performance improvement. In theory it may
379       reduce the visual quality, in practice I'm not seeing a difference
380     */
381    cinfo->do_fancy_upsampling = 0;
382
383    /* this gives another few percents */
384    cinfo->do_block_smoothing = 0;
385}
386
387/**
388 * Common code for setting the dct method.
389 */
390static void set_dct_method(const SkImageDecoder& decoder, jpeg_decompress_struct* cinfo) {
391    SkASSERT(cinfo != NULL);
392#ifdef DCT_IFAST_SUPPORTED
393    if (decoder.getPreferQualityOverSpeed()) {
394        cinfo->dct_method = JDCT_ISLOW;
395    } else {
396        cinfo->dct_method = JDCT_IFAST;
397    }
398#else
399    cinfo->dct_method = JDCT_ISLOW;
400#endif
401}
402
403SkColorType SkJPEGImageDecoder::getBitmapColorType(jpeg_decompress_struct* cinfo) {
404    SkASSERT(cinfo != NULL);
405
406    SrcDepth srcDepth = k32Bit_SrcDepth;
407    if (JCS_GRAYSCALE == cinfo->jpeg_color_space) {
408        srcDepth = k8BitGray_SrcDepth;
409    }
410
411    SkColorType colorType = this->getPrefColorType(srcDepth, /*hasAlpha*/ false);
412    switch (colorType) {
413        case kAlpha_8_SkColorType:
414            // Only respect A8 colortype if the original is grayscale,
415            // in which case we will treat the grayscale as alpha
416            // values.
417            if (cinfo->jpeg_color_space != JCS_GRAYSCALE) {
418                colorType = kN32_SkColorType;
419            }
420            break;
421        case kN32_SkColorType:
422            // Fall through.
423        case kARGB_4444_SkColorType:
424            // Fall through.
425        case kRGB_565_SkColorType:
426            // These are acceptable destination colortypes.
427            break;
428        default:
429            // Force all other colortypes to 8888.
430            colorType = kN32_SkColorType;
431            break;
432    }
433
434    switch (cinfo->jpeg_color_space) {
435        case JCS_CMYK:
436            // Fall through.
437        case JCS_YCCK:
438            // libjpeg cannot convert from CMYK or YCCK to RGB - here we set up
439            // so libjpeg will give us CMYK samples back and we will later
440            // manually convert them to RGB
441            cinfo->out_color_space = JCS_CMYK;
442            break;
443        case JCS_GRAYSCALE:
444            if (kAlpha_8_SkColorType == colorType) {
445                cinfo->out_color_space = JCS_GRAYSCALE;
446                break;
447            }
448            // The data is JCS_GRAYSCALE, but the caller wants some sort of RGB
449            // colortype. Fall through to set to the default.
450        default:
451            cinfo->out_color_space = JCS_RGB;
452            break;
453    }
454    return colorType;
455}
456
457/**
458 *  Based on the colortype and dither mode, adjust out_color_space and
459 *  dither_mode of cinfo. Only does work in ANDROID_RGB
460 */
461static void adjust_out_color_space_and_dither(jpeg_decompress_struct* cinfo,
462                                              SkColorType colorType,
463                                              const SkImageDecoder& decoder) {
464    SkASSERT(cinfo != NULL);
465#ifdef ANDROID_RGB
466    cinfo->dither_mode = JDITHER_NONE;
467    if (JCS_CMYK == cinfo->out_color_space) {
468        return;
469    }
470    switch (colorType) {
471        case kN32_SkColorType:
472            cinfo->out_color_space = JCS_RGBA_8888;
473            break;
474        case kRGB_565_SkColorType:
475            cinfo->out_color_space = JCS_RGB_565;
476            if (decoder.getDitherImage()) {
477                cinfo->dither_mode = JDITHER_ORDERED;
478            }
479            break;
480        default:
481            break;
482    }
483#endif
484}
485
486
487/**
488   Sets all pixels in given bitmap to SK_ColorWHITE for all rows >= y.
489   Used when decoding fails partway through reading scanlines to fill
490   remaining lines. */
491static void fill_below_level(int y, SkBitmap* bitmap) {
492    SkIRect rect = SkIRect::MakeLTRB(0, y, bitmap->width(), bitmap->height());
493    SkCanvas canvas(*bitmap);
494    canvas.clipRect(SkRect::Make(rect));
495    canvas.drawColor(SK_ColorWHITE);
496}
497
498/**
499 *  Get the config and bytes per pixel of the source data. Return
500 *  whether the data is supported.
501 */
502static bool get_src_config(const jpeg_decompress_struct& cinfo,
503                           SkScaledBitmapSampler::SrcConfig* sc,
504                           int* srcBytesPerPixel) {
505    SkASSERT(sc != NULL && srcBytesPerPixel != NULL);
506    if (JCS_CMYK == cinfo.out_color_space) {
507        // In this case we will manually convert the CMYK values to RGB
508        *sc = SkScaledBitmapSampler::kRGBX;
509        // The CMYK work-around relies on 4 components per pixel here
510        *srcBytesPerPixel = 4;
511    } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) {
512        *sc = SkScaledBitmapSampler::kRGB;
513        *srcBytesPerPixel = 3;
514#ifdef ANDROID_RGB
515    } else if (JCS_RGBA_8888 == cinfo.out_color_space) {
516        *sc = SkScaledBitmapSampler::kRGBX;
517        *srcBytesPerPixel = 4;
518    } else if (JCS_RGB_565 == cinfo.out_color_space) {
519        *sc = SkScaledBitmapSampler::kRGB_565;
520        *srcBytesPerPixel = 2;
521#endif
522    } else if (1 == cinfo.out_color_components &&
523               JCS_GRAYSCALE == cinfo.out_color_space) {
524        *sc = SkScaledBitmapSampler::kGray;
525        *srcBytesPerPixel = 1;
526    } else {
527        return false;
528    }
529    return true;
530}
531
532bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
533#ifdef TIME_DECODE
534    SkAutoTime atm("JPEG Decode");
535#endif
536
537    JPEGAutoClean autoClean;
538
539    jpeg_decompress_struct  cinfo;
540    skjpeg_source_mgr       srcManager(stream, this);
541
542    skjpeg_error_mgr errorManager;
543    set_error_mgr(&cinfo, &errorManager);
544
545    // All objects need to be instantiated before this setjmp call so that
546    // they will be cleaned up properly if an error occurs.
547    if (setjmp(errorManager.fJmpBuf)) {
548        return return_false(cinfo, *bm, "setjmp");
549    }
550
551    initialize_info(&cinfo, &srcManager);
552    autoClean.set(&cinfo);
553
554    int status = jpeg_read_header(&cinfo, true);
555    if (status != JPEG_HEADER_OK) {
556        return return_false(cinfo, *bm, "read_header");
557    }
558
559    /*  Try to fulfill the requested sampleSize. Since jpeg can do it (when it
560        can) much faster that we, just use their num/denom api to approximate
561        the size.
562    */
563    int sampleSize = this->getSampleSize();
564
565    set_dct_method(*this, &cinfo);
566
567    SkASSERT(1 == cinfo.scale_num);
568    cinfo.scale_denom = sampleSize;
569
570    turn_off_visual_optimizations(&cinfo);
571
572    const SkColorType colorType = this->getBitmapColorType(&cinfo);
573    const SkAlphaType alphaType = kAlpha_8_SkColorType == colorType ?
574                                      kPremul_SkAlphaType : kOpaque_SkAlphaType;
575
576    adjust_out_color_space_and_dither(&cinfo, colorType, *this);
577
578    if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) {
579        // Assume an A8 bitmap is not opaque to avoid the check of each
580        // individual pixel. It is very unlikely to be opaque, since
581        // an opaque A8 bitmap would not be very interesting.
582        // Otherwise, a jpeg image is opaque.
583        return bm->setInfo(SkImageInfo::Make(cinfo.image_width, cinfo.image_height,
584                                             colorType, alphaType));
585    }
586
587    /*  image_width and image_height are the original dimensions, available
588        after jpeg_read_header(). To see the scaled dimensions, we have to call
589        jpeg_start_decompress(), and then read output_width and output_height.
590    */
591    if (!jpeg_start_decompress(&cinfo)) {
592        /*  If we failed here, we may still have enough information to return
593            to the caller if they just wanted (subsampled bounds). If sampleSize
594            was 1, then we would have already returned. Thus we just check if
595            we're in kDecodeBounds_Mode, and that we have valid output sizes.
596
597            One reason to fail here is that we have insufficient stream data
598            to complete the setup. However, output dimensions seem to get
599            computed very early, which is why this special check can pay off.
600         */
601        if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) {
602            SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height,
603                                       recompute_sampleSize(sampleSize, cinfo));
604            // Assume an A8 bitmap is not opaque to avoid the check of each
605            // individual pixel. It is very unlikely to be opaque, since
606            // an opaque A8 bitmap would not be very interesting.
607            // Otherwise, a jpeg image is opaque.
608            return bm->setInfo(SkImageInfo::Make(smpl.scaledWidth(), smpl.scaledHeight(),
609                                                 colorType, alphaType));
610        } else {
611            return return_false(cinfo, *bm, "start_decompress");
612        }
613    }
614    sampleSize = recompute_sampleSize(sampleSize, cinfo);
615
616#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
617    // should we allow the Chooser (if present) to pick a colortype for us???
618    if (!this->chooseFromOneChoice(colorType, cinfo.output_width, cinfo.output_height)) {
619        return return_false(cinfo, *bm, "chooseFromOneChoice");
620    }
621#endif
622
623    SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampleSize);
624    // Assume an A8 bitmap is not opaque to avoid the check of each
625    // individual pixel. It is very unlikely to be opaque, since
626    // an opaque A8 bitmap would not be very interesting.
627    // Otherwise, a jpeg image is opaque.
628    bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(),
629                                  colorType, alphaType));
630    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
631        return true;
632    }
633    if (!this->allocPixelRef(bm, NULL)) {
634        return return_false(cinfo, *bm, "allocPixelRef");
635    }
636
637    SkAutoLockPixels alp(*bm);
638
639#ifdef ANDROID_RGB
640    /* short-circuit the SkScaledBitmapSampler when possible, as this gives
641       a significant performance boost.
642    */
643    if (sampleSize == 1 &&
644        ((kN32_SkColorType == colorType && cinfo.out_color_space == JCS_RGBA_8888) ||
645         (kRGB_565_SkColorType == colorType && cinfo.out_color_space == JCS_RGB_565)))
646    {
647        JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels();
648        INT32 const bpr =  bm->rowBytes();
649
650        while (cinfo.output_scanline < cinfo.output_height) {
651            int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
652            if (0 == row_count) {
653                // if row_count == 0, then we didn't get a scanline,
654                // so return early.  We will return a partial image.
655                fill_below_level(cinfo.output_scanline, bm);
656                cinfo.output_scanline = cinfo.output_height;
657                break;  // Skip to jpeg_finish_decompress()
658            }
659            if (this->shouldCancelDecode()) {
660                return return_false(cinfo, *bm, "shouldCancelDecode");
661            }
662            rowptr += bpr;
663        }
664        jpeg_finish_decompress(&cinfo);
665        return true;
666    }
667#endif
668
669    // check for supported formats
670    SkScaledBitmapSampler::SrcConfig sc;
671    int srcBytesPerPixel;
672
673    if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) {
674        return return_false(cinfo, *bm, "jpeg colorspace");
675    }
676
677    if (!sampler.begin(bm, sc, *this)) {
678        return return_false(cinfo, *bm, "sampler.begin");
679    }
680
681    SkAutoMalloc srcStorage(cinfo.output_width * srcBytesPerPixel);
682    uint8_t* srcRow = (uint8_t*)srcStorage.get();
683
684    //  Possibly skip initial rows [sampler.srcY0]
685    if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) {
686        return return_false(cinfo, *bm, "skip rows");
687    }
688
689    // now loop through scanlines until y == bm->height() - 1
690    for (int y = 0;; y++) {
691        JSAMPLE* rowptr = (JSAMPLE*)srcRow;
692        int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
693        if (0 == row_count) {
694            // if row_count == 0, then we didn't get a scanline,
695            // so return early.  We will return a partial image.
696            fill_below_level(y, bm);
697            cinfo.output_scanline = cinfo.output_height;
698            break;  // Skip to jpeg_finish_decompress()
699        }
700        if (this->shouldCancelDecode()) {
701            return return_false(cinfo, *bm, "shouldCancelDecode");
702        }
703
704        if (JCS_CMYK == cinfo.out_color_space) {
705            convert_CMYK_to_RGB(srcRow, cinfo.output_width);
706        }
707
708        sampler.next(srcRow);
709        if (bm->height() - 1 == y) {
710            // we're done
711            break;
712        }
713
714        if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) {
715            return return_false(cinfo, *bm, "skip rows");
716        }
717    }
718
719    // we formally skip the rest, so we don't get a complaint from libjpeg
720    if (!skip_src_rows(&cinfo, srcRow,
721                       cinfo.output_height - cinfo.output_scanline)) {
722        return return_false(cinfo, *bm, "skip rows");
723    }
724    jpeg_finish_decompress(&cinfo);
725
726    return true;
727}
728
729#ifdef SK_BUILD_FOR_ANDROID
730bool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width, int *height) {
731
732    SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (stream, this)));
733    jpeg_decompress_struct* cinfo = imageIndex->cinfo();
734
735    skjpeg_error_mgr sk_err;
736    set_error_mgr(cinfo, &sk_err);
737
738    // All objects need to be instantiated before this setjmp call so that
739    // they will be cleaned up properly if an error occurs.
740    if (setjmp(sk_err.fJmpBuf)) {
741        return false;
742    }
743
744    // create the cinfo used to create/build the huffmanIndex
745    if (!imageIndex->initializeInfoAndReadHeader()) {
746        return false;
747    }
748
749    if (!imageIndex->buildHuffmanIndex()) {
750        return false;
751    }
752
753    // destroy the cinfo used to create/build the huffman index
754    imageIndex->destroyInfo();
755
756    // Init decoder to image decode mode
757    if (!imageIndex->initializeInfoAndReadHeader()) {
758        return false;
759    }
760
761    // FIXME: This sets cinfo->out_color_space, which we may change later
762    // based on the config in onDecodeSubset. This should be fine, since
763    // jpeg_init_read_tile_scanline will check out_color_space again after
764    // that change (when it calls jinit_color_deconverter).
765    (void) this->getBitmapColorType(cinfo);
766
767    turn_off_visual_optimizations(cinfo);
768
769    // instead of jpeg_start_decompress() we start a tiled decompress
770    if (!imageIndex->startTileDecompress()) {
771        return false;
772    }
773
774    SkASSERT(1 == cinfo->scale_num);
775    fImageWidth = cinfo->output_width;
776    fImageHeight = cinfo->output_height;
777
778    if (width) {
779        *width = fImageWidth;
780    }
781    if (height) {
782        *height = fImageHeight;
783    }
784
785    SkDELETE(fImageIndex);
786    fImageIndex = imageIndex.detach();
787
788    return true;
789}
790
791bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
792    if (NULL == fImageIndex) {
793        return false;
794    }
795    jpeg_decompress_struct* cinfo = fImageIndex->cinfo();
796
797    SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight);
798    if (!rect.intersect(region)) {
799        // If the requested region is entirely outside the image return false
800        return false;
801    }
802
803
804    skjpeg_error_mgr errorManager;
805    set_error_mgr(cinfo, &errorManager);
806
807    if (setjmp(errorManager.fJmpBuf)) {
808        return false;
809    }
810
811    int requestedSampleSize = this->getSampleSize();
812    cinfo->scale_denom = requestedSampleSize;
813
814    set_dct_method(*this, cinfo);
815
816    const SkColorType colorType = this->getBitmapColorType(cinfo);
817    adjust_out_color_space_and_dither(cinfo, colorType, *this);
818
819    int startX = rect.fLeft;
820    int startY = rect.fTop;
821    int width = rect.width();
822    int height = rect.height();
823
824    jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(),
825                                 &startX, &startY, &width, &height);
826    int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo);
827    int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size);
828
829    SkScaledBitmapSampler sampler(width, height, skiaSampleSize);
830
831    SkBitmap bitmap;
832    // Assume an A8 bitmap is not opaque to avoid the check of each
833    // individual pixel. It is very unlikely to be opaque, since
834    // an opaque A8 bitmap would not be very interesting.
835    // Otherwise, a jpeg image is opaque.
836    bitmap.setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), colorType,
837                                     kAlpha_8_SkColorType == colorType ?
838                                         kPremul_SkAlphaType : kOpaque_SkAlphaType));
839
840    // Check ahead of time if the swap(dest, src) is possible or not.
841    // If yes, then we will stick to AllocPixelRef since it's cheaper with the
842    // swap happening. If no, then we will use alloc to allocate pixels to
843    // prevent garbage collection.
844    int w = rect.width() / actualSampleSize;
845    int h = rect.height() / actualSampleSize;
846    bool swapOnly = (rect == region) && bm->isNull() &&
847                    (w == bitmap.width()) && (h == bitmap.height()) &&
848                    ((startX - rect.x()) / actualSampleSize == 0) &&
849                    ((startY - rect.y()) / actualSampleSize == 0);
850    if (swapOnly) {
851        if (!this->allocPixelRef(&bitmap, NULL)) {
852            return return_false(*cinfo, bitmap, "allocPixelRef");
853        }
854    } else {
855        if (!bitmap.tryAllocPixels()) {
856            return return_false(*cinfo, bitmap, "allocPixels");
857        }
858    }
859
860    SkAutoLockPixels alp(bitmap);
861
862#ifdef ANDROID_RGB
863    /* short-circuit the SkScaledBitmapSampler when possible, as this gives
864       a significant performance boost.
865    */
866    if (skiaSampleSize == 1 &&
867        ((kN32_SkColorType == colorType && cinfo->out_color_space == JCS_RGBA_8888) ||
868         (kRGB_565_SkColorType == colorType && cinfo->out_color_space == JCS_RGB_565)))
869    {
870        JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels();
871        INT32 const bpr = bitmap.rowBytes();
872        int rowTotalCount = 0;
873
874        while (rowTotalCount < height) {
875            int rowCount = jpeg_read_tile_scanline(cinfo,
876                                                   fImageIndex->huffmanIndex(),
877                                                   &rowptr);
878            // if rowCount == 0, then we didn't get a scanline, so abort.
879            // onDecodeSubset() relies on onBuildTileIndex(), which
880            // needs a complete image to succeed.
881            if (0 == rowCount) {
882                return return_false(*cinfo, bitmap, "read_scanlines");
883            }
884            if (this->shouldCancelDecode()) {
885                return return_false(*cinfo, bitmap, "shouldCancelDecode");
886            }
887            rowTotalCount += rowCount;
888            rowptr += bpr;
889        }
890
891        if (swapOnly) {
892            bm->swap(bitmap);
893        } else {
894            cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(),
895                       region.width(), region.height(), startX, startY);
896        }
897        return true;
898    }
899#endif
900
901    // check for supported formats
902    SkScaledBitmapSampler::SrcConfig sc;
903    int srcBytesPerPixel;
904
905    if (!get_src_config(*cinfo, &sc, &srcBytesPerPixel)) {
906        return return_false(*cinfo, *bm, "jpeg colorspace");
907    }
908
909    if (!sampler.begin(&bitmap, sc, *this)) {
910        return return_false(*cinfo, bitmap, "sampler.begin");
911    }
912
913    SkAutoMalloc  srcStorage(width * srcBytesPerPixel);
914    uint8_t* srcRow = (uint8_t*)srcStorage.get();
915
916    //  Possibly skip initial rows [sampler.srcY0]
917    if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.srcY0())) {
918        return return_false(*cinfo, bitmap, "skip rows");
919    }
920
921    // now loop through scanlines until y == bitmap->height() - 1
922    for (int y = 0;; y++) {
923        JSAMPLE* rowptr = (JSAMPLE*)srcRow;
924        int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), &rowptr);
925        // if row_count == 0, then we didn't get a scanline, so abort.
926        // onDecodeSubset() relies on onBuildTileIndex(), which
927        // needs a complete image to succeed.
928        if (0 == row_count) {
929            return return_false(*cinfo, bitmap, "read_scanlines");
930        }
931        if (this->shouldCancelDecode()) {
932            return return_false(*cinfo, bitmap, "shouldCancelDecode");
933        }
934
935        if (JCS_CMYK == cinfo->out_color_space) {
936            convert_CMYK_to_RGB(srcRow, width);
937        }
938
939        sampler.next(srcRow);
940        if (bitmap.height() - 1 == y) {
941            // we're done
942            break;
943        }
944
945        if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow,
946                                sampler.srcDY() - 1)) {
947            return return_false(*cinfo, bitmap, "skip rows");
948        }
949    }
950    if (swapOnly) {
951        bm->swap(bitmap);
952    } else {
953        cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(),
954                   region.width(), region.height(), startX, startY);
955    }
956    return true;
957}
958#endif
959
960///////////////////////////////////////////////////////////////////////////////
961
962#include "SkColorPriv.h"
963
964// taken from jcolor.c in libjpeg
965#if 0   // 16bit - precise but slow
966    #define CYR     19595   // 0.299
967    #define CYG     38470   // 0.587
968    #define CYB      7471   // 0.114
969
970    #define CUR    -11059   // -0.16874
971    #define CUG    -21709   // -0.33126
972    #define CUB     32768   // 0.5
973
974    #define CVR     32768   // 0.5
975    #define CVG    -27439   // -0.41869
976    #define CVB     -5329   // -0.08131
977
978    #define CSHIFT  16
979#else      // 8bit - fast, slightly less precise
980    #define CYR     77    // 0.299
981    #define CYG     150    // 0.587
982    #define CYB      29    // 0.114
983
984    #define CUR     -43    // -0.16874
985    #define CUG    -85    // -0.33126
986    #define CUB     128    // 0.5
987
988    #define CVR      128   // 0.5
989    #define CVG     -107   // -0.41869
990    #define CVB      -21   // -0.08131
991
992    #define CSHIFT  8
993#endif
994
995static void rgb2yuv_32(uint8_t dst[], SkPMColor c) {
996    int r = SkGetPackedR32(c);
997    int g = SkGetPackedG32(c);
998    int b = SkGetPackedB32(c);
999
1000    int  y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT;
1001    int  u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT;
1002    int  v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT;
1003
1004    dst[0] = SkToU8(y);
1005    dst[1] = SkToU8(u + 128);
1006    dst[2] = SkToU8(v + 128);
1007}
1008
1009static void rgb2yuv_4444(uint8_t dst[], U16CPU c) {
1010    int r = SkGetPackedR4444(c);
1011    int g = SkGetPackedG4444(c);
1012    int b = SkGetPackedB4444(c);
1013
1014    int  y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4);
1015    int  u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4);
1016    int  v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4);
1017
1018    dst[0] = SkToU8(y);
1019    dst[1] = SkToU8(u + 128);
1020    dst[2] = SkToU8(v + 128);
1021}
1022
1023static void rgb2yuv_16(uint8_t dst[], U16CPU c) {
1024    int r = SkGetPackedR16(c);
1025    int g = SkGetPackedG16(c);
1026    int b = SkGetPackedB16(c);
1027
1028    int  y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2);
1029    int  u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2);
1030    int  v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2);
1031
1032    dst[0] = SkToU8(y);
1033    dst[1] = SkToU8(u + 128);
1034    dst[2] = SkToU8(v + 128);
1035}
1036
1037///////////////////////////////////////////////////////////////////////////////
1038
1039typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst,
1040                              const void* SK_RESTRICT src, int width,
1041                              const SkPMColor* SK_RESTRICT ctable);
1042
1043static void Write_32_YUV(uint8_t* SK_RESTRICT dst,
1044                         const void* SK_RESTRICT srcRow, int width,
1045                         const SkPMColor*) {
1046    const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow;
1047    while (--width >= 0) {
1048#ifdef WE_CONVERT_TO_YUV
1049        rgb2yuv_32(dst, *src++);
1050#else
1051        uint32_t c = *src++;
1052        dst[0] = SkGetPackedR32(c);
1053        dst[1] = SkGetPackedG32(c);
1054        dst[2] = SkGetPackedB32(c);
1055#endif
1056        dst += 3;
1057    }
1058}
1059
1060static void Write_4444_YUV(uint8_t* SK_RESTRICT dst,
1061                           const void* SK_RESTRICT srcRow, int width,
1062                           const SkPMColor*) {
1063    const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow;
1064    while (--width >= 0) {
1065#ifdef WE_CONVERT_TO_YUV
1066        rgb2yuv_4444(dst, *src++);
1067#else
1068        SkPMColor16 c = *src++;
1069        dst[0] = SkPacked4444ToR32(c);
1070        dst[1] = SkPacked4444ToG32(c);
1071        dst[2] = SkPacked4444ToB32(c);
1072#endif
1073        dst += 3;
1074    }
1075}
1076
1077static void Write_16_YUV(uint8_t* SK_RESTRICT dst,
1078                         const void* SK_RESTRICT srcRow, int width,
1079                         const SkPMColor*) {
1080    const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow;
1081    while (--width >= 0) {
1082#ifdef WE_CONVERT_TO_YUV
1083        rgb2yuv_16(dst, *src++);
1084#else
1085        uint16_t c = *src++;
1086        dst[0] = SkPacked16ToR32(c);
1087        dst[1] = SkPacked16ToG32(c);
1088        dst[2] = SkPacked16ToB32(c);
1089#endif
1090        dst += 3;
1091    }
1092}
1093
1094static void Write_Index_YUV(uint8_t* SK_RESTRICT dst,
1095                            const void* SK_RESTRICT srcRow, int width,
1096                            const SkPMColor* SK_RESTRICT ctable) {
1097    const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow;
1098    while (--width >= 0) {
1099#ifdef WE_CONVERT_TO_YUV
1100        rgb2yuv_32(dst, ctable[*src++]);
1101#else
1102        uint32_t c = ctable[*src++];
1103        dst[0] = SkGetPackedR32(c);
1104        dst[1] = SkGetPackedG32(c);
1105        dst[2] = SkGetPackedB32(c);
1106#endif
1107        dst += 3;
1108    }
1109}
1110
1111static WriteScanline ChooseWriter(const SkBitmap& bm) {
1112    switch (bm.colorType()) {
1113        case kN32_SkColorType:
1114            return Write_32_YUV;
1115        case kRGB_565_SkColorType:
1116            return Write_16_YUV;
1117        case kARGB_4444_SkColorType:
1118            return Write_4444_YUV;
1119        case kIndex_8_SkColorType:
1120            return Write_Index_YUV;
1121        default:
1122            return NULL;
1123    }
1124}
1125
1126class SkJPEGImageEncoder : public SkImageEncoder {
1127protected:
1128    virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) {
1129#ifdef TIME_ENCODE
1130        SkAutoTime atm("JPEG Encode");
1131#endif
1132
1133        SkAutoLockPixels alp(bm);
1134        if (NULL == bm.getPixels()) {
1135            return false;
1136        }
1137
1138        jpeg_compress_struct    cinfo;
1139        skjpeg_error_mgr        sk_err;
1140        skjpeg_destination_mgr  sk_wstream(stream);
1141
1142        // allocate these before set call setjmp
1143        SkAutoMalloc    oneRow;
1144        SkAutoLockColors ctLocker;
1145
1146        cinfo.err = jpeg_std_error(&sk_err);
1147        sk_err.error_exit = skjpeg_error_exit;
1148        if (setjmp(sk_err.fJmpBuf)) {
1149            return false;
1150        }
1151
1152        // Keep after setjmp or mark volatile.
1153        const WriteScanline writer = ChooseWriter(bm);
1154        if (NULL == writer) {
1155            return false;
1156        }
1157
1158        jpeg_create_compress(&cinfo);
1159        cinfo.dest = &sk_wstream;
1160        cinfo.image_width = bm.width();
1161        cinfo.image_height = bm.height();
1162        cinfo.input_components = 3;
1163#ifdef WE_CONVERT_TO_YUV
1164        cinfo.in_color_space = JCS_YCbCr;
1165#else
1166        cinfo.in_color_space = JCS_RGB;
1167#endif
1168        cinfo.input_gamma = 1;
1169
1170        jpeg_set_defaults(&cinfo);
1171        jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
1172#ifdef DCT_IFAST_SUPPORTED
1173        cinfo.dct_method = JDCT_IFAST;
1174#endif
1175
1176        jpeg_start_compress(&cinfo, TRUE);
1177
1178        const int       width = bm.width();
1179        uint8_t*        oneRowP = (uint8_t*)oneRow.reset(width * 3);
1180
1181        const SkPMColor* colors = ctLocker.lockColors(bm);
1182        const void*      srcRow = bm.getPixels();
1183
1184        while (cinfo.next_scanline < cinfo.image_height) {
1185            JSAMPROW row_pointer[1];    /* pointer to JSAMPLE row[s] */
1186
1187            writer(oneRowP, srcRow, width, colors);
1188            row_pointer[0] = oneRowP;
1189            (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
1190            srcRow = (const void*)((const char*)srcRow + bm.rowBytes());
1191        }
1192
1193        jpeg_finish_compress(&cinfo);
1194        jpeg_destroy_compress(&cinfo);
1195
1196        return true;
1197    }
1198};
1199
1200///////////////////////////////////////////////////////////////////////////////
1201DEFINE_DECODER_CREATOR(JPEGImageDecoder);
1202DEFINE_ENCODER_CREATOR(JPEGImageEncoder);
1203///////////////////////////////////////////////////////////////////////////////
1204
1205static bool is_jpeg(SkStreamRewindable* stream) {
1206    static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF };
1207    static const size_t HEADER_SIZE = sizeof(gHeader);
1208
1209    char buffer[HEADER_SIZE];
1210    size_t len = stream->read(buffer, HEADER_SIZE);
1211
1212    if (len != HEADER_SIZE) {
1213        return false;   // can't read enough
1214    }
1215    if (memcmp(buffer, gHeader, HEADER_SIZE)) {
1216        return false;
1217    }
1218    return true;
1219}
1220
1221
1222static SkImageDecoder* sk_libjpeg_dfactory(SkStreamRewindable* stream) {
1223    if (is_jpeg(stream)) {
1224        return SkNEW(SkJPEGImageDecoder);
1225    }
1226    return NULL;
1227}
1228
1229static SkImageDecoder::Format get_format_jpeg(SkStreamRewindable* stream) {
1230    if (is_jpeg(stream)) {
1231        return SkImageDecoder::kJPEG_Format;
1232    }
1233    return SkImageDecoder::kUnknown_Format;
1234}
1235
1236static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) {
1237    return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL;
1238}
1239
1240static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory);
1241static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg);
1242static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory);
1243