18dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine/* Copyright (C) 2011 The Android Open Source Project
28dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine**
38dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine** This software is licensed under the terms of the GNU General Public
48dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine** License version 2, as published by the Free Software Foundation, and
58dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine** may be copied, distributed, and modified under those terms.
68dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine**
78dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine** This program is distributed in the hope that it will be useful,
88dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine** but WITHOUT ANY WARRANTY; without even the implied warranty of
98dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
108dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine** GNU General Public License for more details.
118dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine*/
128dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
138dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine#include <stdint.h>
148dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine#include "jinclude.h"
158dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine#include "jpeglib.h"
168dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine#include "jpeg-compress.h"
178dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine#include "panic.h"
188dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
198dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine/* Implements JPEG destination manager's init_destination routine. */
208dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkinestatic void _on_init_destination(j_compress_ptr cinfo);
218dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine/* Implements JPEG destination manager's empty_output_buffer routine. */
228dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkinestatic boolean _on_empty_output_buffer(j_compress_ptr cinfo);
238dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine/* Implements JPEG destination manager's term_destination routine. */
248dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkinestatic void _on_term_destination(j_compress_ptr cinfo);
258dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
268dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine/* JPEG compression descriptor. */
278dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkinestruct AJPEGDesc {
288dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    /* Common JPEG compression destination manager header. */
298dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    struct jpeg_destination_mgr     common;
308dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    /* Buffer where to save compressed output. */
318dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    uint8_t*                        jpeg_buf;
328dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    /* Byte size of the 'jpeg_buf' */
338dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    int                             size;
348dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    /* Chunk size to increment the 'jpeg_buf' with on each allocation request. */
358dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    int                             chunk_size;
368dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    /* Size of the header to put in front of the compressed data. */
378dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    int                             header_size;
388dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine};
398dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
408dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine/********************************************************************************
418dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine *                      jpeglib callbacks.
428dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine *******************************************************************************/
438dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
448dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine/* Implements JPEG destination manager's init_destination routine. */
458dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkinestatic void
468dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine_on_init_destination(j_compress_ptr cinfo)
478dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine{
488dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    AJPEGDesc* const dst = (AJPEGDesc*)cinfo->dest;
498dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    if (dst->jpeg_buf == NULL) {
508dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine        /* This is the first time our destination manager is initialized.
518dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine         * Allocate minimal buffer. */
528dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine        dst->size = dst->chunk_size;
538dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine        dst->jpeg_buf = malloc(dst->size);
548dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine        if (dst->jpeg_buf == NULL) {
558dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine            APANIC("Unable to allocate %d bytes for JPEG compression", dst->size);
568dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine        }
578dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    }
588dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    /* Initialize common header with entire destination buffer. */
598dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    dst->common.next_output_byte = dst->jpeg_buf + dst->header_size;
608dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    dst->common.free_in_buffer = dst->size - dst->header_size;
618dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine}
628dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
638dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine/* Implements JPEG destination manager's empty_output_buffer routine.
648dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine * Name is a bit misleading here. This routine is called by the compressor when
658dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine * output buffer doesn't have enough free space to contain the next chunk of the
668dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine * compressed data. So, here we should reallocate the output buffer, rather than
678dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine * "empty" it.
688dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine */
698dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkinestatic boolean
708dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine_on_empty_output_buffer(j_compress_ptr cinfo)
718dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine{
728dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    AJPEGDesc* const dst = (AJPEGDesc*)cinfo->dest;
738dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    /* Save already compressed data size. */
748dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    const int accumulated = jpeg_compressor_get_jpeg_size(dst);
758dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
768dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    /* Reallocate output buffer. */
778dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    dst->size += dst->chunk_size;
788dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    dst->jpeg_buf = realloc(dst->jpeg_buf, dst->size);
798dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    if (dst->jpeg_buf == NULL) {
808dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine        APANIC("Unable to allocate %d bytes for JPEG compression", dst->size);
818dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    }
828dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
838dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    /* Update common header. */
848dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    dst->common.next_output_byte = dst->jpeg_buf + accumulated + dst->header_size;
858dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    dst->common.free_in_buffer = dst->size - accumulated - dst->header_size;
868dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
878dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    return TRUE;
888dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine}
898dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
908dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine/* Implements JPEG destination manager's term_destination routine.
918dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine * We don't do anything here. All the cleanup will be performed when the user
928dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine * calls jpeg_compressor_destroy. */
938dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkinestatic void
948dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine_on_term_destination(j_compress_ptr cinfo)
958dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine{
968dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine}
978dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
988dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine/********************************************************************************
998dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine *                      JPEG compressor API.
1008dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine *******************************************************************************/
1018dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
1028dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir ChtchetkineAJPEGDesc*
1038dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkinejpeg_compressor_create(int header_size, int chunk_size)
1048dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine{
1058dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    AJPEGDesc* dsc = (AJPEGDesc*)malloc(sizeof(AJPEGDesc));
1068dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    if (dsc == NULL) {
1078dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine        APANIC("Unable to allocate JPEG compression descriptor.");
1088dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    }
1098dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
1108dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    dsc->common.next_output_byte    = NULL;
1118dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    dsc->common.free_in_buffer      = 0;
1128dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    dsc->common.init_destination    = _on_init_destination;
1138dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    dsc->common.empty_output_buffer = _on_empty_output_buffer;
1148dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    dsc->common.term_destination    = _on_term_destination;
1158dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    dsc->jpeg_buf                   = NULL;
1168dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    dsc->size                       = 0;
1178dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    dsc->chunk_size                 = chunk_size;
1188dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    dsc->header_size                = header_size;
1198dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    return dsc;
1208dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine}
1218dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
1228dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkinevoid
1238dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkinejpeg_compressor_destroy(AJPEGDesc* dsc)
1248dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine{
1258dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    if (dsc != NULL) {
1268dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine        if (dsc->jpeg_buf != NULL) {
1278dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine            free(dsc->jpeg_buf);
1288dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine        }
1298dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine        free(dsc);
1308dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    }
1318dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine}
1328dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
1338dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkineint
1348dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkinejpeg_compressor_get_jpeg_size(const AJPEGDesc* dsc)
1358dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine{
1368dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    return (dsc->jpeg_buf == NULL) ? 0 :
1378dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine        (uint8_t*)dsc->common.next_output_byte - dsc->jpeg_buf - dsc->header_size;
1388dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine}
1398dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
1408dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkinevoid*
1418dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkinejpeg_compressor_get_buffer(const AJPEGDesc* dsc)
1428dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine{
1438dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine     return dsc->jpeg_buf;
1448dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine}
1458dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
1468dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkineint
1478dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkinejpeg_compressor_get_header_size(const AJPEGDesc* dsc)
1488dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine{
1498dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine     return dsc->header_size;
1508dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine}
1518dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
1528dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkinevoid
1538dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkinejpeg_compressor_compress_fb(AJPEGDesc* dsc,
1541a820e90d8848c6b0ac7c78b5a2e8b28c9738a3aVladimir Chtchetkine                            int x, int y, int w, int h, int num_lines,
1558dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine                            int bpp, int bpl,
1568dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine                            const uint8_t* fb,
1571a820e90d8848c6b0ac7c78b5a2e8b28c9738a3aVladimir Chtchetkine                            int jpeg_quality,
1581a820e90d8848c6b0ac7c78b5a2e8b28c9738a3aVladimir Chtchetkine                            int ydir){
1598dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    struct jpeg_compress_struct cinfo = {0};
1608dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    struct jpeg_error_mgr err_mgr;
1611a820e90d8848c6b0ac7c78b5a2e8b28c9738a3aVladimir Chtchetkine    const int x_shift = x * bpp;
1628dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
1638dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    /*
1648dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine     * Initialize compressin information structure, and start compression
1658dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine     */
1668dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
1678dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    cinfo.err = jpeg_std_error(&err_mgr);
1688dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    jpeg_create_compress(&cinfo);
1698dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    cinfo.dest = &dsc->common;
1708dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    cinfo.image_width = w;
1718dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    cinfo.image_height = h;
1728dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
1738dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    /* Decode framebuffer's pixel format. There can be only three:
1748dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine     * - RGB565,
1758dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine     * - RGBA8888,
1768dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine     * - RGBX8888 */
1778dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    if (bpp == 2) {
1788dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine        /* This is RGB565 - most commonly used pixel format for framebuffer. */
1798dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine        cinfo.input_components = 2;
1808dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine        cinfo.in_color_space = JCS_RGB_565;
1818dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    } else {
1828dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine        /* RGBA8888, or RGBX8888 - makes no difference here. */
1838dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine        cinfo.input_components = 4;
1848dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine        cinfo.in_color_space = JCS_RGBA_8888;
1858dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    }
1868dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    jpeg_set_defaults(&cinfo);
1878dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    jpeg_set_quality(&cinfo, jpeg_quality, TRUE);
1888dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    jpeg_start_compress(&cinfo, TRUE);
1898dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
1908dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    /* Line by line compress the region. */
1911a820e90d8848c6b0ac7c78b5a2e8b28c9738a3aVladimir Chtchetkine    if (ydir >= 0) {
1921a820e90d8848c6b0ac7c78b5a2e8b28c9738a3aVladimir Chtchetkine        while (cinfo.next_scanline < cinfo.image_height) {
1931a820e90d8848c6b0ac7c78b5a2e8b28c9738a3aVladimir Chtchetkine            JSAMPROW rgb = (JSAMPROW)(fb + (cinfo.next_scanline + y) * bpl + x_shift);
1941a820e90d8848c6b0ac7c78b5a2e8b28c9738a3aVladimir Chtchetkine            jpeg_write_scanlines(&cinfo, (JSAMPARRAY)&rgb, 1);
1951a820e90d8848c6b0ac7c78b5a2e8b28c9738a3aVladimir Chtchetkine        }
1961a820e90d8848c6b0ac7c78b5a2e8b28c9738a3aVladimir Chtchetkine    } else {
1971a820e90d8848c6b0ac7c78b5a2e8b28c9738a3aVladimir Chtchetkine        const int y_shift = num_lines - y - 1;
1981a820e90d8848c6b0ac7c78b5a2e8b28c9738a3aVladimir Chtchetkine        while (cinfo.next_scanline < cinfo.image_height) {
1991a820e90d8848c6b0ac7c78b5a2e8b28c9738a3aVladimir Chtchetkine            JSAMPROW rgb = (JSAMPROW)(fb + (y_shift - cinfo.next_scanline) * bpl + x_shift);
2001a820e90d8848c6b0ac7c78b5a2e8b28c9738a3aVladimir Chtchetkine            jpeg_write_scanlines(&cinfo, (JSAMPARRAY)&rgb, 1);
2011a820e90d8848c6b0ac7c78b5a2e8b28c9738a3aVladimir Chtchetkine        }
2028dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    }
2038dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine
2048dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    /* Complete the compression. */
2058dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    jpeg_finish_compress(&cinfo);
2068dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine    jpeg_destroy_compress(&cinfo);
2078dd31e8e10fc3ca10192368acf19d2345eeddde7Vladimir Chtchetkine}
208