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