Fredrik Lundh is sharing code with you

Bitbucket is a code hosting site. Unlimited public and private repositories. Free for small teams.

Don't show this again

effbot / pil-2009-raclette http://effbot.org/zone/pil-index.htm

Work repository for PIL 1.1.7 and beyond. The "default" branch should be fairly solid, the other branches less so. For production use, see the pil-117 repository.

Clone this repository (size: 1.6 MB): HTTPS / SSH
hg clone https://bitbucket.org/effbot/pil-2009-raclette
hg clone ssh://hg@bitbucket.org/effbot/pil-2009-raclette

pil-2009-raclette / libImaging / JpegEncode.c

/*
 * The Python Imaging Library.
 * $Id: JpegEncode.c 2134 2004-10-06 08:55:20Z fredrik $
 *
 * coder for JPEG data
 *
 * history:
 * 1996-05-06 fl   created
 * 1996-07-16 fl   don't drop last block of encoded data
 * 1996-12-30 fl   added quality and progressive settings
 * 1997-01-08 fl   added streamtype settings
 * 1998-01-31 fl   adapted to libjpeg 6a
 * 1998-07-12 fl   added YCbCr support
 * 2001-04-16 fl   added DPI write support
 *
 * Copyright (c) 1997-2001 by Secret Labs AB
 * Copyright (c) 1995-1997 by Fredrik Lundh
 *
 * See the README file for details on usage and redistribution.
 */


#include "Imaging.h"

#ifdef  HAVE_LIBJPEG

#undef HAVE_PROTOTYPES 
#undef HAVE_STDLIB_H 
#undef HAVE_STDDEF_H 
#undef UINT8
#undef UINT16
#undef UINT32
#undef INT16
#undef INT32

#include "Jpeg.h"

/* -------------------------------------------------------------------- */
/* Suspending output handler                                            */
/* -------------------------------------------------------------------- */

METHODDEF(void)
stub(j_compress_ptr cinfo)
{
    /* empty */
}

METHODDEF(boolean)
empty_output_buffer (j_compress_ptr cinfo)
{
    /* Suspension */
    return FALSE;
}

GLOBAL(void)
jpeg_buffer_dest(j_compress_ptr cinfo, JPEGDESTINATION* destination)
{
    cinfo->dest = (void*) destination;

    destination->pub.init_destination = stub;
    destination->pub.empty_output_buffer = empty_output_buffer;
    destination->pub.term_destination = stub;
}


/* -------------------------------------------------------------------- */
/* Error handler                                                        */
/* -------------------------------------------------------------------- */

METHODDEF(void)
error(j_common_ptr cinfo)
{
  JPEGERROR* error;
  error = (JPEGERROR*) cinfo->err;
  (*cinfo->err->output_message) (cinfo);
  longjmp(error->setjmp_buffer, 1);
}


/* -------------------------------------------------------------------- */
/* Encoder                                                              */
/* -------------------------------------------------------------------- */

