00001
00009 #include "xview.h"
00010
00011 #include <stdio.h>
00012 #include <string.h>
00013 #include <stdlib.h>
00014 #include <QtGui/QImage>
00015
00016 #define BUFSIZE 1024
00017
00018 static const int b_255_3[]= {0,85,170,255},
00019 rg_255_7[]={0,36,72,109,145,182,218,255};
00020
00021
00022 XVHandler::XVHandler()
00023 {
00024 }
00025
00026 bool XVHandler::canRead() const
00027 {
00028 if (canRead(device())) {
00029 setFormat("xv");
00030 return true;
00031 }
00032 return false;
00033 }
00034
00035 bool XVHandler::read(QImage *retImage)
00036 {
00037 int x=-1;
00038 int y=-1;
00039 int maxval=-1;
00040 QIODevice *iodev = device();
00041
00042 char str[ BUFSIZE ];
00043
00044
00045 iodev->readLine( str, BUFSIZE );
00046 if (strncmp(str,"P7 332",6))
00047 return false;
00048
00049
00050 iodev->readLine( str, BUFSIZE );
00051 if (strncmp(str, "#XVVERSION", 10))
00052 return false;
00053
00054
00055
00056 iodev->readLine( str, BUFSIZE );
00057 if (strncmp(str, "#IMGINFO:", 9))
00058 return false;
00059
00060
00061 iodev->readLine( str, BUFSIZE );
00062 if (strncmp(str, "#END_OF", 7))
00063 return false;
00064
00065
00066
00067 iodev->readLine( str, BUFSIZE );
00068 sscanf(str, "%d %d %d", &x, &y, &maxval);
00069
00070 if (maxval != 255)
00071 return false;
00072 int blocksize = x*y;
00073 if(x < 0 || y < 0 || blocksize < x || blocksize < y)
00074 return false;
00075
00076
00077 char *block = (char*) malloc(blocksize);
00078 if(!block)
00079 return false;
00080
00081 if (iodev->read(block, blocksize) != blocksize )
00082 {
00083 free(block);
00084 return false;
00085 }
00086
00087
00088 QImage image( x, y, QImage::Format_Indexed8 );
00089 int numColors;
00090 numColors = qMin( maxval + 1, 0 );
00091 numColors = qMax( 0, maxval + 1 );
00092 image.setNumColors( numColors );
00093
00094
00095
00096 int r,g,b;
00097
00098 for ( int j = 0; j < 256; j++ )
00099 {
00100 r = rg_255_7[((j >> 5) & 0x07)];
00101 g = rg_255_7[((j >> 2) & 0x07)];
00102 b = b_255_3[((j >> 0) & 0x03)];
00103 image.setColor( j, qRgb( r, g, b ) );
00104 }
00105
00106 for ( int py = 0; py < y; py++ )
00107 {
00108 uchar *data = image.scanLine( py );
00109 memcpy( data, block + py * x, x );
00110 }
00111
00112 *retImage = image;
00113
00114 free(block);
00115 return true;
00116 }
00117
00118 bool XVHandler::write(const QImage &image)
00119 {
00120 QIODevice& f = *( device() );
00121
00122
00123
00124 int w = image.width(), h = image.height();
00125
00126 char str[ 1024 ];
00127
00128
00129 f.write( "P7 332\n", 7 );
00130
00131
00132 f.write( "#XVVERSION:\n", 12 );
00133
00134
00135
00136 f.write( "#IMGINFO:\n", 10 );
00137
00138
00139 f.write( "#END_OF_COMMENTS:\n", 18 );
00140
00141
00142 sprintf( str, "%i %i 255\n", w, h );
00143 f.write( str, strlen( str ) );
00144
00145
00146 QImage tmpImage( image );
00147 if ( image.depth() == 1 )
00148 tmpImage = image.convertToFormat( QImage::Format_Indexed8, Qt::AutoColor );
00149
00150 uchar* buffer = new uchar[ w ];
00151
00152 for ( int py = 0; py < h; py++ )
00153 {
00154 const uchar *data = tmpImage.scanLine( py );
00155 for ( int px = 0; px < w; px++ )
00156 {
00157 int r, g, b;
00158 if ( tmpImage.depth() == 32 )
00159 {
00160 const QRgb *data32 = (QRgb*) data;
00161 r = qRed( *data32 ) >> 5;
00162 g = qGreen( *data32 ) >> 5;
00163 b = qBlue( *data32 ) >> 6;
00164 data += sizeof( QRgb );
00165 }
00166 else
00167 {
00168 QRgb color = tmpImage.color( *data );
00169 r = qRed( color ) >> 5;
00170 g = qGreen( color ) >> 5;
00171 b = qBlue( color ) >> 6;
00172 data++;
00173 }
00174 buffer[ px ] = ( r << 5 ) | ( g << 2 ) | b;
00175 }
00176 f.write( (const char*)buffer, w );
00177 }
00178 delete[] buffer;
00179
00180 return true;
00181 }
00182
00183 QByteArray XVHandler::name() const
00184 {
00185 return "xv";
00186 }
00187
00188 bool XVHandler::canRead(QIODevice *device)
00189 {
00190 if (!device) {
00191 qWarning("XVHandler::canRead() called with no device");
00192 return false;
00193 }
00194
00195 qint64 oldPos = device->pos();
00196
00197 char head[6];
00198 qint64 readBytes = device->read(head, sizeof(head));
00199 if (readBytes != sizeof(head)) {
00200 if (device->isSequential()) {
00201 while (readBytes > 0)
00202 device->ungetChar(head[readBytes-- - 1]);
00203 } else {
00204 device->seek(oldPos);
00205 }
00206 return false;
00207 }
00208
00209 if (device->isSequential()) {
00210 while (readBytes > 0)
00211 device->ungetChar(head[readBytes-- - 1]);
00212 } else {
00213 device->seek(oldPos);
00214 }
00215
00216 return qstrncmp(head, "P7 332", 6) == 0;
00217 }
00218
00219
00220 class XVPlugin : public QImageIOPlugin
00221 {
00222 public:
00223 QStringList keys() const;
00224 Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
00225 QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
00226 };
00227
00228 QStringList XVPlugin::keys() const
00229 {
00230 return QStringList() << "xv";
00231 }
00232
00233 QImageIOPlugin::Capabilities XVPlugin::capabilities(QIODevice *device, const QByteArray &format) const
00234 {
00235 if (format == "xv")
00236 return Capabilities(CanRead | CanWrite);
00237 if (!format.isEmpty())
00238 return 0;
00239 if (!device->isOpen())
00240 return 0;
00241
00242 Capabilities cap;
00243 if (device->isReadable() && XVHandler::canRead(device))
00244 cap |= CanRead;
00245 if (device->isWritable())
00246 cap |= CanWrite;
00247 return cap;
00248 }
00249
00250 QImageIOHandler *XVPlugin::create(QIODevice *device, const QByteArray &format) const
00251 {
00252 QImageIOHandler *handler = new XVHandler;
00253 handler->setDevice(device);
00254 handler->setFormat(format);
00255 return handler;
00256 }
00257
00258 Q_EXPORT_STATIC_PLUGIN(XVPlugin)
00259 Q_EXPORT_PLUGIN2(xv, XVPlugin)