2003-03-26 19:57:29 +08:00
//
// ZoneMinder Image Class Implementation, $Date$, $Revision$
2008-07-25 17:33:23 +08:00
// Copyright (C) 2001-2008 Philip Coombes
2003-03-26 19:57:29 +08:00
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
2003-05-16 18:27:41 +08:00
# include "zm.h"
2003-04-07 18:56:38 +08:00
# include "zm_font.h"
2003-03-26 19:57:29 +08:00
# include "zm_image.h"
2005-11-30 01:51:06 +08:00
# include <sys/stat.h>
2009-03-20 20:39:29 +08:00
# include <errno.h>
2005-11-30 01:51:06 +08:00
2003-04-16 21:02:15 +08:00
# define ABSDIFF(a,b) (((a)<(b))?((b)-(a)):((a)-(b)))
2004-02-16 03:53:10 +08:00
bool Image : : initialised = false ;
unsigned char * Image : : abs_table ;
unsigned char * Image : : y_r_table ;
unsigned char * Image : : y_g_table ;
unsigned char * Image : : y_b_table ;
Image : : BlendTablePtr Image : : blend_tables [ 101 ] ;
2005-11-22 18:41:50 +08:00
jpeg_compress_struct * Image : : jpg_ccinfo [ 100 ] = { 0 } ;
jpeg_decompress_struct * Image : : jpg_dcinfo = 0 ;
struct zm_error_mgr Image : : jpg_err ;
2007-08-30 02:11:09 +08:00
Image : : Image ( )
{
if ( ! initialised )
Initialise ( ) ;
width = 0 ;
height = 0 ;
pixels = 0 ;
colours = 0 ;
size = 0 ;
allocation = 0 ;
buffer = 0 ;
blend_buffer = 0 ;
text [ 0 ] = ' \0 ' ;
}
Image : : Image ( const char * filename )
{
if ( ! initialised )
Initialise ( ) ;
width = 0 ;
height = 0 ;
pixels = 0 ;
colours = 0 ;
size = 0 ;
allocation = 0 ;
buffer = 0 ;
ReadJpeg ( filename ) ;
blend_buffer = 0 ;
text [ 0 ] = ' \0 ' ;
}
2011-02-15 19:18:41 +08:00
Image : : Image ( int p_width , int p_height , int p_colours , uint8_t * p_buffer )
2007-08-30 02:11:09 +08:00
{
if ( ! initialised )
Initialise ( ) ;
width = p_width ;
height = p_height ;
pixels = width * height ;
colours = p_colours ;
size = width * height * colours ;
if ( p_buffer )
{
allocation = 0 ;
buffer = p_buffer ;
}
else
{
allocation = size ;
2011-02-15 19:18:41 +08:00
buffer = new uint8_t [ allocation ] ;
2007-08-30 02:11:09 +08:00
memset ( buffer , 0 , size ) ;
}
blend_buffer = 0 ;
text [ 0 ] = ' \0 ' ;
}
Image : : Image ( const Image & p_image )
{
if ( ! initialised )
Initialise ( ) ;
width = p_image . width ;
height = p_image . height ;
pixels = p_image . pixels ;
colours = p_image . colours ;
size = allocation = p_image . size ;
2011-02-15 19:18:41 +08:00
buffer = new uint8_t [ allocation ] ;
2007-08-30 02:11:09 +08:00
memcpy ( buffer , p_image . buffer , size ) ;
blend_buffer = 0 ;
strncpy ( text , p_image . text , sizeof ( text ) ) ;
}
Image : : ~ Image ( )
{
if ( allocation )
{
delete [ ] buffer ;
}
delete [ ] blend_buffer ;
}
2004-02-16 03:53:10 +08:00
void Image : : Initialise ( )
{
initialised = true ;
abs_table = new unsigned char [ ( 6 * 255 ) + 1 ] ;
abs_table + = ( 3 * 255 ) ;
y_r_table = new unsigned char [ 511 ] ;
y_r_table + = 255 ;
y_g_table = new unsigned char [ 511 ] ;
y_g_table + = 255 ;
y_b_table = new unsigned char [ 511 ] ;
y_b_table + = 255 ;
for ( int i = - ( 3 * 255 ) ; i < = ( 3 * 255 ) ; i + + )
{
abs_table [ i ] = abs ( i ) ;
}
for ( int i = - 255 ; i < = 255 ; i + + )
{
y_r_table [ i ] = ( 2990 * abs ( i ) ) / 10000 ;
y_g_table [ i ] = ( 5670 * abs ( i ) ) / 10000 ;
y_b_table [ i ] = ( 1140 * abs ( i ) ) / 10000 ;
2008-07-14 22:43:47 +08:00
//Info( "I:%d, R:%d, G:%d, B:%d", i, y_r_table[i], y_g_table[i], y_b_table[i] );
2004-02-16 03:53:10 +08:00
}
for ( int i = 0 ; i < = 100 ; i + + )
{
blend_tables [ i ] = 0 ;
}
}
Image : : BlendTablePtr Image : : GetBlendTable ( int transparency )
{
BlendTablePtr blend_ptr = blend_tables [ transparency ] ;
if ( ! blend_ptr )
{
blend_ptr = blend_tables [ transparency ] = new BlendTable [ 1 ] ;
2008-07-14 22:43:47 +08:00
//Info( "Generating blend table for transparency %d", transparency );
2004-02-16 03:53:10 +08:00
int opacity = 100 - transparency ;
for ( int i = 0 ; i < 256 ; i + + )
{
for ( int j = 0 ; j < 256 ; j + + )
{
2011-02-15 19:18:41 +08:00
( * blend_ptr ) [ i ] [ j ] = ( uint8_t ) round ( ( ( i * opacity ) + ( j * transparency ) ) / 100.0 L ) ;
2004-02-16 03:53:10 +08:00
//printf( "I:%d, J:%d, B:%d\n", i, j, (*blend_ptr)[i][j] );
}
}
}
return ( blend_ptr ) ;
}
2007-08-30 02:11:09 +08:00
void Image : : Empty ( )
{
if ( allocation )
{
delete [ ] buffer ;
buffer = 0 ;
allocation = 0 ;
}
width = height = colours = size = 0 ;
}
void Image : : Assign ( int p_width , int p_height , int p_colours , unsigned char * new_buffer )
{
if ( ! buffer | | p_width ! = width | | p_height ! = height | | p_colours ! = colours )
{
width = p_width ;
height = p_height ;
pixels = width * height ;
colours = p_colours ;
size = width * height * colours ;
if ( allocation < size )
{
allocation = size ;
delete [ ] buffer ;
2011-02-15 19:18:41 +08:00
buffer = new uint8_t [ allocation ] ;
2007-08-30 02:11:09 +08:00
memset ( buffer , 0 , size ) ;
}
}
memcpy ( buffer , new_buffer , size ) ;
}
void Image : : Assign ( const Image & image )
{
if ( ! buffer | | image . width ! = width | | image . height ! = height | | image . colours ! = colours )
{
width = image . width ;
height = image . height ;
pixels = width * height ;
colours = image . colours ;
size = width * height * colours ;
if ( allocation < size )
{
allocation = size ;
delete [ ] buffer ;
2011-02-15 19:18:41 +08:00
buffer = new uint8_t [ allocation ] ;
2007-08-30 02:11:09 +08:00
memset ( buffer , 0 , size ) ;
}
}
memcpy ( buffer , image . buffer , size ) ;
}
2003-03-26 19:57:29 +08:00
Image * Image : : HighlightEdges ( Rgb colour , const Box * limits )
{
2006-05-08 20:46:53 +08:00
if ( colours ! = 1 )
{
2009-10-14 18:01:46 +08:00
Panic ( " Attempt to highlight image edges when colours = %d " , colours ) ;
2006-05-08 20:46:53 +08:00
}
2003-03-26 19:57:29 +08:00
Image * high_image = new Image ( width , height , 3 ) ;
int lo_x = limits ? limits - > Lo ( ) . X ( ) : 0 ;
int lo_y = limits ? limits - > Lo ( ) . Y ( ) : 0 ;
int hi_x = limits ? limits - > Hi ( ) . X ( ) : width - 1 ;
int hi_y = limits ? limits - > Hi ( ) . Y ( ) : height - 1 ;
for ( int y = lo_y ; y < = hi_y ; y + + )
{
unsigned char * p = & buffer [ ( y * width ) + lo_x ] ;
unsigned char * phigh = high_image - > Buffer ( lo_x , y ) ;
for ( int x = lo_x ; x < = hi_x ; x + + , p + + , phigh + = 3 )
{
bool edge = false ;
if ( * p )
{
if ( ! edge & & x > 0 & & ! * ( p - 1 ) ) edge = true ;
if ( ! edge & & x < ( width - 1 ) & & ! * ( p + 1 ) ) edge = true ;
if ( ! edge & & y > 0 & & ! * ( p - width ) ) edge = true ;
if ( ! edge & & y < ( height - 1 ) & & ! * ( p + width ) ) edge = true ;
}
if ( edge )
{
RED ( phigh ) = RGB_RED_VAL ( colour ) ;
GREEN ( phigh ) = RGB_GREEN_VAL ( colour ) ;
BLUE ( phigh ) = RGB_BLUE_VAL ( colour ) ;
}
}
}
return ( high_image ) ;
}
2005-11-30 01:51:06 +08:00
bool Image : : ReadRaw ( const char * filename )
{
FILE * infile ;
if ( ( infile = fopen ( filename , " rb " ) ) = = NULL )
{
2008-07-14 22:43:47 +08:00
Error ( " Can't open %s: %s " , filename , strerror ( errno ) ) ;
2005-11-30 01:51:06 +08:00
return ( false ) ;
}
struct stat statbuf ;
if ( fstat ( fileno ( infile ) , & statbuf ) < 0 )
{
2008-07-14 22:43:47 +08:00
Error ( " Can't fstat %s: %s " , filename , strerror ( errno ) ) ;
2005-11-30 01:51:06 +08:00
return ( false ) ;
}
2007-08-30 02:11:09 +08:00
if ( statbuf . st_size ! = size )
2005-11-30 01:51:06 +08:00
{
2008-07-14 22:43:47 +08:00
Error ( " Raw file size mismatch, expected %d bytes, found %ld " , size , statbuf . st_size ) ;
2005-11-30 01:51:06 +08:00
return ( false ) ;
}
2008-12-06 04:55:58 +08:00
if ( fread ( buffer , size , 1 , infile ) < 1 )
{
Fatal ( " Unable to read from '%s': %s " , filename , strerror ( errno ) ) ;
return ( false ) ;
}
2005-11-30 01:51:06 +08:00
fclose ( infile ) ;
return ( true ) ;
}
bool Image : : WriteRaw ( const char * filename ) const
{
FILE * outfile ;
if ( ( outfile = fopen ( filename , " wb " ) ) = = NULL )
{
2008-07-14 22:43:47 +08:00
Error ( " Can't open %s: %s " , filename , strerror ( errno ) ) ;
2005-11-30 01:51:06 +08:00
return ( false ) ;
}
2009-05-08 17:47:37 +08:00
if ( fwrite ( buffer , size , 1 , outfile ) ! = 1 )
2008-12-06 04:55:58 +08:00
{
Error ( " Unable to write to '%s': %s " , filename , strerror ( errno ) ) ;
return ( false ) ;
}
2005-11-30 01:51:06 +08:00
fclose ( outfile ) ;
return ( true ) ;
}
2005-10-18 05:45:06 +08:00
bool Image : : ReadJpeg ( const char * filename )
2003-03-26 19:57:29 +08:00
{
2005-11-22 18:41:50 +08:00
struct jpeg_decompress_struct * cinfo = jpg_dcinfo ;
2005-10-18 05:45:06 +08:00
2005-11-22 18:41:50 +08:00
if ( ! cinfo )
2005-11-20 03:41:06 +08:00
{
2005-11-22 18:41:50 +08:00
cinfo = jpg_dcinfo = new jpeg_decompress_struct ;
cinfo - > err = jpeg_std_error ( & jpg_err . pub ) ;
2006-10-19 01:08:10 +08:00
jpg_err . pub . error_exit = zm_jpeg_error_exit ;
jpg_err . pub . emit_message = zm_jpeg_emit_message ;
2005-11-22 18:41:50 +08:00
jpeg_create_decompress ( cinfo ) ;
2005-11-20 03:41:06 +08:00
}
2003-03-26 19:57:29 +08:00
2005-11-20 03:41:06 +08:00
FILE * infile ;
if ( ( infile = fopen ( filename , " rb " ) ) = = NULL )
2003-03-26 19:57:29 +08:00
{
2008-07-14 22:43:47 +08:00
Error ( " Can't open %s: %s " , filename , strerror ( errno ) ) ;
2005-10-18 05:45:06 +08:00
return ( false ) ;
2003-03-26 19:57:29 +08:00
}
2005-10-18 05:45:06 +08:00
2005-11-22 18:41:50 +08:00
if ( setjmp ( jpg_err . setjmp_buffer ) )
2005-10-18 05:45:06 +08:00
{
2005-11-22 18:41:50 +08:00
jpeg_abort_decompress ( cinfo ) ;
2005-10-18 05:45:06 +08:00
fclose ( infile ) ;
return ( false ) ;
}
2005-11-22 18:41:50 +08:00
jpeg_stdio_src ( cinfo , infile ) ;
2003-03-26 19:57:29 +08:00
2005-11-22 18:41:50 +08:00
jpeg_read_header ( cinfo , TRUE ) ;
2003-03-26 19:57:29 +08:00
2005-11-22 18:41:50 +08:00
if ( cinfo - > image_width ! = width | | cinfo - > image_height ! = height | | cinfo - > num_components ! = colours )
{
width = cinfo - > image_width ;
height = cinfo - > image_height ;
2006-01-15 06:47:02 +08:00
pixels = width * height ;
2005-11-22 18:41:50 +08:00
colours = cinfo - > num_components ;
2006-05-08 20:46:53 +08:00
if ( ! ( colours = = 1 | | colours = = 3 ) )
{
2008-07-14 22:43:47 +08:00
Error ( " Unexpected colours (%d) when reading jpeg image " , colours ) ;
2006-05-08 20:46:53 +08:00
jpeg_abort_decompress ( cinfo ) ;
fclose ( infile ) ;
return ( false ) ;
}
2007-08-30 02:11:09 +08:00
size = width * height * colours ;
if ( ! buffer | | allocation < size )
2005-11-22 18:41:50 +08:00
{
2007-08-30 02:11:09 +08:00
allocation = size ;
2005-11-22 18:41:50 +08:00
delete [ ] buffer ;
2011-02-15 19:18:41 +08:00
buffer = new uint8_t [ allocation ] ;
2005-11-22 18:41:50 +08:00
}
}
2003-03-26 19:57:29 +08:00
2005-11-22 18:41:50 +08:00
jpeg_start_decompress ( cinfo ) ;
2003-03-26 19:57:29 +08:00
JSAMPROW row_pointer ; /* pointer to a single row */
int row_stride = width * colours ; /* physical row width in buffer */
2005-11-22 18:41:50 +08:00
while ( cinfo - > output_scanline < cinfo - > output_height )
2003-03-26 19:57:29 +08:00
{
2005-11-22 18:41:50 +08:00
row_pointer = & buffer [ cinfo - > output_scanline * row_stride ] ;
jpeg_read_scanlines ( cinfo , & row_pointer , 1 ) ;
2003-03-26 19:57:29 +08:00
}
2005-11-22 18:41:50 +08:00
jpeg_finish_decompress ( cinfo ) ;
2003-03-26 19:57:29 +08:00
fclose ( infile ) ;
2005-10-18 05:45:06 +08:00
return ( true ) ;
2003-03-26 19:57:29 +08:00
}
2005-11-19 01:26:12 +08:00
bool Image : : WriteJpeg ( const char * filename , int quality_override ) const
2003-03-26 19:57:29 +08:00
{
2005-05-16 17:27:06 +08:00
if ( config . colour_jpeg_files & & colours = = 1 )
2003-04-14 21:06:03 +08:00
{
2003-04-15 22:14:56 +08:00
Image temp_image ( * this ) ;
temp_image . Colourise ( ) ;
2009-05-26 02:03:46 +08:00
return ( temp_image . WriteJpeg ( filename , quality_override ) ) ;
2003-04-14 21:06:03 +08:00
}
2005-11-22 18:41:50 +08:00
int quality = quality_override ? quality_override : config . jpeg_file_quality ;
struct jpeg_compress_struct * cinfo = jpg_ccinfo [ quality ] ;
2005-11-20 03:41:06 +08:00
2005-11-22 18:41:50 +08:00
if ( ! cinfo )
2005-11-20 03:41:06 +08:00
{
2005-11-22 18:41:50 +08:00
cinfo = jpg_ccinfo [ quality ] = new jpeg_compress_struct ;
cinfo - > err = jpeg_std_error ( & jpg_err . pub ) ;
2006-10-19 01:08:10 +08:00
jpg_err . pub . error_exit = zm_jpeg_error_exit ;
jpg_err . pub . emit_message = zm_jpeg_emit_message ;
2005-11-22 18:41:50 +08:00
jpeg_create_compress ( cinfo ) ;
2005-11-20 03:41:06 +08:00
}
2003-03-26 19:57:29 +08:00
FILE * outfile ;
2005-11-20 03:41:06 +08:00
if ( ( outfile = fopen ( filename , " wb " ) ) = = NULL )
2003-03-26 19:57:29 +08:00
{
2008-07-14 22:43:47 +08:00
Error ( " Can't open %s: %s " , filename , strerror ( errno ) ) ;
2005-10-18 05:45:06 +08:00
return ( false ) ;
2003-03-26 19:57:29 +08:00
}
2005-11-22 18:41:50 +08:00
jpeg_stdio_dest ( cinfo , outfile ) ;
2003-03-26 19:57:29 +08:00
2005-11-22 18:41:50 +08:00
cinfo - > image_width = width ; /* image width and height, in pixels */
cinfo - > image_height = height ;
cinfo - > input_components = colours ; /* # of color components per pixel */
2003-03-26 19:57:29 +08:00
if ( colours = = 1 )
{
2005-11-22 18:41:50 +08:00
cinfo - > in_color_space = JCS_GRAYSCALE ; /* colorspace of input image */
2003-03-26 19:57:29 +08:00
}
else
{
2005-11-22 18:41:50 +08:00
cinfo - > in_color_space = JCS_RGB ; /* colorspace of input image */
2005-11-20 03:41:06 +08:00
}
2005-11-22 18:41:50 +08:00
jpeg_set_defaults ( cinfo ) ;
2006-03-30 21:46:48 +08:00
jpeg_set_quality ( cinfo , quality , false ) ;
2005-11-22 18:41:50 +08:00
cinfo - > dct_method = JDCT_FASTEST ;
2005-11-20 03:41:06 +08:00
2005-11-22 18:41:50 +08:00
jpeg_start_compress ( cinfo , TRUE ) ;
if ( config . add_jpeg_comments & & text [ 0 ] )
2005-11-20 02:43:46 +08:00
{
2005-11-22 18:41:50 +08:00
jpeg_write_marker ( cinfo , JPEG_COM , ( const JOCTET * ) text , strlen ( text ) ) ;
2005-11-20 02:43:46 +08:00
}
2003-03-26 19:57:29 +08:00
JSAMPROW row_pointer ; /* pointer to a single row */
2005-11-22 18:41:50 +08:00
int row_stride = cinfo - > image_width * cinfo - > input_components ; /* physical row width in buffer */
while ( cinfo - > next_scanline < cinfo - > image_height )
2003-03-26 19:57:29 +08:00
{
2005-11-22 18:41:50 +08:00
row_pointer = & buffer [ cinfo - > next_scanline * row_stride ] ;
jpeg_write_scanlines ( cinfo , & row_pointer , 1 ) ;
2003-03-26 19:57:29 +08:00
}
2005-11-22 18:41:50 +08:00
jpeg_finish_compress ( cinfo ) ;
2003-03-26 19:57:29 +08:00
fclose ( outfile ) ;
2005-10-18 05:45:06 +08:00
return ( true ) ;
2003-03-26 19:57:29 +08:00
}
2006-01-20 23:27:48 +08:00
bool Image : : DecodeJpeg ( const JOCTET * inbuffer , int inbuffer_size )
2003-03-26 19:57:29 +08:00
{
2005-11-22 18:41:50 +08:00
struct jpeg_decompress_struct * cinfo = jpg_dcinfo ;
2005-10-18 05:45:06 +08:00
2005-11-22 18:41:50 +08:00
if ( ! cinfo )
2005-11-20 03:41:06 +08:00
{
2005-11-22 18:41:50 +08:00
cinfo = jpg_dcinfo = new jpeg_decompress_struct ;
cinfo - > err = jpeg_std_error ( & jpg_err . pub ) ;
2006-10-19 01:08:10 +08:00
jpg_err . pub . error_exit = zm_jpeg_error_exit ;
jpg_err . pub . emit_message = zm_jpeg_emit_message ;
2005-11-22 18:41:50 +08:00
jpeg_create_decompress ( cinfo ) ;
2005-11-20 03:41:06 +08:00
}
2003-03-26 19:57:29 +08:00
2005-11-22 18:41:50 +08:00
if ( setjmp ( jpg_err . setjmp_buffer ) )
2005-10-18 05:45:06 +08:00
{
2005-11-22 18:41:50 +08:00
jpeg_abort_decompress ( cinfo ) ;
2005-10-18 05:45:06 +08:00
return ( false ) ;
}
2010-01-20 22:43:54 +08:00
zm_jpeg_mem_src ( cinfo , inbuffer , inbuffer_size ) ;
2003-03-26 19:57:29 +08:00
2005-11-22 18:41:50 +08:00
jpeg_read_header ( cinfo , TRUE ) ;
2003-03-26 19:57:29 +08:00
2005-11-22 18:41:50 +08:00
if ( cinfo - > image_width ! = width | | cinfo - > image_height ! = height | | cinfo - > num_components ! = colours )
{
width = cinfo - > image_width ;
height = cinfo - > image_height ;
2006-01-15 06:47:02 +08:00
pixels = width * height ;
2005-11-22 18:41:50 +08:00
colours = cinfo - > num_components ;
2006-05-08 20:46:53 +08:00
if ( ! ( colours = = 1 | | colours = = 3 ) )
{
2008-07-14 22:43:47 +08:00
Error ( " Unexpected colours (%d) when decoding jpeg image " , colours ) ;
2006-05-08 20:46:53 +08:00
jpeg_abort_decompress ( cinfo ) ;
return ( false ) ;
}
2007-08-30 02:11:09 +08:00
size = width * height * colours ;
if ( ! buffer | | allocation < size )
2005-11-22 18:41:50 +08:00
{
2007-08-30 02:11:09 +08:00
allocation = size ;
2005-11-22 18:41:50 +08:00
delete [ ] buffer ;
2011-02-15 19:18:41 +08:00
buffer = new uint8_t [ allocation ] ;
2005-11-22 18:41:50 +08:00
}
}
2003-03-26 19:57:29 +08:00
2005-11-22 18:41:50 +08:00
jpeg_start_decompress ( cinfo ) ;
2003-03-26 19:57:29 +08:00
JSAMPROW row_pointer ; /* pointer to a single row */
int row_stride = width * colours ; /* physical row width in buffer */
2005-11-22 18:41:50 +08:00
while ( cinfo - > output_scanline < cinfo - > output_height )
2003-03-26 19:57:29 +08:00
{
2005-11-22 18:41:50 +08:00
row_pointer = & buffer [ cinfo - > output_scanline * row_stride ] ;
jpeg_read_scanlines ( cinfo , & row_pointer , 1 ) ;
2003-03-26 19:57:29 +08:00
}
2005-11-22 18:41:50 +08:00
jpeg_finish_decompress ( cinfo ) ;
2005-10-18 05:45:06 +08:00
return ( true ) ;
2003-03-26 19:57:29 +08:00
}
2005-11-19 01:26:12 +08:00
bool Image : : EncodeJpeg ( JOCTET * outbuffer , int * outbuffer_size , int quality_override ) const
2003-03-26 19:57:29 +08:00
{
2005-05-16 17:27:06 +08:00
if ( config . colour_jpeg_files & & colours = = 1 )
2003-07-10 17:54:17 +08:00
{
Image temp_image ( * this ) ;
temp_image . Colourise ( ) ;
2005-11-20 02:35:31 +08:00
return ( temp_image . EncodeJpeg ( outbuffer , outbuffer_size , quality_override ) ) ;
2003-07-10 17:54:17 +08:00
}
2007-09-18 18:58:03 +08:00
int quality = quality_override ? quality_override : config . jpeg_stream_quality ;
2003-03-26 19:57:29 +08:00
2005-11-22 18:41:50 +08:00
struct jpeg_compress_struct * cinfo = jpg_ccinfo [ quality ] ;
if ( ! cinfo )
2005-11-20 03:41:06 +08:00
{
2005-11-22 18:41:50 +08:00
cinfo = jpg_ccinfo [ quality ] = new jpeg_compress_struct ;
cinfo - > err = jpeg_std_error ( & jpg_err . pub ) ;
2006-10-19 01:08:10 +08:00
jpg_err . pub . error_exit = zm_jpeg_error_exit ;
jpg_err . pub . emit_message = zm_jpeg_emit_message ;
2005-11-22 18:41:50 +08:00
jpeg_create_compress ( cinfo ) ;
2005-11-20 03:41:06 +08:00
}
2010-01-20 22:43:54 +08:00
zm_jpeg_mem_dest ( cinfo , outbuffer , outbuffer_size ) ;
2003-03-26 19:57:29 +08:00
2005-11-22 18:41:50 +08:00
cinfo - > image_width = width ; /* image width and height, in pixels */
cinfo - > image_height = height ;
cinfo - > input_components = colours ; /* # of color components per pixel */
2003-03-26 19:57:29 +08:00
if ( colours = = 1 )
{
2005-11-22 18:41:50 +08:00
cinfo - > in_color_space = JCS_GRAYSCALE ; /* colorspace of input image */
2003-03-26 19:57:29 +08:00
}
else
{
2005-11-22 18:41:50 +08:00
cinfo - > in_color_space = JCS_RGB ; /* colorspace of input image */
2005-11-20 03:41:06 +08:00
}
2005-11-22 18:41:50 +08:00
jpeg_set_defaults ( cinfo ) ;
2006-03-30 21:46:48 +08:00
jpeg_set_quality ( cinfo , quality , false ) ;
2005-11-22 18:41:50 +08:00
cinfo - > dct_method = JDCT_FASTEST ;
2005-11-20 03:41:06 +08:00
2005-11-22 18:41:50 +08:00
jpeg_start_compress ( cinfo , TRUE ) ;
2003-03-26 19:57:29 +08:00
JSAMPROW row_pointer ; /* pointer to a single row */
2005-11-22 18:41:50 +08:00
int row_stride = cinfo - > image_width * cinfo - > input_components ; /* physical row width in buffer */
while ( cinfo - > next_scanline < cinfo - > image_height )
2003-03-26 19:57:29 +08:00
{
2005-11-22 18:41:50 +08:00
row_pointer = & buffer [ cinfo - > next_scanline * row_stride ] ;
jpeg_write_scanlines ( cinfo , & row_pointer , 1 ) ;
2003-03-26 19:57:29 +08:00
}
2005-11-22 18:41:50 +08:00
jpeg_finish_compress ( cinfo ) ;
2005-10-18 05:45:06 +08:00
return ( true ) ;
2003-03-26 19:57:29 +08:00
}
2009-03-20 20:39:29 +08:00
# if HAVE_ZLIB_H
2006-01-20 23:27:48 +08:00
bool Image : : Unzip ( const Bytef * inbuffer , unsigned long inbuffer_size )
{
unsigned long zip_size = size ;
int result = uncompress ( buffer , & zip_size , inbuffer , inbuffer_size ) ;
if ( result ! = Z_OK )
{
2008-07-14 22:43:47 +08:00
Error ( " Unzip failed, result = %d " , result ) ;
2006-01-20 23:27:48 +08:00
return ( false ) ;
}
if ( zip_size ! = size )
{
2008-07-14 22:43:47 +08:00
Error ( " Unzip failed, size mismatch, expected %d bytes, got %ld " , size , zip_size ) ;
2006-01-20 23:27:48 +08:00
return ( false ) ;
}
return ( true ) ;
}
bool Image : : Zip ( Bytef * outbuffer , unsigned long * outbuffer_size , int compression_level ) const
{
int result = compress2 ( outbuffer , outbuffer_size , buffer , size , compression_level ) ;
if ( result ! = Z_OK )
{
2008-07-14 22:43:47 +08:00
Error ( " Zip failed, result = %d " , result ) ;
2006-01-20 23:27:48 +08:00
return ( false ) ;
}
return ( true ) ;
}
2009-03-20 20:39:29 +08:00
# endif // HAVE_ZLIB_H
2006-01-20 23:27:48 +08:00
2005-12-02 00:24:25 +08:00
bool Image : : Crop ( int lo_x , int lo_y , int hi_x , int hi_y )
{
2007-08-30 02:11:09 +08:00
int new_width = ( hi_x - lo_x ) + 1 ;
int new_height = ( hi_y - lo_y ) + 1 ;
2005-12-02 00:24:25 +08:00
if ( lo_x > hi_x | | lo_y > hi_y )
{
2008-07-14 22:43:47 +08:00
Error ( " Invalid or reversed crop region %d,%d -> %d,%d " , lo_x , lo_y , hi_x , hi_y ) ;
2005-12-02 00:24:25 +08:00
return ( false ) ;
}
if ( lo_x < 0 | | hi_x > ( width - 1 ) | | ( lo_y < 0 | | hi_y > ( height - 1 ) ) )
{
2008-07-14 22:43:47 +08:00
Error ( " Attempting to crop outside image, %d,%d -> %d,%d not in %d,%d " , lo_x , lo_y , hi_x , hi_y , width - 1 , height - 1 ) ;
2005-12-02 00:24:25 +08:00
return ( false ) ;
}
if ( new_width = = width & & new_height = = height )
{
return ( true ) ;
}
int new_size = new_width * new_height * colours ;
2011-02-15 19:18:41 +08:00
uint8_t * new_buffer = new uint8_t [ new_size ] ;
2005-12-02 00:24:25 +08:00
int new_stride = new_width * colours ;
for ( int y = lo_y , ny = 0 ; y < = hi_y ; y + + , ny + + )
{
unsigned char * pbuf = & buffer [ ( ( y * width ) + lo_x ) * colours ] ;
unsigned char * pnbuf = & new_buffer [ ( ny * new_width ) * colours ] ;
memcpy ( pnbuf , pbuf , new_stride ) ;
}
2007-08-30 02:11:09 +08:00
if ( allocation )
2005-12-02 00:24:25 +08:00
{
delete [ ] buffer ;
}
width = new_width ;
height = new_height ;
2006-01-15 06:47:02 +08:00
pixels = width * height ;
2007-08-30 02:11:09 +08:00
size = allocation = new_size ;
2005-12-02 00:24:25 +08:00
buffer = new_buffer ;
if ( blend_buffer )
{
delete [ ] blend_buffer ;
blend_buffer = 0 ;
}
return ( true ) ;
}
2007-08-30 02:11:09 +08:00
bool Image : : Crop ( const Box & limits )
{
return ( Crop ( limits . LoX ( ) , limits . LoY ( ) , limits . HiX ( ) , limits . HiY ( ) ) ) ;
}
2003-03-26 19:57:29 +08:00
void Image : : Overlay ( const Image & image )
{
2006-05-08 20:46:53 +08:00
if ( ! ( width = = image . width & & height = = image . height ) )
{
2009-10-14 18:01:46 +08:00
Panic ( " Attempt to overlay different sized images, expected %dx%d, got %dx%d " , width , height , image . width , image . height ) ;
2006-05-08 20:46:53 +08:00
}
2003-03-26 19:57:29 +08:00
unsigned char * pdest = buffer ;
unsigned char * psrc = image . buffer ;
if ( colours = = 1 )
{
if ( image . colours = = 1 )
{
while ( pdest < ( buffer + size ) )
{
if ( * psrc )
{
* pdest = * psrc ;
}
pdest + + ;
psrc + + ;
}
}
else
{
Colourise ( ) ;
pdest = buffer ;
while ( pdest < ( buffer + size ) )
{
if ( RED ( psrc ) | | GREEN ( psrc ) | | BLUE ( psrc ) )
{
RED ( pdest ) = RED ( psrc ) ;
GREEN ( pdest ) = GREEN ( psrc ) ;
BLUE ( pdest ) = BLUE ( psrc ) ;
}
psrc + = 3 ;
pdest + = 3 ;
}
}
}
else
{
if ( image . colours = = 1 )
{
while ( pdest < ( buffer + size ) )
{
if ( * psrc )
{
RED ( pdest ) = GREEN ( pdest ) = BLUE ( pdest ) = * psrc + + ;
}
pdest + = 3 ;
}
}
else
{
while ( pdest < ( buffer + size ) )
{
if ( RED ( psrc ) | | GREEN ( psrc ) | | BLUE ( psrc ) )
{
RED ( pdest ) = RED ( psrc ) ;
GREEN ( pdest ) = GREEN ( psrc ) ;
BLUE ( pdest ) = BLUE ( psrc ) ;
}
psrc + = 3 ;
pdest + = 3 ;
}
}
}
}
2007-08-30 02:11:09 +08:00
void Image : : Overlay ( const Image & image , int x , int y )
{
if ( ! ( width < image . width | | height < image . height ) )
{
2009-10-14 18:01:46 +08:00
Panic ( " Attempt to overlay image too big for destination, %dx%d > %dx%d " , image . width , image . height , width , height ) ;
2007-08-30 02:11:09 +08:00
}
if ( ! ( width < ( x + image . width ) | | height < ( y + image . height ) ) )
{
2009-10-14 18:01:46 +08:00
Panic ( " Attempt to overlay image outside of destination bounds, %dx%d @ %dx%d > %dx%d " , image . width , image . height , x , y , width , height ) ;
2007-08-30 02:11:09 +08:00
}
if ( ! ( colours = = image . colours ) )
{
2009-10-14 18:01:46 +08:00
Panic ( " Attempt to partial overlay differently coloured images, expected %d, got %d " , colours , image . colours ) ;
2007-08-30 02:11:09 +08:00
}
int lo_x = x ;
int lo_y = y ;
int hi_x = ( x + image . width ) - 1 ;
int hi_y = ( y + image . height - 1 ) ;
if ( colours = = 1 )
{
unsigned char * psrc = image . buffer ;
for ( int y = lo_y ; y < = hi_y ; y + + )
{
unsigned char * pdest = & buffer [ ( y * width ) + lo_x ] ;
for ( int x = lo_x ; x < = hi_x ; x + + )
{
* pdest + + = * psrc + + ;
}
}
}
else if ( colours = = 3 )
{
unsigned char * psrc = image . buffer ;
for ( int y = lo_y ; y < = hi_y ; y + + )
{
unsigned char * pdest = & buffer [ colours * ( ( y * width ) + lo_x ) ] ;
for ( int x = lo_x ; x < = hi_x ; x + + )
{
* pdest + + = * psrc + + ;
* pdest + + = * psrc + + ;
* pdest + + = * psrc + + ;
}
}
}
}
2003-03-26 19:57:29 +08:00
void Image : : Blend ( const Image & image , int transparency ) const
{
2006-05-08 20:46:53 +08:00
if ( ! ( width = = image . width & & height = = image . height & & colours = = image . colours ) )
{
2009-10-14 18:01:46 +08:00
Panic ( " Attempt to blend different sized images, expected %dx%dx%d, got %dx%dx%d " , width , height , colours , image . width , image . height , image . colours ) ;
2006-05-08 20:46:53 +08:00
}
2003-03-26 19:57:29 +08:00
2005-05-16 17:27:06 +08:00
if ( config . fast_image_blends )
2003-04-23 07:16:57 +08:00
{
2004-02-16 03:53:10 +08:00
BlendTablePtr blend_ptr = GetBlendTable ( transparency ) ;
2003-04-23 07:16:57 +08:00
2011-02-15 19:18:41 +08:00
uint8_t * psrc = image . buffer ;
uint8_t * pdest = buffer ;
2004-02-16 03:53:10 +08:00
while ( pdest < ( buffer + size ) )
2003-04-23 07:16:57 +08:00
{
2004-02-16 03:53:10 +08:00
* pdest + + = ( * blend_ptr ) [ * pdest ] [ * psrc + + ] ;
2003-04-23 07:16:57 +08:00
}
}
2004-02-16 03:53:10 +08:00
else
{
if ( ! blend_buffer )
{
2011-02-15 19:18:41 +08:00
blend_buffer = new uint16_t [ size ] ;
2004-02-16 03:53:10 +08:00
2011-02-15 19:18:41 +08:00
uint16_t * pb = blend_buffer ;
uint8_t * p = buffer ;
2004-02-16 03:53:10 +08:00
while ( p < ( buffer + size ) )
{
2011-02-15 19:18:41 +08:00
* pb + + = ( uint16_t ) ( ( * p + + ) < < 8 ) ;
2004-02-16 03:53:10 +08:00
}
}
2003-04-23 07:16:57 +08:00
2011-02-15 19:18:41 +08:00
uint8_t * psrc = image . buffer ;
uint8_t * pdest = buffer ;
uint16_t * pblend = blend_buffer ;
2004-02-16 03:53:10 +08:00
int opacity = 100 - transparency ;
2003-03-26 19:57:29 +08:00
2004-02-16 03:53:10 +08:00
while ( pdest < ( buffer + size ) )
{
2011-02-15 19:18:41 +08:00
* pblend = ( uint16_t ) ( ( ( * pblend * opacity ) + ( ( ( * psrc + + ) < < 8 ) * transparency ) ) / 100 ) ;
* pdest + + = ( uint8_t ) ( ( * pblend + + ) > > 8 ) ;
2004-02-16 03:53:10 +08:00
}
2003-03-26 19:57:29 +08:00
}
}
Image * Image : : Merge ( int n_images , Image * images [ ] )
{
if ( n_images < = 0 ) return ( 0 ) ;
if ( n_images = = 1 ) return ( new Image ( * images [ 0 ] ) ) ;
int width = images [ 0 ] - > width ;
int height = images [ 0 ] - > height ;
int colours = images [ 0 ] - > colours ;
for ( int i = 1 ; i < n_images ; i + + )
{
2006-05-08 20:46:53 +08:00
if ( ! ( width = = images [ i ] - > width & & height = = images [ i ] - > height & & colours = = images [ i ] - > colours ) )
{
2009-10-14 18:01:46 +08:00
Panic ( " Attempt to merge different sized images, expected %dx%dx%d, got %dx%dx%d, for image %d " , width , height , colours , images [ i ] - > width , images [ i ] - > height , images [ i ] - > colours , i ) ;
2006-05-08 20:46:53 +08:00
}
2003-03-26 19:57:29 +08:00
}
Image * result = new Image ( width , height , images [ 0 ] - > colours ) ;
int size = result - > size ;
for ( int i = 0 ; i < size ; i + + )
{
int total = 0 ;
2011-02-15 19:18:41 +08:00
uint8_t * pdest = result - > buffer ;
2003-03-26 19:57:29 +08:00
for ( int j = 0 ; j < n_images ; j + + )
{
2011-02-15 19:18:41 +08:00
uint8_t * psrc = images [ j ] - > buffer ;
2003-03-26 19:57:29 +08:00
total + = * psrc ;
psrc + + ;
}
* pdest = total / n_images ;
pdest + + ;
}
return ( result ) ;
}
Image * Image : : Merge ( int n_images , Image * images [ ] , double weight )
{
if ( n_images < = 0 ) return ( 0 ) ;
if ( n_images = = 1 ) return ( new Image ( * images [ 0 ] ) ) ;
int width = images [ 0 ] - > width ;
int height = images [ 0 ] - > height ;
int colours = images [ 0 ] - > colours ;
for ( int i = 1 ; i < n_images ; i + + )
{
2006-05-08 20:46:53 +08:00
if ( ! ( width = = images [ i ] - > width & & height = = images [ i ] - > height & & colours = = images [ i ] - > colours ) )
{
2009-10-14 18:01:46 +08:00
Panic ( " Attempt to merge different sized images, expected %dx%dx%d, got %dx%dx%d, for image %d " , width , height , colours , images [ i ] - > width , images [ i ] - > height , images [ i ] - > colours , i ) ;
2006-05-08 20:46:53 +08:00
}
2003-03-26 19:57:29 +08:00
}
Image * result = new Image ( * images [ 0 ] ) ;
int size = result - > size ;
double factor = 1.0 * weight ;
for ( int i = 1 ; i < n_images ; i + + )
{
2011-02-15 19:18:41 +08:00
uint8_t * pdest = result - > buffer ;
uint8_t * psrc = images [ i ] - > buffer ;
2003-03-26 19:57:29 +08:00
for ( int j = 0 ; j < size ; j + + )
{
2011-02-15 19:18:41 +08:00
* pdest = ( uint8_t ) ( ( ( * pdest ) * ( 1.0 - factor ) ) + ( ( * psrc ) * factor ) ) ;
2003-03-26 19:57:29 +08:00
pdest + + ;
psrc + + ;
}
factor * = weight ;
}
return ( result ) ;
}
Image * Image : : Highlight ( int n_images , Image * images [ ] , const Rgb threshold , const Rgb ref_colour )
{
if ( n_images < = 0 ) return ( 0 ) ;
if ( n_images = = 1 ) return ( new Image ( * images [ 0 ] ) ) ;
int width = images [ 0 ] - > width ;
int height = images [ 0 ] - > height ;
int colours = images [ 0 ] - > colours ;
for ( int i = 1 ; i < n_images ; i + + )
{
2006-05-08 20:46:53 +08:00
if ( ! ( width = = images [ i ] - > width & & height = = images [ i ] - > height & & colours = = images [ i ] - > colours ) )
{
2009-10-14 18:01:46 +08:00
Panic ( " Attempt to highlight different sized images, expected %dx%dx%d, got %dx%dx%d, for image %d " , width , height , colours , images [ i ] - > width , images [ i ] - > height , images [ i ] - > colours , i ) ;
2006-05-08 20:46:53 +08:00
}
2003-03-26 19:57:29 +08:00
}
Image * result = new Image ( width , height , images [ 0 ] - > colours ) ;
int size = result - > size ;
for ( int c = 0 ; c < 3 ; c + + )
{
for ( int i = 0 ; i < size ; i + + )
{
int count = 0 ;
2011-02-15 19:18:41 +08:00
uint8_t * pdest = result - > buffer + c ;
2003-03-26 19:57:29 +08:00
for ( int j = 0 ; j < n_images ; j + + )
{
2011-02-15 19:18:41 +08:00
uint8_t * psrc = images [ j ] - > buffer + c ;
2003-03-26 19:57:29 +08:00
2003-04-07 18:56:38 +08:00
if ( ( unsigned ) abs ( ( * psrc ) - RGB_VAL ( ref_colour , c ) ) > = RGB_VAL ( threshold , c ) )
2003-03-26 19:57:29 +08:00
{
count + + ;
}
psrc + = 3 ;
}
* pdest = ( count * 255 ) / n_images ;
pdest + = 3 ;
}
}
return ( result ) ;
}
2003-04-16 21:02:15 +08:00
Image * Image : : Delta ( const Image & image ) const
2003-03-26 19:57:29 +08:00
{
2006-05-08 20:46:53 +08:00
if ( ! ( width = = image . width & & height = = image . height & & colours = = image . colours ) )
{
2009-10-14 18:01:46 +08:00
Panic ( " Attempt to get delta of different sized images, expected %dx%dx%d, got %dx%dx%d " , width , height , colours , image . width , image . height , image . colours ) ;
2006-05-08 20:46:53 +08:00
}
2003-03-26 19:57:29 +08:00
Image * result = new Image ( width , height , 1 ) ;
unsigned char * psrc = buffer ;
unsigned char * pref = image . buffer ;
unsigned char * pdiff = result - > buffer ;
if ( colours = = 1 )
{
2003-04-16 21:02:15 +08:00
while ( psrc < ( buffer + size ) )
2003-03-26 19:57:29 +08:00
{
2003-04-16 21:02:15 +08:00
//*pdiff++ = abs( *psrc++ - *pref++ );
2004-02-16 03:53:10 +08:00
//*pdiff++ = ABSDIFF( *psrc, *pref );
* pdiff + + = abs_table [ * psrc + + - * pref + + ] ;
//psrc++;
//pref++;
2003-03-26 19:57:29 +08:00
}
}
else
{
2004-02-16 03:53:10 +08:00
register int red , green , blue ;
2003-04-16 21:02:15 +08:00
while ( psrc < ( buffer + size ) )
2003-03-26 19:57:29 +08:00
{
2005-05-16 17:27:06 +08:00
if ( config . y_image_deltas )
2004-02-16 03:53:10 +08:00
{
2008-07-14 22:43:47 +08:00
//Info( "RS:%d, RR: %d", *psrc, *pref );
2004-02-16 03:53:10 +08:00
red = y_r_table [ * psrc + + - * pref + + ] ;
2008-07-14 22:43:47 +08:00
//Info( "GS:%d, GR: %d", *psrc, *pref );
2004-02-16 03:53:10 +08:00
green = y_g_table [ * psrc + + - * pref + + ] ;
2008-07-14 22:43:47 +08:00
//Info( "BS:%d, BR: %d", *psrc, *pref );
2004-02-16 03:53:10 +08:00
blue = y_b_table [ * psrc + + - * pref + + ] ;
2008-07-14 22:43:47 +08:00
//Info( "R:%d, G:%d, B:%d, D:%d", red, green, blue, abs_table[red + green + blue] );
2004-02-16 03:53:10 +08:00
* pdiff + + = abs_table [ red + green + blue ] ;
}
else
2003-03-26 19:57:29 +08:00
{
2004-02-16 03:53:10 +08:00
red = abs_table [ * psrc + + - * pref + + ] ;
green = abs_table [ * psrc + + - * pref + + ] ;
blue = abs_table [ * psrc + + - * pref + + ] ;
2003-04-17 06:03:08 +08:00
2003-04-16 21:02:15 +08:00
// This is uses an RMS function, all floating point and
// rather too slow
2011-02-15 19:18:41 +08:00
//*pdiff++ = (uint8_t)sqrt((red*red + green*green + blue*blue)/3);
2003-04-16 21:02:15 +08:00
// This just uses the average difference, much faster
2011-02-15 19:18:41 +08:00
* pdiff + + = ( uint8_t ) ( ( red + green + blue ) / 3 ) ;
2003-03-26 19:57:29 +08:00
}
}
}
return ( result ) ;
}
2007-08-30 02:11:09 +08:00
const Coord Image : : centreCoord ( const char * text )
{
int index = 0 ;
int line_no = 0 ;
int text_len = strlen ( text ) ;
int line_len = 0 ;
int max_line_len = 0 ;
const char * line = text ;
while ( ( index < text_len ) & & ( line_len = strcspn ( line , " \n " ) ) )
{
if ( line_len > max_line_len )
max_line_len = line_len ;
index + = line_len ;
while ( text [ index ] = = ' \n ' )
{
index + + ;
}
line = text + index ;
line_no + + ;
}
int x = ( width - ( max_line_len * CHAR_WIDTH ) ) / 2 ;
int y = ( height - ( line_no * LINE_HEIGHT ) ) / 2 ;
return ( Coord ( x , y ) ) ;
}
2006-11-16 19:34:53 +08:00
void Image : : Annotate ( const char * p_text , const Coord & coord , const Rgb fg_colour , const Rgb bg_colour )
2003-03-26 19:57:29 +08:00
{
2005-11-20 02:43:46 +08:00
strncpy ( text , p_text , sizeof ( text ) ) ;
2006-11-16 19:34:53 +08:00
int index = 0 ;
int line_no = 0 ;
2004-02-18 23:35:33 +08:00
int text_len = strlen ( text ) ;
2006-11-16 19:34:53 +08:00
int line_len = 0 ;
const char * line = text ;
char fg_r_col = RGB_RED_VAL ( fg_colour ) ;
char fg_g_col = RGB_GREEN_VAL ( fg_colour ) ;
char fg_b_col = RGB_BLUE_VAL ( fg_colour ) ;
char fg_bw_col = ( fg_r_col + fg_g_col + fg_b_col ) / 3 ;
bool fg_trans = ( fg_colour = = RGB_TRANSPARENT ) ;
char bg_r_col = RGB_RED_VAL ( bg_colour ) ;
char bg_g_col = RGB_GREEN_VAL ( bg_colour ) ;
char bg_b_col = RGB_BLUE_VAL ( bg_colour ) ;
char bg_bw_col = ( bg_r_col + bg_g_col + bg_b_col ) / 3 ;
bool bg_trans = ( bg_colour = = RGB_TRANSPARENT ) ;
while ( ( index < text_len ) & & ( line_len = strcspn ( line , " \n " ) ) )
{
int line_width = line_len * CHAR_WIDTH ;
int lo_line_x = coord . X ( ) ;
int lo_line_y = coord . Y ( ) + ( line_no * LINE_HEIGHT ) ;
int min_line_x = 0 ;
int max_line_x = width - line_width ;
int min_line_y = 0 ;
2007-08-30 02:11:09 +08:00
int max_line_y = height - LINE_HEIGHT ;
2006-11-16 19:34:53 +08:00
if ( lo_line_x > max_line_x )
lo_line_x = max_line_x ;
if ( lo_line_x < min_line_x )
lo_line_x = min_line_x ;
if ( lo_line_y > max_line_y )
lo_line_y = max_line_y ;
if ( lo_line_y < min_line_y )
lo_line_y = min_line_y ;
int hi_line_x = lo_line_x + line_width ;
2007-08-30 02:11:09 +08:00
int hi_line_y = lo_line_y + LINE_HEIGHT ;
2006-11-16 19:34:53 +08:00
// Clip anything that runs off the right of the screen
if ( hi_line_x > width )
hi_line_x = width ;
if ( hi_line_y > height )
hi_line_y = height ;
if ( colours = = 1 )
{
unsigned char * ptr = & buffer [ ( lo_line_y * width ) + lo_line_x ] ;
for ( int y = lo_line_y , r = 0 ; y < hi_line_y & & r < CHAR_HEIGHT ; y + + , r + + , ptr + = width )
{
unsigned char * temp_ptr = ptr ;
for ( int x = lo_line_x , c = 0 ; x < hi_line_x & & c < line_len ; c + + )
{
int f = fontdata [ ( line [ c ] * CHAR_HEIGHT ) + r ] ;
for ( int i = 0 ; i < CHAR_WIDTH & & x < hi_line_x ; i + + , x + + , temp_ptr + + )
{
if ( f & ( 0x80 > > i ) )
{
if ( ! fg_trans )
* temp_ptr = fg_bw_col ;
}
else if ( ! bg_trans )
{
* temp_ptr = bg_bw_col ;
}
}
}
}
}
else
{
int wc = width * colours ;
unsigned char * ptr = & buffer [ ( ( lo_line_y * width ) + lo_line_x ) * colours ] ;
for ( int y = lo_line_y , r = 0 ; y < hi_line_y & & r < CHAR_HEIGHT ; y + + , r + + , ptr + = wc )
{
unsigned char * temp_ptr = ptr ;
for ( int x = lo_line_x , c = 0 ; x < hi_line_x & & c < line_len ; c + + )
{
int f = fontdata [ ( line [ c ] * CHAR_HEIGHT ) + r ] ;
for ( int i = 0 ; i < CHAR_WIDTH & & x < hi_line_x ; i + + , x + + , temp_ptr + = colours )
{
if ( f & ( 0x80 > > i ) )
{
if ( ! fg_trans )
{
RED ( temp_ptr ) = fg_r_col ;
GREEN ( temp_ptr ) = fg_g_col ;
BLUE ( temp_ptr ) = fg_b_col ;
}
}
else if ( ! bg_trans )
{
RED ( temp_ptr ) = bg_r_col ;
GREEN ( temp_ptr ) = bg_g_col ;
BLUE ( temp_ptr ) = bg_b_col ;
}
}
}
}
}
index + = line_len ;
while ( text [ index ] = = ' \n ' )
{
index + + ;
}
line = text + index ;
line_no + + ;
}
2003-03-26 19:57:29 +08:00
}
void Image : : Timestamp ( const char * label , const time_t when , const Coord & coord )
{
char time_text [ 64 ] ;
strftime ( time_text , sizeof ( time_text ) , " %y/%m/%d %H:%M:%S " , localtime ( & when ) ) ;
char text [ 64 ] ;
if ( label )
{
2004-04-20 00:02:17 +08:00
snprintf ( text , sizeof ( text ) , " %s - %s " , label , time_text ) ;
2003-03-26 19:57:29 +08:00
Annotate ( text , coord ) ;
}
else
{
Annotate ( time_text , coord ) ;
}
}
void Image : : Colourise ( )
{
if ( colours = = 1 )
{
colours = 3 ;
size = width * height * 3 ;
2011-02-15 19:18:41 +08:00
uint8_t * new_buffer = new uint8_t [ size ] ;
2003-03-26 19:57:29 +08:00
2011-02-15 19:18:41 +08:00
uint8_t * psrc = buffer ;
uint8_t * pdest = new_buffer ;
2003-03-26 19:57:29 +08:00
while ( pdest < ( new_buffer + size ) )
{
RED ( pdest ) = GREEN ( pdest ) = BLUE ( pdest ) = * psrc + + ;
pdest + = 3 ;
}
delete [ ] buffer ;
buffer = new_buffer ;
}
}
void Image : : DeColourise ( )
{
if ( colours = = 3 )
{
colours = 1 ;
size = width * height ;
2011-02-15 19:18:41 +08:00
uint8_t * psrc = buffer ;
uint8_t * pdest = buffer ;
2003-03-26 19:57:29 +08:00
while ( pdest < ( buffer + size ) )
{
2011-02-15 19:18:41 +08:00
* pdest + + = ( uint8_t ) sqrt ( ( RED ( psrc ) + GREEN ( psrc ) + BLUE ( psrc ) ) / 3 ) ;
2003-03-26 19:57:29 +08:00
psrc + = 3 ;
}
}
}
2005-11-30 01:51:06 +08:00
void Image : : Fill ( Rgb colour , const Box * limits )
{
2006-05-08 20:46:53 +08:00
if ( ! ( colours = = 1 | | colours = = 3 ) )
{
2009-10-14 18:01:46 +08:00
Panic ( " Attempt to fill image with unexpected colours %d " , colours ) ;
2006-05-08 20:46:53 +08:00
}
2005-11-30 01:51:06 +08:00
int lo_x = limits ? limits - > Lo ( ) . X ( ) : 0 ;
int lo_y = limits ? limits - > Lo ( ) . Y ( ) : 0 ;
int hi_x = limits ? limits - > Hi ( ) . X ( ) : width - 1 ;
int hi_y = limits ? limits - > Hi ( ) . Y ( ) : height - 1 ;
if ( colours = = 1 )
{
for ( int y = lo_y ; y < = hi_y ; y + + )
{
unsigned char * p = & buffer [ ( y * width ) + lo_x ] ;
for ( int x = lo_x ; x < = hi_x ; x + + )
{
* p + + = colour ;
}
}
}
else if ( colours = = 3 )
{
for ( int y = lo_y ; y < = hi_y ; y + + )
{
unsigned char * p = & buffer [ colours * ( ( y * width ) + lo_x ) ] ;
for ( int x = lo_x ; x < = hi_x ; x + + )
{
RED ( p ) = RGB_RED_VAL ( colour ) ;
GREEN ( p ) = RGB_GREEN_VAL ( colour ) ;
BLUE ( p ) = RGB_BLUE_VAL ( colour ) ;
p + = colours ;
}
}
}
}
void Image : : Fill ( Rgb colour , int density , const Box * limits )
2003-03-26 19:57:29 +08:00
{
2006-05-08 20:46:53 +08:00
if ( ! ( colours = = 1 | | colours = = 3 ) )
{
2009-10-14 18:01:46 +08:00
Panic ( " Attempt to fill image with unexpected colours %d " , colours ) ;
2006-05-08 20:46:53 +08:00
}
2003-03-26 19:57:29 +08:00
int lo_x = limits ? limits - > Lo ( ) . X ( ) : 0 ;
int lo_y = limits ? limits - > Lo ( ) . Y ( ) : 0 ;
int hi_x = limits ? limits - > Hi ( ) . X ( ) : width - 1 ;
int hi_y = limits ? limits - > Hi ( ) . Y ( ) : height - 1 ;
for ( int y = lo_y ; y < = hi_y ; y + + )
{
2003-03-28 06:45:26 +08:00
unsigned char * p = & buffer [ colours * ( ( y * width ) + lo_x ) ] ;
2003-03-26 19:57:29 +08:00
for ( int x = lo_x ; x < = hi_x ; x + + , p + = colours )
{
2005-11-30 01:51:06 +08:00
if ( ( x = = lo_x | | x = = hi_x | | y = = lo_y | | y = = hi_y ) | | ( ! ( x % density ) & & ! ( y % density ) ) )
2003-03-26 19:57:29 +08:00
{
if ( colours = = 1 )
{
* p = colour ;
}
else if ( colours = = 3 )
{
RED ( p ) = RGB_RED_VAL ( colour ) ;
GREEN ( p ) = RGB_GREEN_VAL ( colour ) ;
BLUE ( p ) = RGB_BLUE_VAL ( colour ) ;
}
}
}
}
}
2005-11-30 01:51:06 +08:00
void Image : : Outline ( Rgb colour , const Polygon & polygon )
2003-03-26 19:57:29 +08:00
{
2006-05-08 20:46:53 +08:00
if ( ! ( colours = = 1 | | colours = = 3 ) )
{
2009-10-14 18:01:46 +08:00
Panic ( " Attempt to outline image with unexpected colours %d " , colours ) ;
2006-05-08 20:46:53 +08:00
}
2005-11-30 01:51:06 +08:00
int n_coords = polygon . getNumCoords ( ) ;
for ( int j = 0 , i = n_coords - 1 ; j < n_coords ; i = j + + )
2003-03-26 19:57:29 +08:00
{
2005-11-30 01:51:06 +08:00
const Coord & p1 = polygon . getCoord ( i ) ;
const Coord & p2 = polygon . getCoord ( j ) ;
int x1 = p1 . X ( ) ;
int x2 = p2 . X ( ) ;
int y1 = p1 . Y ( ) ;
int y2 = p2 . Y ( ) ;
double dx = x2 - x1 ;
double dy = y2 - y1 ;
double grad ;
2008-07-14 22:43:47 +08:00
Debug ( 9 , " dx: %.2lf, dy: %.2lf " , dx , dy ) ;
2005-11-30 01:51:06 +08:00
if ( fabs ( dx ) < = fabs ( dy ) )
2003-03-26 19:57:29 +08:00
{
2008-07-14 22:43:47 +08:00
Debug ( 9 , " dx <= dy " ) ;
2005-11-30 01:51:06 +08:00
if ( y1 ! = y2 )
grad = dx / dy ;
else
grad = width ;
double x ;
int y , yinc = ( y1 < y2 ) ? 1 : - 1 ;
grad * = yinc ;
if ( colours = = 1 )
2003-03-26 19:57:29 +08:00
{
2008-07-14 22:43:47 +08:00
Debug ( 9 , " x1:%d, x2:%d, y1:%d, y2:%d, gr:%.2f " , x1 , x2 , y1 , y2 , grad ) ;
2005-11-30 01:51:06 +08:00
for ( x = x1 , y = y1 ; y ! = y2 ; y + = yinc , x + = grad )
{
2008-07-14 22:43:47 +08:00
Debug ( 9 , " x:%.2f, y:%d " , x , y ) ;
2005-11-30 01:51:06 +08:00
buffer [ ( y * width ) + int ( round ( x ) ) ] = colour ;
}
}
else if ( colours = = 3 )
{
for ( x = x1 , y = y1 ; y ! = y2 ; y + = yinc , x + = grad )
{
unsigned char * p = & buffer [ colours * ( ( y * width ) + int ( round ( x ) ) ) ] ;
RED ( p ) = RGB_RED_VAL ( colour ) ;
GREEN ( p ) = RGB_GREEN_VAL ( colour ) ;
BLUE ( p ) = RGB_BLUE_VAL ( colour ) ;
}
}
}
else
{
2008-07-14 22:43:47 +08:00
Debug ( 9 , " dx > dy " ) ;
2005-11-30 01:51:06 +08:00
if ( x1 ! = x2 )
grad = dy / dx ;
else
grad = height ;
2008-07-14 22:43:47 +08:00
Debug ( 9 , " grad: %.2lf " , grad ) ;
2005-11-30 01:51:06 +08:00
double y ;
int x , xinc = ( x1 < x2 ) ? 1 : - 1 ;
grad * = xinc ;
if ( colours = = 1 )
{
2008-07-14 22:43:47 +08:00
Debug ( 9 , " x1:%d, x2:%d, y1:%d, y2:%d, gr:%.2lf " , x1 , x2 , y1 , y2 , grad ) ;
2005-11-30 01:51:06 +08:00
for ( y = y1 , x = x1 ; x ! = x2 ; x + = xinc , y + = grad )
{
2008-07-14 22:43:47 +08:00
Debug ( 9 , " x:%d, y:%.2f " , x , y ) ;
2005-11-30 01:51:06 +08:00
buffer [ ( int ( round ( y ) ) * width ) + x ] = colour ;
}
}
else if ( colours = = 3 )
{
for ( y = y1 , x = x1 ; x ! = x2 ; x + = xinc , y + = grad )
{
unsigned char * p = & buffer [ colours * ( ( int ( round ( y ) ) * width ) + x ) ] ;
RED ( p ) = RGB_RED_VAL ( colour ) ;
GREEN ( p ) = RGB_GREEN_VAL ( colour ) ;
BLUE ( p ) = RGB_BLUE_VAL ( colour ) ;
}
2003-03-26 19:57:29 +08:00
}
}
}
2005-11-30 01:51:06 +08:00
}
void Image : : Fill ( Rgb colour , int density , const Polygon & polygon )
{
2006-05-08 20:46:53 +08:00
if ( ! ( colours = = 1 | | colours = = 3 ) )
{
2009-10-14 18:01:46 +08:00
Panic ( " Attempt to fill image with unexpected colours %d " , colours ) ;
2006-05-08 20:46:53 +08:00
}
2005-11-30 01:51:06 +08:00
int n_coords = polygon . getNumCoords ( ) ;
int n_global_edges = 0 ;
Edge global_edges [ n_coords ] ;
for ( int j = 0 , i = n_coords - 1 ; j < n_coords ; i = j + + )
2003-03-26 19:57:29 +08:00
{
2005-11-30 01:51:06 +08:00
const Coord & p1 = polygon . getCoord ( i ) ;
const Coord & p2 = polygon . getCoord ( j ) ;
int x1 = p1 . X ( ) ;
int x2 = p2 . X ( ) ;
int y1 = p1 . Y ( ) ;
int y2 = p2 . Y ( ) ;
2008-07-14 22:43:47 +08:00
Debug ( 9 , " x1:%d,y1:%d x2:%d,y2:%d " , x1 , y1 , x2 , y2 ) ;
2005-11-30 01:51:06 +08:00
if ( y1 = = y2 )
continue ;
double dx = x2 - x1 ;
double dy = y2 - y1 ;
global_edges [ n_global_edges ] . min_y = y1 < y2 ? y1 : y2 ;
global_edges [ n_global_edges ] . max_y = y1 < y2 ? y2 : y1 ;
global_edges [ n_global_edges ] . min_x = y1 < y2 ? x1 : x2 ;
global_edges [ n_global_edges ] . _1_m = dx / dy ;
n_global_edges + + ;
}
qsort ( global_edges , n_global_edges , sizeof ( * global_edges ) , Edge : : CompareYX ) ;
2005-12-02 00:29:19 +08:00
# ifndef ZM_DBG_OFF
2011-06-21 17:19:10 +08:00
if ( logLevel ( ) > = Logger : : DEBUG9 )
2005-12-02 00:24:25 +08:00
{
for ( int i = 0 ; i < n_global_edges ; i + + )
{
2008-07-14 22:43:47 +08:00
Debug ( 9 , " %d: min_y: %d, max_y:%d, min_x:%.2f, 1/m:%.2f " , i , global_edges [ i ] . min_y , global_edges [ i ] . max_y , global_edges [ i ] . min_x , global_edges [ i ] . _1_m ) ;
2005-12-02 00:24:25 +08:00
}
}
2005-12-02 00:29:19 +08:00
# endif
2005-11-30 01:51:06 +08:00
int n_active_edges = 0 ;
Edge active_edges [ n_global_edges ] ;
int y = global_edges [ 0 ] . min_y ;
do
{
for ( int i = 0 ; i < n_global_edges ; i + + )
2003-03-26 19:57:29 +08:00
{
2005-11-30 01:51:06 +08:00
if ( global_edges [ i ] . min_y = = y )
2003-03-26 19:57:29 +08:00
{
2008-07-14 22:43:47 +08:00
Debug ( 9 , " Moving global edge " ) ;
2005-11-30 01:51:06 +08:00
active_edges [ n_active_edges + + ] = global_edges [ i ] ;
if ( i < ( n_global_edges - 1 ) )
{
2009-02-17 02:17:19 +08:00
//memcpy( &global_edges[i], &global_edges[i+1], sizeof(*global_edges)*(n_global_edges-i) );
memmove ( & global_edges [ i ] , & global_edges [ i + 1 ] , sizeof ( * global_edges ) * ( n_global_edges - i ) ) ;
2005-11-30 01:51:06 +08:00
i - - ;
}
n_global_edges - - ;
}
else
{
break ;
2003-03-26 19:57:29 +08:00
}
}
2005-11-30 01:51:06 +08:00
qsort ( active_edges , n_active_edges , sizeof ( * active_edges ) , Edge : : CompareX ) ;
2005-12-02 00:29:19 +08:00
# ifndef ZM_DBG_OFF
2011-06-21 17:19:10 +08:00
if ( logLevel ( ) > = Logger : : DEBUG9 )
2005-12-02 00:24:25 +08:00
{
for ( int i = 0 ; i < n_active_edges ; i + + )
{
2008-07-14 22:43:47 +08:00
Debug ( 9 , " %d - %d: min_y: %d, max_y:%d, min_x:%.2f, 1/m:%.2f " , y , i , active_edges [ i ] . min_y , active_edges [ i ] . max_y , active_edges [ i ] . min_x , active_edges [ i ] . _1_m ) ;
2005-12-02 00:24:25 +08:00
}
}
2005-12-02 00:29:19 +08:00
# endif
2005-11-30 01:51:06 +08:00
if ( ! ( y % density ) )
{
2008-07-14 22:43:47 +08:00
//Debug( 9, "%d", y );
2005-11-30 01:51:06 +08:00
for ( int i = 0 ; i < n_active_edges ; )
{
int lo_x = int ( round ( active_edges [ i + + ] . min_x ) ) ;
int hi_x = int ( round ( active_edges [ i + + ] . min_x ) ) ;
unsigned char * p = & buffer [ colours * ( ( y * width ) + lo_x ) ] ;
for ( int x = lo_x ; x < = hi_x ; x + + , p + = colours )
{
if ( ! ( x % density ) )
{
2008-07-14 22:43:47 +08:00
//Debug( 9, " %d", x );
2005-11-30 01:51:06 +08:00
if ( colours = = 1 )
{
2005-12-02 00:24:25 +08:00
* p = colour ;
2005-11-30 01:51:06 +08:00
}
else
{
RED ( p ) = RGB_RED_VAL ( colour ) ;
GREEN ( p ) = RGB_GREEN_VAL ( colour ) ;
BLUE ( p ) = RGB_BLUE_VAL ( colour ) ;
}
}
}
}
}
y + + ;
for ( int i = n_active_edges - 1 ; i > = 0 ; i - - )
{
if ( y > = active_edges [ i ] . max_y ) // Or >= as per sheets
{
2008-07-14 22:43:47 +08:00
Debug ( 9 , " Deleting active_edge " ) ;
2005-11-30 01:51:06 +08:00
if ( i < ( n_active_edges - 1 ) )
{
2009-02-17 02:17:19 +08:00
//memcpy( &active_edges[i], &active_edges[i+1], sizeof(*active_edges)*(n_active_edges-i) );
memmove ( & active_edges [ i ] , & active_edges [ i + 1 ] , sizeof ( * active_edges ) * ( n_active_edges - i ) ) ;
2005-11-30 01:51:06 +08:00
}
n_active_edges - - ;
}
else
{
active_edges [ i ] . min_x + = active_edges [ i ] . _1_m ;
}
}
} while ( n_global_edges | | n_active_edges ) ;
}
void Image : : Fill ( Rgb colour , const Polygon & polygon )
{
Fill ( colour , 1 , polygon ) ;
2003-03-26 19:57:29 +08:00
}
2003-05-02 23:03:16 +08:00
void Image : : Rotate ( int angle )
{
angle % = 360 ;
if ( ! angle )
{
return ;
}
if ( angle % 90 )
{
return ;
}
static unsigned char rotate_buffer [ ZM_MAX_IMAGE_SIZE ] ;
switch ( angle )
{
case 90 :
{
int temp = width ;
width = height ;
height = temp ;
2005-07-12 21:38:42 +08:00
int line_bytes = width * colours ;
2003-05-02 23:03:16 +08:00
unsigned char * s_ptr = buffer ;
if ( colours = = 1 )
{
unsigned char * d_ptr ;
for ( int i = width - 1 ; i > = 0 ; i - - )
{
d_ptr = rotate_buffer + i ;
for ( int j = height - 1 ; j > = 0 ; j - - )
{
* d_ptr = * s_ptr + + ;
2005-05-06 00:42:37 +08:00
d_ptr + = line_bytes ;
2003-05-02 23:03:16 +08:00
}
}
}
else
{
unsigned char * d_ptr ;
for ( int i = width - 1 ; i > = 0 ; i - - )
{
d_ptr = rotate_buffer + ( 3 * i ) ;
for ( int j = height - 1 ; j > = 0 ; j - - )
{
* d_ptr = * s_ptr + + ;
* ( d_ptr + 1 ) = * s_ptr + + ;
* ( d_ptr + 2 ) = * s_ptr + + ;
2005-05-06 00:42:37 +08:00
d_ptr + = line_bytes ;
2003-05-02 23:03:16 +08:00
}
}
}
break ;
}
case 180 :
{
unsigned char * s_ptr = buffer + size ;
unsigned char * d_ptr = rotate_buffer ;
if ( colours = = 1 )
{
while ( s_ptr > buffer )
{
s_ptr - - ;
* d_ptr + + = * s_ptr ;
}
}
else
{
while ( s_ptr > buffer )
{
s_ptr - = 3 ;
* d_ptr + + = * s_ptr ;
* d_ptr + + = * ( s_ptr + 1 ) ;
* d_ptr + + = * ( s_ptr + 2 ) ;
}
}
break ;
}
case 270 :
{
int temp = width ;
width = height ;
height = temp ;
2005-07-12 21:38:42 +08:00
int line_bytes = width * colours ;
2003-05-02 23:03:16 +08:00
unsigned char * s_ptr = buffer + size ;
if ( colours = = 1 )
{
unsigned char * d_ptr ;
for ( int i = width - 1 ; i > = 0 ; i - - )
{
d_ptr = rotate_buffer + i ;
for ( int j = height - 1 ; j > = 0 ; j - - )
{
s_ptr - - ;
* d_ptr = * s_ptr ;
2005-05-06 00:42:37 +08:00
d_ptr + = line_bytes ;
2003-05-02 23:03:16 +08:00
}
}
}
else
{
unsigned char * d_ptr ;
for ( int i = width - 1 ; i > = 0 ; i - - )
{
d_ptr = rotate_buffer + ( 3 * i ) ;
for ( int j = height - 1 ; j > = 0 ; j - - )
{
* ( d_ptr + 2 ) = * ( - - s_ptr ) ;
* ( d_ptr + 1 ) = * ( - - s_ptr ) ;
* d_ptr = * ( - - s_ptr ) ;
2005-05-06 00:42:37 +08:00
d_ptr + = line_bytes ;
2003-05-02 23:03:16 +08:00
}
}
}
break ;
}
}
memcpy ( buffer , rotate_buffer , size ) ;
}
2003-10-16 17:00:25 +08:00
2005-05-06 00:42:37 +08:00
void Image : : Flip ( bool leftright )
{
static unsigned char flip_buffer [ ZM_MAX_IMAGE_SIZE ] ;
int line_bytes = width * colours ;
int line_bytes2 = 2 * line_bytes ;
if ( leftright )
{
// Horizontal flip, left to right
unsigned char * s_ptr = buffer + line_bytes ;
unsigned char * d_ptr = flip_buffer ;
unsigned char * max_d_ptr = flip_buffer + size ;
if ( colours = = 1 )
{
while ( d_ptr < max_d_ptr )
{
for ( int j = 0 ; j < width ; j + + )
{
s_ptr - - ;
* d_ptr + + = * s_ptr ;
}
s_ptr + = line_bytes2 ;
}
}
else
{
while ( d_ptr < max_d_ptr )
{
for ( int j = 0 ; j < width ; j + + )
{
s_ptr - = 3 ;
* d_ptr + + = * s_ptr ;
* d_ptr + + = * ( s_ptr + 1 ) ;
* d_ptr + + = * ( s_ptr + 2 ) ;
}
s_ptr + = line_bytes2 ;
}
}
}
else
{
// Vertical flip, top to bottom
unsigned char * s_ptr = buffer + ( height * line_bytes ) ;
unsigned char * d_ptr = flip_buffer ;
while ( s_ptr > buffer )
{
s_ptr - = line_bytes ;
memcpy ( d_ptr , s_ptr , line_bytes ) ;
d_ptr + = line_bytes ;
}
}
memcpy ( buffer , flip_buffer , size ) ;
}
2004-02-16 03:47:23 +08:00
void Image : : Scale ( unsigned int factor )
2003-10-16 17:00:25 +08:00
{
if ( ! factor )
{
2008-07-14 22:43:47 +08:00
Error ( " Bogus scale factor %d found " , factor ) ;
2003-10-16 17:00:25 +08:00
return ;
}
2007-08-30 02:11:09 +08:00
if ( factor = = ZM_SCALE_BASE )
2003-10-16 17:00:25 +08:00
{
return ;
}
static unsigned char scale_buffer [ ZM_MAX_IMAGE_SIZE ] ;
2007-08-30 02:11:09 +08:00
unsigned int new_width = ( width * factor ) / ZM_SCALE_BASE ;
unsigned int new_height = ( height * factor ) / ZM_SCALE_BASE ;
if ( factor > ZM_SCALE_BASE )
2003-10-16 17:00:25 +08:00
{
unsigned char * pd = scale_buffer ;
unsigned int wc = width * colours ;
2004-02-16 03:47:23 +08:00
unsigned int nwc = new_width * colours ;
2007-08-30 02:11:09 +08:00
unsigned int h_count = ZM_SCALE_BASE / 2 ;
2004-02-16 03:47:23 +08:00
unsigned int last_h_index = 0 ;
2006-11-09 19:47:37 +08:00
unsigned int last_w_index = 0 ;
2004-02-16 03:47:23 +08:00
unsigned int h_index ;
2003-10-16 17:00:25 +08:00
for ( int y = 0 ; y < height ; y + + )
{
unsigned char * ps = & buffer [ y * wc ] ;
2007-08-30 02:11:09 +08:00
unsigned int w_count = ZM_SCALE_BASE / 2 ;
2004-02-16 03:47:23 +08:00
unsigned int w_index ;
2006-11-09 19:47:37 +08:00
last_w_index = 0 ;
2003-10-16 17:00:25 +08:00
for ( int x = 0 ; x < width ; x + + )
{
2004-02-16 03:47:23 +08:00
w_count + = factor ;
2007-08-30 02:11:09 +08:00
w_index = w_count / ZM_SCALE_BASE ;
2004-02-16 03:47:23 +08:00
for ( int f = last_w_index ; f < w_index ; f + + )
2003-10-16 17:00:25 +08:00
{
for ( int c = 0 ; c < colours ; c + + )
{
* pd + + = * ( ps + c ) ;
}
}
ps + = colours ;
2004-02-16 03:47:23 +08:00
last_w_index = w_index ;
2003-10-16 17:00:25 +08:00
}
2004-02-16 03:47:23 +08:00
h_count + = factor ;
2007-08-30 02:11:09 +08:00
h_index = h_count / ZM_SCALE_BASE ;
2004-02-16 03:47:23 +08:00
for ( int f = last_h_index + 1 ; f < h_index ; f + + )
2003-10-16 17:00:25 +08:00
{
2004-02-16 03:47:23 +08:00
memcpy ( pd , pd - nwc , nwc ) ;
pd + = nwc ;
2003-10-16 17:00:25 +08:00
}
2004-02-16 03:47:23 +08:00
last_h_index = h_index ;
2003-10-16 17:00:25 +08:00
}
2006-11-09 19:47:37 +08:00
new_width = last_w_index ;
new_height = last_h_index ;
2003-10-16 17:00:25 +08:00
}
else
{
unsigned char * pd = scale_buffer ;
unsigned int wc = width * colours ;
2004-02-16 03:47:23 +08:00
unsigned int xstart = factor / 2 ;
unsigned int ystart = factor / 2 ;
unsigned int h_count = ystart ;
unsigned int last_h_index = 0 ;
2006-11-09 19:47:37 +08:00
unsigned int last_w_index = 0 ;
2004-02-16 03:47:23 +08:00
unsigned int h_index ;
for ( unsigned int y = 0 ; y < height ; y + + )
2003-10-16 17:00:25 +08:00
{
2004-02-16 03:47:23 +08:00
h_count + = factor ;
2007-08-30 02:11:09 +08:00
h_index = h_count / ZM_SCALE_BASE ;
2004-02-16 03:47:23 +08:00
if ( h_index > last_h_index )
2003-10-16 17:00:25 +08:00
{
2004-02-16 03:47:23 +08:00
unsigned int w_count = xstart ;
unsigned int w_index ;
2006-11-09 19:47:37 +08:00
last_w_index = 0 ;
2004-02-16 03:47:23 +08:00
unsigned char * ps = & buffer [ y * wc ] ;
for ( unsigned int x = 0 ; x < width ; x + + )
2003-10-16 17:00:25 +08:00
{
2004-02-16 03:47:23 +08:00
w_count + = factor ;
2007-08-30 02:11:09 +08:00
w_index = w_count / ZM_SCALE_BASE ;
2004-02-16 03:47:23 +08:00
if ( w_index > last_w_index )
{
for ( int c = 0 ; c < colours ; c + + )
{
* pd + + = * ps + + ;
}
}
else
{
ps + = colours ;
}
last_w_index = w_index ;
2003-10-16 17:00:25 +08:00
}
}
2004-02-16 03:47:23 +08:00
last_h_index = h_index ;
2003-10-16 17:00:25 +08:00
}
2006-11-09 19:47:37 +08:00
new_width = last_w_index ;
new_height = last_h_index ;
2003-10-16 17:00:25 +08:00
}
2007-08-30 02:11:09 +08:00
Assign ( new_width , new_height , colours , scale_buffer ) ;
2003-10-16 17:00:25 +08:00
}