int
ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
{
    JPEGENCODERSTATE* context = (JPEGENCODERSTATE*) state->context;
    int ok;

    if (setjmp(context->error.setjmp_buffer)) {
        /* JPEG error handler */
        jpeg_destroy_compress(&context->cinfo);
        state->errcode = IMAGING_CODEC_BROKEN;
        return -1;
    }

    if (!state->state) {

        /* Setup compression context (very similar to the decoder) */
        context->cinfo.err = jpeg_std_error(&context->error.pub);
        context->error.pub.error_exit = error;
        jpeg_create_compress(&context->cinfo);
        jpeg_buffer_dest(&context->cinfo, &context->destination);

        /* Ready to encode */
        state->state = 1;

    }

    /* Load the destination buffer */
    context->destination.pub.next_output_byte = buf;
    context->destination.pub.free_in_buffer = bytes;

    switch (state->state) {

    case 1:

        context->cinfo.image_width = state->xsize;
        context->cinfo.image_height = state->ysize;

        switch (state->bits) {
        case 8:
            context->cinfo.input_components = 1;
            context->cinfo.in_color_space = JCS_GRAYSCALE;
            break;
        case 24:
            context->cinfo.input_components = 3;
            if (strcmp(im->mode, "YCbCr") == 0)
                context->cinfo.in_color_space = JCS_YCbCr;
            else
                context->cinfo.in_color_space = JCS_RGB;
            break;
        case 32:
            context->cinfo.input_components = 4;
            context->cinfo.in_color_space = JCS_CMYK;
            break;
        default:
            state->errcode = IMAGING_CODEC_CONFIG;
            return -1;
        }

        /* Compressor configuration */
        jpeg_set_defaults(&context->cinfo);
        if (context->quality > 0)
            jpeg_set_quality(&context->cinfo, context->quality, 1);
        
        /* Set subsampling options */
        switch (context->subsampling)
        {
                case 0:  /* 1x1 1x1 1x1 (4:4:4) : None */
                {
                        context->cinfo.comp_info[0].h_samp_factor = 1;
                        context->cinfo.comp_info[0].v_samp_factor = 1;
                        context->cinfo.comp_info[1].h_samp_factor = 1;
                        context->cinfo.comp_info[1].v_samp_factor = 1;
                        context->cinfo.comp_info[2].h_samp_factor = 1;
                        context->cinfo.comp_info[2].v_samp_factor = 1;
                        break;
                }
                case 1:  /* 2x1, 1x1, 1x1 (4:2:2) : Medium */
                {
                        context->cinfo.comp_info[0].h_samp_factor = 2;
                        context->cinfo.comp_info[0].v_samp_factor = 1;
                        context->cinfo.comp_info[1].h_samp_factor = 1;
                        context->cinfo.comp_info[1].v_samp_factor = 1;
                        context->cinfo.comp_info[2].h_samp_factor = 1;
                        context->cinfo.comp_info[2].v_samp_factor = 1;
                        break;
                }
                case 2:  /* 2x2, 1x1, 1x1 (4:1:1) : High */
                {
                        context->cinfo.comp_info[0].h_samp_factor = 2;
                        context->cinfo.comp_info[0].v_samp_factor = 2;
                        context->cinfo.comp_info[1].h_samp_factor = 1;
                        context->cinfo.comp_info[1].v_samp_factor = 1;
                        context->cinfo.comp_info[2].h_samp_factor = 1;
                        context->cinfo.comp_info[2].v_samp_factor = 1;
                        break;
                }
                default:
                {
                        /* Use the lib's default */
                        break;
                }
        }
        if (context->progressive)
            jpeg_simple_progression(&context->cinfo);
        context->cinfo.smoothing_factor = context->smooth;
        context->cinfo.optimize_coding = (boolean) context->optimize;
        if (context->xdpi > 0 && context->ydpi > 0) {
            context->cinfo.density_unit = 1; /* dots per inch */
            context->cinfo.X_density = context->xdpi;
            context->cinfo.Y_density = context->ydpi;
        }
        switch (context->streamtype) {
        case 1:
            /* tables only -- not yet implemented */
            state->errcode = IMAGING_CODEC_CONFIG;
            return -1;
        case 2:
            /* image only */
            jpeg_suppress_tables(&context->cinfo, TRUE);
            jpeg_start_compress(&context->cinfo, FALSE);
            break;
        default:
            /* interchange stream */
            jpeg_start_compress(&context->cinfo, TRUE);
            break;
        }
        state->state++;
        /* fall through */

    case 2:

        ok = 1;
        while (state->y < state->ysize) {
            state->shuffle(state->buffer,
                           (UINT8*) im->image[state->y + state->yoff] +
                           state->xoff * im->pixelsize, state->xsize);
            ok = jpeg_write_scanlines(&context->cinfo, &state->buffer, 1);
            if (ok != 1)
                break;
            state->y++;
        }

        if (ok != 1)
            break;
        state->state++;
        /* fall through */

    case 3:

        /* Finish compression */
        if (context->destination.pub.free_in_buffer < 100)
            break;
        jpeg_finish_compress(&context->cinfo);

        /* Clean up */
        jpeg_destroy_compress(&context->cinfo);
        /* if (jerr.pub.num_warnings) return BROKEN; */
        state->errcode = IMAGING_CODEC_END;
        break;

    }

    /* Return number of bytes in output buffer */
    return context->destination.pub.next_output_byte - buf;

}

const char*
ImagingJpegVersion(void)
{
    static char version[10];
    sprintf(version, "%d.%d", JPEG_LIB_VERSION / 10, JPEG_LIB_VERSION % 10);
    return version;
}

#endif