2
// Copyright ļæ½ 1997 - 2001, Paul C. Gregory
4
// Contact: pgregory@aqsis.com
6
// This library is free software; you can redistribute it and/or
7
// modify it under the terms of the GNU General Public
8
// License as published by the Free Software Foundation; either
9
// version 2 of the License, or (at your option) any later version.
11
// This library is distributed in the hope that it will be useful,
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
// General Public License for more details.
16
// You should have received a copy of the GNU General Public
17
// License along with this library; if not, write to the Free Software
18
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
\brief Implements a TIFF based display driver.
23
\author Paul C. Gregory (pgregory@aqsis.com)
32
#include "logging_streambufs.h"
34
#if defined(AQSIS_SYSTEM_WIN32) || defined(AQSIS_SYSTEM_MACOSX)
38
#ifdef AQSIS_SYSTEM_WIN32
42
#else // AQSIS_SYSTEM_WIN32
46
#endif // !AQSIS_SYSTEM_WIN32
48
#include "displaydriver.h"
53
using namespace Aqsis;
55
/// Static response message for a format query.
56
SqDDMessageFormatResponse frmt( 2 );
57
/// Static response message close message.
58
SqDDMessageCloseAcknowledge closeack;
60
/** Handle a query message from the manager.
62
TqInt Query( SOCKET s, SqDDMessageBase* pMsg );
63
/** Handle an open message from the handler.
65
TqInt Open( SOCKET s, SqDDMessageBase* pMsg );
66
/** Handle a data message from the manager.
68
TqInt Data( SOCKET s, SqDDMessageBase* pMsg );
69
/** Handle a close message from the manager.
71
TqInt Close( SOCKET s, SqDDMessageBase* pMsg );
72
/** Handle an abandon message from the manager.
74
TqInt Abandon( SOCKET s, SqDDMessageBase* pMsg );
77
/// Main loop,, just cycle handling any recieved messages.
78
int main( int argc, char* argv[] )
80
std::auto_ptr<std::streambuf> reset_level( new Aqsis::reset_level_buf(std::cerr) );
81
std::auto_ptr<std::streambuf> show_timestamps( new Aqsis::timestamp_buf(std::cerr) );
82
std::auto_ptr<std::streambuf> fold_duplicates( new Aqsis::fold_duplicates_buf(std::cerr) );
83
std::auto_ptr<std::streambuf> show_level( new Aqsis::show_level_buf(std::cerr) );
84
std::auto_ptr<std::streambuf> filter_level( new Aqsis::filter_by_level_buf(Aqsis::WARNING, std::cerr) );
87
char *portStr = getenv( "AQSIS_DD_PORT" );
89
if ( portStr != NULL )
91
port = atoi( portStr );
94
if ( DDInitialise( NULL, port ) == 0 )
100
std::cerr << error << "Could not open communications channel to Aqsis" << std::endl;
112
unsigned char* pByteData;
115
TqInt g_CWXmin, g_CWYmin;
116
TqInt g_CWXmax, g_CWYmax;
117
uint16 compression = COMPRESSION_NONE, quality = 0;
118
TqFloat quantize_zeroval = 0.0f;
119
TqFloat quantize_oneval = 0.0f;
120
TqFloat quantize_minval = 0.0f;
121
TqFloat quantize_maxval = 0.0f;
122
TqFloat dither_val = 0.0f;
124
/// Storage for the output file name.
125
std::string strFilename( "output.tif" );
127
TqInt Query( SOCKET s, SqDDMessageBase* pMsgB )
129
switch ( pMsgB->m_MessageID )
131
case MessageID_FormatQuery:
133
SqDDMessageFormatQuery* pMsg = static_cast<SqDDMessageFormatQuery*>(pMsgB);
134
g_Format = pMsg->m_Formats[0];
135
frmt.m_DataFormat = g_Format;
136
if ( DDSendMsg( s, &frmt ) <= 0 )
138
// Create a buffer big enough to hold a row of buckets.
141
if ( g_Format == DataFormat_Unsigned8 )
142
pByteData = new unsigned char[ XRes * YRes * g_Channels ];
144
pFloatData = new float[ XRes * YRes * g_Channels ];
151
TqInt Open( SOCKET s, SqDDMessageBase* pMsgB )
153
SqDDMessageOpen * pMsg = static_cast<SqDDMessageOpen*>( pMsgB );
155
XRes = ( pMsg->m_CropWindowXMax - pMsg->m_CropWindowXMin );
156
YRes = ( pMsg->m_CropWindowYMax - pMsg->m_CropWindowYMin );
157
g_Channels = pMsg->m_Channels;
158
// BitsPerSample = pMsg->m_BitsPerSample;
160
g_CWXmin = pMsg->m_CropWindowXMin;
161
g_CWYmin = pMsg->m_CropWindowYMin;
162
g_CWXmax = pMsg->m_CropWindowXMax;
163
g_CWYmax = pMsg->m_CropWindowYMax;
169
TqInt Data( SOCKET s, SqDDMessageBase* pMsgB )
171
SqDDMessageData * pMsg = static_cast<SqDDMessageData*>( pMsgB );
173
TqInt linelen = XRes * g_Channels;
174
char* pBucket = reinterpret_cast<char*>( &pMsg->m_Data );
176
SqDDMessageData * const message = static_cast<SqDDMessageData*>( pMsgB );
178
// CHeck if the beck is not at all within the crop window.
179
if ( message->m_XMin > g_CWXmax || message->m_XMaxPlus1 < g_CWXmin ||
180
message->m_YMin > g_CWYmax || message->m_YMaxPlus1 < g_CWYmin )
184
for ( y = pMsg->m_YMin - g_CWYmin; y < pMsg->m_YMaxPlus1 - g_CWYmin; y++ )
187
for ( x = pMsg->m_XMin - g_CWXmin; x < pMsg->m_XMaxPlus1 - g_CWXmin; x++ )
189
if ( x >= 0 && y >= 0 && x < XRes && y < YRes )
191
TqInt so = ( y * linelen ) + ( x * g_Channels );
194
while ( i < g_Channels )
196
TqFloat value = reinterpret_cast<TqFloat*>( pBucket ) [ i ];
198
if( !( quantize_zeroval == 0.0f &&
199
quantize_oneval == 0.0f &&
200
quantize_minval == 0.0f &&
201
quantize_maxval == 0.0f ) )
203
value = ROUND(quantize_zeroval + value * (quantize_oneval - quantize_zeroval) + dither_val );
204
value = CLAMP(value, quantize_minval, quantize_maxval) ;
207
if ( g_Format == DataFormat_Unsigned8 )
209
if( NULL != pByteData )
210
pByteData[ so ] = static_cast<char>( value );
214
if( NULL != pFloatData )
215
pFloatData[ so ] = value;
221
pBucket += pMsg->m_ElementSize;
228
TqInt Close( SOCKET s, SqDDMessageBase* pMsgB )
230
uint16 photometric = PHOTOMETRIC_RGB;
231
uint16 config = PLANARCONFIG_CONTIG;
232
SqDDMessageClose *pClose = ( SqDDMessageClose * ) pMsgB;
234
pOut = TIFFOpen( strFilename.c_str(), "w" );
238
// Write the image to a tiff file.
241
int ExtraSamplesTypes[ 1 ] = {EXTRASAMPLE_ASSOCALPHA};
243
#if defined(AQSIS_SYSTEM_WIN32) || defined(AQSIS_SYSTEM_MACOSX)
244
sprintf( version, "%s %s", STRNAME, VERSION_STR );
246
sprintf( version, "%s %s", STRNAME, VERSION );
249
bool use_logluv = false;
252
TIFFSetField( pOut, TIFFTAG_SOFTWARE, ( uint32 ) version );
253
TIFFSetField( pOut, TIFFTAG_IMAGEWIDTH, ( uint32 ) XRes );
254
TIFFSetField( pOut, TIFFTAG_IMAGELENGTH, ( uint32 ) YRes );
255
TIFFSetField( pOut, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT );
256
TIFFSetField( pOut, TIFFTAG_SAMPLESPERPIXEL, g_Channels );
258
// Write out an 8 bits per pixel integer image.
259
if ( g_Format == DataFormat_Unsigned8 )
261
TIFFSetField( pOut, TIFFTAG_BITSPERSAMPLE, 8 );
262
TIFFSetField( pOut, TIFFTAG_PLANARCONFIG, config );
263
TIFFSetField( pOut, TIFFTAG_COMPRESSION, compression );
264
if ( compression == COMPRESSION_JPEG )
265
TIFFSetField( pOut, TIFFTAG_JPEGQUALITY, quality );
266
//if (description != "")
267
//TIFFSetField(TIFFTAG_IMAGEDESCRIPTION, description);
268
TIFFSetField( pOut, TIFFTAG_PHOTOMETRIC, photometric );
269
TIFFSetField( pOut, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize( pOut, 0 ) );
271
if ( g_Channels == 4 )
272
TIFFSetField( pOut, TIFFTAG_EXTRASAMPLES, 1, ExtraSamplesTypes );
274
// Set the position tages in case we aer dealing with a cropped image.
275
TIFFSetField( pOut, TIFFTAG_XPOSITION, ( float ) g_CWXmin );
276
TIFFSetField( pOut, TIFFTAG_YPOSITION, ( float ) g_CWYmin );
278
TqInt linelen = XRes * g_Channels;
280
for ( row = 0; row < YRes; row++ )
282
if ( TIFFWriteScanline( pOut, pByteData + ( row * linelen ), row, 0 ) < 0 )
289
// Write out a floating point image.
290
TIFFSetField( pOut, TIFFTAG_STONITS, ( double ) 1.0 );
292
// if(/* user wants logluv compression*/)
294
// if(/* user wants to save the alpha channel */)
296
// warn("SGI LogLuv encoding does not allow an alpha channel"
297
// " - using uncompressed IEEEFP instead");
301
// use_logluv = true;
304
// if(/* user wants LZW compression*/)
306
// warn("LZW compression is not available with SGI LogLuv encoding\n");
312
/* use SGI LogLuv compression */
313
TIFFSetField( pOut, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT );
314
TIFFSetField( pOut, TIFFTAG_BITSPERSAMPLE, 16 );
315
TIFFSetField( pOut, TIFFTAG_COMPRESSION, COMPRESSION_SGILOG );
316
TIFFSetField( pOut, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_LOGLUV );
317
TIFFSetField( pOut, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT );
321
/* use uncompressed IEEEFP pixels */
322
TIFFSetField( pOut, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP );
323
TIFFSetField( pOut, TIFFTAG_BITSPERSAMPLE, 32 );
324
TIFFSetField( pOut, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
325
TIFFSetField( pOut, TIFFTAG_COMPRESSION, compression );
328
TIFFSetField( pOut, TIFFTAG_SAMPLESPERPIXEL, g_Channels );
330
if ( g_Channels == 4 )
331
TIFFSetField( pOut, TIFFTAG_EXTRASAMPLES, 1, ExtraSamplesTypes );
332
// Set the position tages in case we aer dealing with a cropped image.
333
TIFFSetField( pOut, TIFFTAG_XPOSITION, ( float ) g_CWXmin );
334
TIFFSetField( pOut, TIFFTAG_YPOSITION, ( float ) g_CWYmin );
335
TIFFSetField( pOut, TIFFTAG_PLANARCONFIG, config );
337
TqInt linelen = XRes * g_Channels;
339
for ( row = 0; row < YRes; row++ )
341
if ( TIFFWriteScanline( pOut, pFloatData + ( row * linelen ), row, 0 ) < 0 )
348
delete[] ( pByteData );
349
delete[] ( pFloatData );
351
if ( DDSendMsg( s, &closeack ) <= 0 )
358
TqInt Abandon( SOCKET s, SqDDMessageBase* pMsgB )
364
/** Handle a general message from the manager.
366
TqInt HandleMessage( SOCKET s, SqDDMessageBase* pMsgB )
368
switch ( pMsgB->m_MessageID )
370
case MessageID_Filename:
372
SqDDMessageFilename * pMsg = static_cast<SqDDMessageFilename*>( pMsgB );
373
strFilename = pMsg->m_String;
377
case MessageID_UserParam:
379
SqDDMessageUserParam * pMsg = static_cast<SqDDMessageUserParam*>( pMsgB );
380
// Check if we understand the parameter.
381
if( strncmp( pMsg->m_NameAndData, "compression", pMsg->m_NameLength ) == 0 )
383
const char* pvalue = reinterpret_cast<const char*>( &pMsg->m_NameAndData[ pMsg->m_NameLength + 1 ] );
384
if ( strstr( pvalue, "none" ) != 0 )
385
compression = COMPRESSION_NONE;
386
else if ( strstr( pvalue, "lzw" ) != 0 )
387
compression = COMPRESSION_LZW;
388
else if ( strstr( pvalue, "deflate" ) != 0 )
389
compression = COMPRESSION_DEFLATE;
390
else if ( strstr( pvalue, "jpeg" ) != 0 )
391
compression = COMPRESSION_JPEG;
392
else if ( strstr( pvalue, "packbits" ) != 0 )
393
compression = COMPRESSION_PACKBITS;
395
else if( strncmp( pMsg->m_NameAndData, "quality", pMsg->m_NameLength ) == 0 )
397
quality = *reinterpret_cast<TqInt*>( &pMsg->m_NameAndData[ pMsg->m_NameLength + 1 ] );
398
if ( quality > 100 ) quality = 100;
400
else if( strncmp( pMsg->m_NameAndData, "quantize", pMsg->m_NameLength ) == 0 )
402
TqFloat* quantize = reinterpret_cast<TqFloat*>( &pMsg->m_NameAndData[ pMsg->m_NameLength + 1 ] );
403
quantize_zeroval = quantize[0];
404
quantize_oneval = quantize[1];
405
quantize_minval = quantize[2];
406
quantize_maxval = quantize[3];