/* This file is part of the KDE project Copyright (C) 2002, The Karbon Developers This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include "vdocument.h" #include "vlayer.h" #include "xcfexport.h" #include // Tile size constants. const unsigned XcfExport::m_tileWidth = 64; const unsigned XcfExport::m_tileHeight = 64; typedef KGenericFactory XcfExportFactory; K_EXPORT_COMPONENT_FACTORY( libkarbonxcfexport, XcfExportFactory( "kofficefilters" ) ) XcfExport::XcfExport( KoFilter*, const char*, const TQStringList& ) : KoFilter() { m_zoomX = 1.0; m_zoomY = 1.0; } KoFilter::ConversionStatus XcfExport::convert( const TQCString& from, const TQCString& to ) { if( to != "image/x-xcf-gimp" || from != "application/x-karbon" ) { return KoFilter::NotImplemented; } KoStoreDevice* storeIn = m_chain->storageFile( "root", KoStore::Read ); if( !storeIn ) return KoFilter::StupidError; TQFile fileOut( m_chain->outputFile() ); if( !fileOut.open( IO_WriteOnly ) ) return KoFilter::StupidError; TQDomDocument domIn; domIn.setContent( storeIn ); TQDomElement docNode = domIn.documentElement(); m_stream = new TQDataStream( &fileOut ); // Load the document. VDocument doc; doc.load( docNode ); // Process the document. doc.accept( *this ); delete m_stream; fileOut.close(); return KoFilter::OK; } void XcfExport::visitVDocument( VDocument& document ) { // Offsets. TQIODevice::Offset current = 0; TQIODevice::Offset start = 0; TQIODevice::Offset end = 0; // Save width and height for layer saving. m_width = static_cast( document.width() * m_zoomX ); m_height = static_cast( document.height() * m_zoomY ); // Header tag (size 14 bytes). m_stream->writeRawBytes( "gimp xcf file", 14 ); // Image width. *m_stream << static_cast( m_width ); // Image height. *m_stream << static_cast( m_height ); // Image type = RGB. *m_stream << static_cast( 0 ); // Do not save any properties currently. *m_stream // "END". << static_cast( 0 ) // Property size in bytes. << static_cast( 0 ); // Save current offset. current = m_stream->device()->at(); // Leave space for layer and channel offsets. m_stream->device()->at( // current position + (number layers + number channels + 2) * 4. current + ( document.layers().count() + 3 + 2 ) * 4 ); // Iterate over layers. VLayerListIterator itr( document.layers() ); for( ; itr.current(); ++itr ) { // Save start offset. start = m_stream->device()->at(); // Write layer. itr.current()->accept( *this ); // Save end offset. end = m_stream->device()->at(); // Return to current offset. m_stream->device()->at( current ); // Save layer offset. *m_stream << start; // Increment offset. current = m_stream->device()->at(); // Return to end offset. m_stream->device()->at( end ); } // Return to current offset. m_stream->device()->at( current ); // Append a zero offset to indicate end of layer offsets. *m_stream << static_cast( 0 ); // Return to end offset. m_stream->device()->at( end ); // Append a zero offset to indicate end of channel offsets. *m_stream << static_cast( 0 ); } void XcfExport::visitVLayer( VLayer& layer ) { // Layer width = image width. *m_stream << static_cast( m_width ); // Layer height = image height. *m_stream << static_cast( m_height ); // Layer type = RGBA. *m_stream << static_cast( 1 ); // Layer name. *m_stream << layer.name().latin1(); // Layer opacity. *m_stream << static_cast( 6 ); // Property size in bytes. *m_stream << static_cast( 4 ); // Fully opaque = 255. *m_stream << static_cast( 255 ); // Layer visible? *m_stream << static_cast( 8 ); // Property size in bytes. *m_stream << static_cast( 4 ); // True. *m_stream << static_cast( 1 ); // Layer linked? *m_stream << static_cast( 9 ); // Property size in bytes. *m_stream << static_cast( 4 ); // False. *m_stream << static_cast( 0 ); // Preserve transparency? *m_stream << static_cast( 10 ); // Property size in bytes. *m_stream << static_cast( 4 ); // False. *m_stream << static_cast( 0 ); // Apply mask? *m_stream << static_cast( 11 ); // Property size in bytes. *m_stream << static_cast( 4 ); // False. *m_stream << static_cast( 0 ); // Edit mask? *m_stream << static_cast( 12 ); // Property size in bytes. *m_stream << static_cast( 4 ); // False. *m_stream << static_cast( 0 ); // Show mask? *m_stream << static_cast( 13 ); // Property size in bytes. *m_stream << static_cast( 4 ); // False. *m_stream << static_cast( 0 ); // Layer offsets. *m_stream << static_cast( 15 ); // Property size in bytes. *m_stream << static_cast( 8 ); // X-Offset. *m_stream << static_cast( 0 ); // Y-Offset. *m_stream << static_cast( 0 ); // Layer mode. *m_stream << static_cast( 7 ); // Property size in bytes. *m_stream << static_cast( 4 ); // Normal mode. *m_stream << static_cast( 0 ); // TODO: Tattoo. *m_stream << static_cast( 20 ); // Property size in bytes. *m_stream << static_cast( 4 ); // False. *m_stream << static_cast( 0 ); // Layer properties end. *m_stream << static_cast( 0 ); // Property size in bytes. *m_stream << static_cast( 0 ); // Offsets. TQIODevice::Offset current = 0; TQIODevice::Offset start = 0; TQIODevice::Offset end = 0; // Save current offset. current = m_stream->device()->at(); // Leave space for hierarchy offsets. m_stream->device()->at( current + 8 ); // Save start offset. start = m_stream->device()->at(); // Write hierarchy. writeHierarchy(); // Save end offset. end = m_stream->device()->at(); // Return to current offset. m_stream->device()->at( current ); // Save hierarchy offset. *m_stream << start; // Append a zero offset to indicate end of layer mask offsets. *m_stream << static_cast( 0 ); } void XcfExport::writeHierarchy() { // Offsets. TQIODevice::Offset current = 0; TQIODevice::Offset start = 0; TQIODevice::Offset end = 0; // Width (again?). *m_stream << m_width; // Height (again?). *m_stream << m_height; // Color depth. *m_stream << static_cast( 3 ); // Calculate level number. int levX = levels( m_width, m_tileWidth ); int levY = levels( m_height, m_tileHeight ); int levels = TQMAX( levX, levY ); int width = m_width; int height = m_height; // Save current offset. current = m_stream->device()->at(); // Leave space for level offsets. m_stream->device()->at( current + ( levels + 1 ) * 4 ); for( int i = 0; i < levels; ++i ) { // Save start offset. start = m_stream->device()->at(); if( i == 0 ) { // Write level. writeLevel(); } else { // Fake an empty level. width /= 2; height /= 2; *m_stream << static_cast( width ); *m_stream << static_cast( height ); *m_stream << static_cast( 0 ); } // Save end offset. end = m_stream->device()->at(); // Return to current offset. m_stream->device()->at( current ); // Save level offset. *m_stream << start; // Increment offset. current = m_stream->device()->at(); // Return to end offset. m_stream->device()->at( end ); } // Return to current offset. m_stream->device()->at( current ); // Append a zero offset to indicate end of level offsets. *m_stream << static_cast( 0 ); } void XcfExport::writeLevel() { // Offsets. TQIODevice::Offset current = 0; TQIODevice::Offset start = 0; TQIODevice::Offset end = 0; *m_stream << static_cast( m_width ); *m_stream << static_cast( m_height ); int rows = ( m_height + m_tileHeight - 1 ) / m_tileHeight; int cols = ( m_width + m_tileWidth - 1 ) / m_tileWidth; int tiles = rows * cols; // Save current offset. current = m_stream->device()->at(); // Leave space for tile offsets. m_stream->device()->at( current + ( tiles + 1 ) * 4 ); for( int i = 0; i < tiles; ++i ) { // Save start offset. start = m_stream->device()->at(); // TODO: Save tile. *m_stream << static_cast( 1 ); *m_stream << static_cast( 1 ); *m_stream << static_cast( 1 ); *m_stream << static_cast( 1 ); *m_stream << static_cast( 1 ); *m_stream << static_cast( 1 ); *m_stream << static_cast( 1 ); *m_stream << static_cast( 1 ); *m_stream << static_cast( 1 ); *m_stream << static_cast( 1 ); *m_stream << static_cast( 1 ); *m_stream << static_cast( 1 ); // Save end offset. end = m_stream->device()->at(); // Return to current offset. m_stream->device()->at( current ); // Save tile offset. *m_stream << start; // Increment offset. current = m_stream->device()->at(); // Return to end offset. m_stream->device()->at( end ); } } int XcfExport::levels( int layerSize, int tileSize ) { int l = 1; while( layerSize > tileSize ) { layerSize /= 2; l += 1; } return l; } #include "xcfexport.moc"