mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-24 19:02:48 +00:00
259 lines
6.2 KiB
C++
259 lines
6.2 KiB
C++
/**
|
|
* QImageIO Routines to read/write XV images.
|
|
* copyright (c) 1998 Torben Weis <weis@kde.org>
|
|
* copyright (c) 1999 Oliver Eiden <o.eiden@pop.ruhr.de>
|
|
*
|
|
* This library is distributed under the conditions of the GNU LGPL.
|
|
*/
|
|
|
|
#include "xview.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <QtGui/QImage>
|
|
|
|
#define BUFSIZE 1024
|
|
|
|
static const int b_255_3[]= {0,85,170,255}, // index*255/3
|
|
rg_255_7[]={0,36,72,109,145,182,218,255}; // index *255/7
|
|
|
|
|
|
XVHandler::XVHandler()
|
|
{
|
|
}
|
|
|
|
bool XVHandler::canRead() const
|
|
{
|
|
if (canRead(device())) {
|
|
setFormat("xv");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool XVHandler::read(QImage *retImage)
|
|
{
|
|
int x=-1;
|
|
int y=-1;
|
|
int maxval=-1;
|
|
QIODevice *iodev = device();
|
|
|
|
char str[ BUFSIZE ];
|
|
|
|
// magic number must be "P7 332"
|
|
iodev->readLine( str, BUFSIZE );
|
|
if (strncmp(str,"P7 332",6))
|
|
return false;
|
|
|
|
// next line #XVVERSION
|
|
iodev->readLine( str, BUFSIZE );
|
|
if (strncmp(str, "#XVVERSION", 10))
|
|
return false;
|
|
|
|
// now it gets interesting, #BUILTIN means we are out.
|
|
// if IMGINFO comes, we are happy!
|
|
iodev->readLine( str, BUFSIZE );
|
|
if (strncmp(str, "#IMGINFO:", 9))
|
|
return false;
|
|
|
|
// after this an #END_OF_COMMENTS signals everything to be ok!
|
|
iodev->readLine( str, BUFSIZE );
|
|
if (strncmp(str, "#END_OF", 7))
|
|
return false;
|
|
|
|
// now a last line with width, height, maxval which is
|
|
// supposed to be 255
|
|
iodev->readLine( str, BUFSIZE );
|
|
sscanf(str, "%d %d %d", &x, &y, &maxval);
|
|
|
|
if (maxval != 255)
|
|
return false;
|
|
int blocksize = x*y;
|
|
if(x < 0 || y < 0 || blocksize < x || blocksize < y)
|
|
return false;
|
|
|
|
// now follows a binary block of x*y bytes.
|
|
char *block = (char*) malloc(blocksize);
|
|
if(!block)
|
|
return false;
|
|
|
|
if (iodev->read(block, blocksize) != blocksize )
|
|
{
|
|
free(block);
|
|
return false;
|
|
}
|
|
|
|
// Create the image
|
|
QImage image( x, y, QImage::Format_Indexed8 );
|
|
int colorCount;
|
|
colorCount = qMin( maxval + 1, 0 );
|
|
colorCount = qMax( 0, maxval + 1 );
|
|
image.setColorCount( colorCount );
|
|
|
|
// how do the color handling? they are absolute 24bpp
|
|
// or at least can be calculated as such.
|
|
int r,g,b;
|
|
|
|
for ( int j = 0; j < 256; j++ )
|
|
{
|
|
r = rg_255_7[((j >> 5) & 0x07)];
|
|
g = rg_255_7[((j >> 2) & 0x07)];
|
|
b = b_255_3[((j >> 0) & 0x03)];
|
|
image.setColor( j, qRgb( r, g, b ) );
|
|
}
|
|
|
|
for ( int py = 0; py < y; py++ )
|
|
{
|
|
uchar *data = image.scanLine( py );
|
|
memcpy( data, block + py * x, x );
|
|
}
|
|
|
|
*retImage = image;
|
|
|
|
free(block);
|
|
return true;
|
|
}
|
|
|
|
bool XVHandler::write(const QImage &image)
|
|
{
|
|
QIODevice& f = *( device() );
|
|
|
|
// Removed "f.open(...)" and "f.close()" (tanghus)
|
|
|
|
int w = image.width(), h = image.height();
|
|
|
|
char str[ 1024 ];
|
|
|
|
// magic number must be "P7 332"
|
|
f.write( "P7 332\n", 7 );
|
|
|
|
// next line #XVVERSION
|
|
f.write( "#XVVERSION:\n", 12 );
|
|
|
|
// now it gets interesting, #BUILTIN means we are out.
|
|
// if IMGINFO comes, we are happy!
|
|
f.write( "#IMGINFO:\n", 10 );
|
|
|
|
// after this an #END_OF_COMMENTS signals everything to be ok!
|
|
f.write( "#END_OF_COMMENTS:\n", 18 );
|
|
|
|
// now a last line with width, height, maxval which is supposed to be 255
|
|
sprintf( str, "%i %i 255\n", w, h );
|
|
f.write( str, strlen( str ) );
|
|
|
|
|
|
QImage tmpImage( image );
|
|
if ( image.depth() == 1 )
|
|
tmpImage = image.convertToFormat( QImage::Format_Indexed8, Qt::AutoColor );
|
|
|
|
uchar* buffer = new uchar[ w ];
|
|
|
|
for ( int py = 0; py < h; py++ )
|
|
{
|
|
const uchar *data = tmpImage.scanLine( py );
|
|
for ( int px = 0; px < w; px++ )
|
|
{
|
|
int r, g, b;
|
|
if ( tmpImage.depth() == 32 )
|
|
{
|
|
const QRgb *data32 = (QRgb*) data;
|
|
r = qRed( *data32 ) >> 5;
|
|
g = qGreen( *data32 ) >> 5;
|
|
b = qBlue( *data32 ) >> 6;
|
|
data += sizeof( QRgb );
|
|
}
|
|
else
|
|
{
|
|
QRgb color = tmpImage.color( *data );
|
|
r = qRed( color ) >> 5;
|
|
g = qGreen( color ) >> 5;
|
|
b = qBlue( color ) >> 6;
|
|
data++;
|
|
}
|
|
buffer[ px ] = ( r << 5 ) | ( g << 2 ) | b;
|
|
}
|
|
f.write( (const char*)buffer, w );
|
|
}
|
|
delete[] buffer;
|
|
|
|
return true;
|
|
}
|
|
|
|
QByteArray XVHandler::name() const
|
|
{
|
|
return "xv";
|
|
}
|
|
|
|
bool XVHandler::canRead(QIODevice *device)
|
|
{
|
|
if (!device) {
|
|
qWarning("XVHandler::canRead() called with no device");
|
|
return false;
|
|
}
|
|
|
|
qint64 oldPos = device->pos();
|
|
|
|
char head[6];
|
|
qint64 readBytes = device->read(head, sizeof(head));
|
|
if (readBytes != sizeof(head)) {
|
|
if (device->isSequential()) {
|
|
while (readBytes > 0)
|
|
device->ungetChar(head[readBytes-- - 1]);
|
|
} else {
|
|
device->seek(oldPos);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (device->isSequential()) {
|
|
while (readBytes > 0)
|
|
device->ungetChar(head[readBytes-- - 1]);
|
|
} else {
|
|
device->seek(oldPos);
|
|
}
|
|
|
|
return qstrncmp(head, "P7 332", 6) == 0;
|
|
}
|
|
|
|
|
|
class XVPlugin : public QImageIOPlugin
|
|
{
|
|
public:
|
|
QStringList keys() const;
|
|
Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
|
|
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
|
|
};
|
|
|
|
QStringList XVPlugin::keys() const
|
|
{
|
|
return QStringList() << "xv";
|
|
}
|
|
|
|
QImageIOPlugin::Capabilities XVPlugin::capabilities(QIODevice *device, const QByteArray &format) const
|
|
{
|
|
if (format == "xv")
|
|
return Capabilities(CanRead | CanWrite);
|
|
if (!format.isEmpty())
|
|
return 0;
|
|
if (!device->isOpen())
|
|
return 0;
|
|
|
|
Capabilities cap;
|
|
if (device->isReadable() && XVHandler::canRead(device))
|
|
cap |= CanRead;
|
|
if (device->isWritable())
|
|
cap |= CanWrite;
|
|
return cap;
|
|
}
|
|
|
|
QImageIOHandler *XVPlugin::create(QIODevice *device, const QByteArray &format) const
|
|
{
|
|
QImageIOHandler *handler = new XVHandler;
|
|
handler->setDevice(device);
|
|
handler->setFormat(format);
|
|
return handler;
|
|
}
|
|
|
|
Q_EXPORT_STATIC_PLUGIN(XVPlugin)
|
|
Q_EXPORT_PLUGIN2(xv, XVPlugin)
|