You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/filters/karbon/xcf/xcfexport.cc

459 lines
10 KiB

/* 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 <tqcstring.h>
#include <tqdatastream.h>
#include <tqdom.h>
#include <tqfile.h>
#include <tqstring.h>
#include <tqvaluelist.h>
#include <kgenericfactory.h>
#include <KoFilter.h>
#include <KoFilterChain.h>
#include <KoStore.h>
#include "vdocument.h"
#include "vlayer.h"
#include "xcfexport.h"
#include <kdebug.h>
// Tile size constants.
const unsigned XcfExport::m_tileWidth = 64;
const unsigned XcfExport::m_tileHeight = 64;
typedef KGenericFactory<XcfExport, KoFilter> 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<unsigned>( document.width() * m_zoomX );
m_height = static_cast<unsigned>( document.height() * m_zoomY );
// Header tag (size 14 bytes).
m_stream->writeRawBytes( "gimp xcf file", 14 );
// Image width.
*m_stream << static_cast<TQ_UINT32>( m_width );
// Image height.
*m_stream << static_cast<TQ_UINT32>( m_height );
// Image type = RGB.
*m_stream << static_cast<TQ_UINT32>( 0 );
// Do not save any properties currently.
*m_stream
// "END".
<< static_cast<TQ_UINT32>( 0 )
// Property size in bytes.
<< static_cast<TQ_UINT32>( 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<TQ_UINT32>( 0 );
// Return to end offset.
m_stream->device()->at( end );
// Append a zero offset to indicate end of channel offsets.
*m_stream << static_cast<TQ_UINT32>( 0 );
}
void
XcfExport::visitVLayer( VLayer& layer )
{
// Layer width = image width.
*m_stream << static_cast<TQ_UINT32>( m_width );
// Layer height = image height.
*m_stream << static_cast<TQ_UINT32>( m_height );
// Layer type = RGBA.
*m_stream << static_cast<TQ_UINT32>( 1 );
// Layer name.
*m_stream << layer.name().latin1();
// Layer opacity.
*m_stream << static_cast<TQ_UINT32>( 6 );
// Property size in bytes.
*m_stream << static_cast<TQ_UINT32>( 4 );
// Fully opaque = 255.
*m_stream << static_cast<TQ_UINT32>( 255 );
// Layer visible?
*m_stream << static_cast<TQ_UINT32>( 8 );
// Property size in bytes.
*m_stream << static_cast<TQ_UINT32>( 4 );
// True.
*m_stream << static_cast<TQ_UINT32>( 1 );
// Layer linked?
*m_stream << static_cast<TQ_UINT32>( 9 );
// Property size in bytes.
*m_stream << static_cast<TQ_UINT32>( 4 );
// False.
*m_stream << static_cast<TQ_UINT32>( 0 );
// Preserve transparency?
*m_stream << static_cast<TQ_UINT32>( 10 );
// Property size in bytes.
*m_stream << static_cast<TQ_UINT32>( 4 );
// False.
*m_stream << static_cast<TQ_UINT32>( 0 );
// Apply mask?
*m_stream << static_cast<TQ_UINT32>( 11 );
// Property size in bytes.
*m_stream << static_cast<TQ_UINT32>( 4 );
// False.
*m_stream << static_cast<TQ_UINT32>( 0 );
// Edit mask?
*m_stream << static_cast<TQ_UINT32>( 12 );
// Property size in bytes.
*m_stream << static_cast<TQ_UINT32>( 4 );
// False.
*m_stream << static_cast<TQ_UINT32>( 0 );
// Show mask?
*m_stream << static_cast<TQ_UINT32>( 13 );
// Property size in bytes.
*m_stream << static_cast<TQ_UINT32>( 4 );
// False.
*m_stream << static_cast<TQ_UINT32>( 0 );
// Layer offsets.
*m_stream << static_cast<TQ_UINT32>( 15 );
// Property size in bytes.
*m_stream << static_cast<TQ_UINT32>( 8 );
// X-Offset.
*m_stream << static_cast<TQ_UINT32>( 0 );
// Y-Offset.
*m_stream << static_cast<TQ_UINT32>( 0 );
// Layer mode.
*m_stream << static_cast<TQ_UINT32>( 7 );
// Property size in bytes.
*m_stream << static_cast<TQ_UINT32>( 4 );
// Normal mode.
*m_stream << static_cast<TQ_UINT32>( 0 );
// TODO: Tattoo.
*m_stream << static_cast<TQ_UINT32>( 20 );
// Property size in bytes.
*m_stream << static_cast<TQ_UINT32>( 4 );
// False.
*m_stream << static_cast<TQ_UINT32>( 0 );
// Layer properties end.
*m_stream << static_cast<TQ_UINT32>( 0 );
// Property size in bytes.
*m_stream << static_cast<TQ_UINT32>( 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<TQ_UINT32>( 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<TQ_UINT32>( 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<TQ_UINT32>( width );
*m_stream << static_cast<TQ_UINT32>( height );
*m_stream << static_cast<TQ_UINT32>( 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<TQ_UINT32>( 0 );
}
void
XcfExport::writeLevel()
{
// Offsets.
TQIODevice::Offset current = 0;
TQIODevice::Offset start = 0;
TQIODevice::Offset end = 0;
*m_stream << static_cast<TQ_UINT32>( m_width );
*m_stream << static_cast<TQ_UINT32>( 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<TQ_UINT8>( 1 );
*m_stream << static_cast<TQ_UINT8>( 1 );
*m_stream << static_cast<TQ_UINT8>( 1 );
*m_stream << static_cast<TQ_UINT8>( 1 );
*m_stream << static_cast<TQ_UINT8>( 1 );
*m_stream << static_cast<TQ_UINT8>( 1 );
*m_stream << static_cast<TQ_UINT8>( 1 );
*m_stream << static_cast<TQ_UINT8>( 1 );
*m_stream << static_cast<TQ_UINT8>( 1 );
*m_stream << static_cast<TQ_UINT8>( 1 );
*m_stream << static_cast<TQ_UINT8>( 1 );
*m_stream << static_cast<TQ_UINT8>( 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"