karbon/xcf/xcfexport.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2002, The Karbon Developers
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include <tqcstring.h>
21#include <tqdatastream.h>
22#include <tqdom.h>
23#include <tqfile.h>
24#include <tqstring.h>
25#include <tqvaluelist.h>
26
27#include <kgenericfactory.h>
28#include <KoFilter.h>
29#include <KoFilterChain.h>
30#include <KoStore.h>
31
32#include "vdocument.h"
33#include "vlayer.h"
34#include "xcfexport.h"
35
36#include <kdebug.h>
37
38
39// Tile size constants.
40const unsigned XcfExport::m_tileWidth = 64;
41const unsigned XcfExport::m_tileHeight = 64;
42
43
44typedef KGenericFactory<XcfExport, KoFilter> XcfExportFactory;
45K_EXPORT_COMPONENT_FACTORY( libkarbonxcfexport, XcfExportFactory( "kofficefilters" ) )
46
47
48XcfExport::XcfExport( KoFilter*, const char*, const TQStringList& )
49 : KoFilter()
50{
51 m_zoomX = 1.0;
52 m_zoomY = 1.0;
53}
54
55KoFilter::ConversionStatus
56XcfExport::convert( const TQCString& from, const TQCString& to )
57{
58 if( to != "image/x-xcf-gimp" || from != "application/x-karbon" )
59 {
60 return KoFilter::NotImplemented;
61 }
62
63
64 KoStoreDevice* storeIn = m_chain->storageFile( "root", KoStore::Read );
65
66 if( !storeIn )
67 return KoFilter::StupidError;
68
69
70 TQFile fileOut( m_chain->outputFile() );
71
72 if( !fileOut.open( IO_WriteOnly ) )
73 return KoFilter::StupidError;
74
75
76 TQDomDocument domIn;
77 domIn.setContent( storeIn );
78 TQDomElement docNode = domIn.documentElement();
79
80 m_stream = new TQDataStream( &fileOut );
81
82
83 // Load the document.
84 VDocument doc;
85 doc.load( docNode );
86
87 // Process the document.
88 doc.accept( *this );
89
90
91 delete m_stream;
92 fileOut.close();
93
94 return KoFilter::OK;
95}
96
97void
98XcfExport::visitVDocument( VDocument& document )
99{
100 // Offsets.
101 TQIODevice::Offset current = 0;
102 TQIODevice::Offset start = 0;
103 TQIODevice::Offset end = 0;
104
105 // Save width and height for layer saving.
106 m_width = static_cast<unsigned>( document.width() * m_zoomX );
107 m_height = static_cast<unsigned>( document.height() * m_zoomY );
108
109
110 // Header tag (size 14 bytes).
111 m_stream->writeRawBytes( "gimp xcf file", 14 );
112
113 // Image width.
114 *m_stream << static_cast<TQ_UINT32>( m_width );
115
116 // Image height.
117 *m_stream << static_cast<TQ_UINT32>( m_height );
118
119 // Image type = RGB.
120 *m_stream << static_cast<TQ_UINT32>( 0 );
121
122 // Do not save any properties currently.
123 *m_stream
124 // "END".
125 << static_cast<TQ_UINT32>( 0 )
126 // Property size in bytes.
127 << static_cast<TQ_UINT32>( 0 );
128
129
130 // Save current offset.
131 current = m_stream->device()->at();
132
133 // Leave space for layer and channel offsets.
134 m_stream->device()->at(
135 // current position + (number layers + number channels + 2) * 4.
136 current + ( document.layers().count() + 3 + 2 ) * 4 );
137
138
139 // Iterate over layers.
140 VLayerListIterator itr( document.layers() );
141
142 for( ; itr.current(); ++itr )
143 {
144 // Save start offset.
145 start = m_stream->device()->at();
146
147
148 // Write layer.
149 itr.current()->accept( *this );
150
151
152 // Save end offset.
153 end = m_stream->device()->at();
154
155 // Return to current offset.
156 m_stream->device()->at( current );
157
158 // Save layer offset.
159 *m_stream << start;
160
161 // Increment offset.
162 current = m_stream->device()->at();
163
164 // Return to end offset.
165 m_stream->device()->at( end );
166 }
167
168
169 // Return to current offset.
170 m_stream->device()->at( current );
171
172 // Append a zero offset to indicate end of layer offsets.
173 *m_stream << static_cast<TQ_UINT32>( 0 );
174
175
176 // Return to end offset.
177 m_stream->device()->at( end );
178
179 // Append a zero offset to indicate end of channel offsets.
180 *m_stream << static_cast<TQ_UINT32>( 0 );
181}
182
183void
184XcfExport::visitVLayer( VLayer& layer )
185{
186 // Layer width = image width.
187 *m_stream << static_cast<TQ_UINT32>( m_width );
188
189 // Layer height = image height.
190 *m_stream << static_cast<TQ_UINT32>( m_height );
191
192 // Layer type = RGBA.
193 *m_stream << static_cast<TQ_UINT32>( 1 );
194
195 // Layer name.
196 *m_stream << layer.name().latin1();
197
198 // Layer opacity.
199 *m_stream << static_cast<TQ_UINT32>( 6 );
200 // Property size in bytes.
201 *m_stream << static_cast<TQ_UINT32>( 4 );
202 // Fully opaque = 255.
203 *m_stream << static_cast<TQ_UINT32>( 255 );
204
205 // Layer visible?
206 *m_stream << static_cast<TQ_UINT32>( 8 );
207 // Property size in bytes.
208 *m_stream << static_cast<TQ_UINT32>( 4 );
209 // True.
210 *m_stream << static_cast<TQ_UINT32>( 1 );
211
212 // Layer linked?
213 *m_stream << static_cast<TQ_UINT32>( 9 );
214 // Property size in bytes.
215 *m_stream << static_cast<TQ_UINT32>( 4 );
216 // False.
217 *m_stream << static_cast<TQ_UINT32>( 0 );
218
219 // Preserve transparency?
220 *m_stream << static_cast<TQ_UINT32>( 10 );
221 // Property size in bytes.
222 *m_stream << static_cast<TQ_UINT32>( 4 );
223 // False.
224 *m_stream << static_cast<TQ_UINT32>( 0 );
225
226 // Apply mask?
227 *m_stream << static_cast<TQ_UINT32>( 11 );
228 // Property size in bytes.
229 *m_stream << static_cast<TQ_UINT32>( 4 );
230 // False.
231 *m_stream << static_cast<TQ_UINT32>( 0 );
232
233 // Edit mask?
234 *m_stream << static_cast<TQ_UINT32>( 12 );
235 // Property size in bytes.
236 *m_stream << static_cast<TQ_UINT32>( 4 );
237 // False.
238 *m_stream << static_cast<TQ_UINT32>( 0 );
239
240 // Show mask?
241 *m_stream << static_cast<TQ_UINT32>( 13 );
242 // Property size in bytes.
243 *m_stream << static_cast<TQ_UINT32>( 4 );
244 // False.
245 *m_stream << static_cast<TQ_UINT32>( 0 );
246
247 // Layer offsets.
248 *m_stream << static_cast<TQ_UINT32>( 15 );
249 // Property size in bytes.
250 *m_stream << static_cast<TQ_UINT32>( 8 );
251 // X-Offset.
252 *m_stream << static_cast<TQ_UINT32>( 0 );
253 // Y-Offset.
254 *m_stream << static_cast<TQ_UINT32>( 0 );
255
256 // Layer mode.
257 *m_stream << static_cast<TQ_UINT32>( 7 );
258 // Property size in bytes.
259 *m_stream << static_cast<TQ_UINT32>( 4 );
260 // Normal mode.
261 *m_stream << static_cast<TQ_UINT32>( 0 );
262
263 // TODO: Tattoo.
264 *m_stream << static_cast<TQ_UINT32>( 20 );
265 // Property size in bytes.
266 *m_stream << static_cast<TQ_UINT32>( 4 );
267 // False.
268 *m_stream << static_cast<TQ_UINT32>( 0 );
269
270 // Layer properties end.
271 *m_stream << static_cast<TQ_UINT32>( 0 );
272 // Property size in bytes.
273 *m_stream << static_cast<TQ_UINT32>( 0 );
274
275
276 // Offsets.
277 TQIODevice::Offset current = 0;
278 TQIODevice::Offset start = 0;
279 TQIODevice::Offset end = 0;
280
281 // Save current offset.
282 current = m_stream->device()->at();
283
284 // Leave space for hierarchy offsets.
285 m_stream->device()->at( current + 8 );
286
287 // Save start offset.
288 start = m_stream->device()->at();
289
290
291 // Write hierarchy.
292 writeHierarchy();
293
294
295 // Save end offset.
296 end = m_stream->device()->at();
297
298 // Return to current offset.
299 m_stream->device()->at( current );
300
301 // Save hierarchy offset.
302 *m_stream << start;
303
304
305 // Append a zero offset to indicate end of layer mask offsets.
306 *m_stream << static_cast<TQ_UINT32>( 0 );
307}
308
309void
310XcfExport::writeHierarchy()
311{
312 // Offsets.
313 TQIODevice::Offset current = 0;
314 TQIODevice::Offset start = 0;
315 TQIODevice::Offset end = 0;
316
317 // Width (again?).
318 *m_stream << m_width;
319
320 // Height (again?).
321 *m_stream << m_height;
322
323 // Color depth.
324 *m_stream << static_cast<TQ_UINT32>( 3 );
325
326
327 // Calculate level number.
328 int levX = levels( m_width, m_tileWidth );
329 int levY = levels( m_height, m_tileHeight );
330 int levels = TQMAX( levX, levY );
331
332 int width = m_width;
333 int height = m_height;
334
335 // Save current offset.
336 current = m_stream->device()->at();
337
338 // Leave space for level offsets.
339 m_stream->device()->at( current + ( levels + 1 ) * 4 );
340
341 for( int i = 0; i < levels; ++i )
342 {
343 // Save start offset.
344 start = m_stream->device()->at();
345
346 if( i == 0 )
347 {
348 // Write level.
349 writeLevel();
350 }
351 else
352 {
353 // Fake an empty level.
354 width /= 2;
355 height /= 2;
356
357 *m_stream << static_cast<TQ_UINT32>( width );
358 *m_stream << static_cast<TQ_UINT32>( height );
359 *m_stream << static_cast<TQ_UINT32>( 0 );
360 }
361
362 // Save end offset.
363 end = m_stream->device()->at();
364
365 // Return to current offset.
366 m_stream->device()->at( current );
367
368 // Save level offset.
369 *m_stream << start;
370
371 // Increment offset.
372 current = m_stream->device()->at();
373
374 // Return to end offset.
375 m_stream->device()->at( end );
376 }
377
378 // Return to current offset.
379 m_stream->device()->at( current );
380
381 // Append a zero offset to indicate end of level offsets.
382 *m_stream << static_cast<TQ_UINT32>( 0 );
383}
384
385void
386XcfExport::writeLevel()
387{
388 // Offsets.
389 TQIODevice::Offset current = 0;
390 TQIODevice::Offset start = 0;
391 TQIODevice::Offset end = 0;
392
393 *m_stream << static_cast<TQ_UINT32>( m_width );
394 *m_stream << static_cast<TQ_UINT32>( m_height );
395
396 int rows = ( m_height + m_tileHeight - 1 ) / m_tileHeight;
397 int cols = ( m_width + m_tileWidth - 1 ) / m_tileWidth;
398 int tiles = rows * cols;
399
400 // Save current offset.
401 current = m_stream->device()->at();
402
403 // Leave space for tile offsets.
404 m_stream->device()->at( current + ( tiles + 1 ) * 4 );
405
406 for( int i = 0; i < tiles; ++i )
407 {
408 // Save start offset.
409 start = m_stream->device()->at();
410
411
412 // TODO: Save tile.
413 *m_stream << static_cast<TQ_UINT8>( 1 );
414 *m_stream << static_cast<TQ_UINT8>( 1 );
415 *m_stream << static_cast<TQ_UINT8>( 1 );
416 *m_stream << static_cast<TQ_UINT8>( 1 );
417 *m_stream << static_cast<TQ_UINT8>( 1 );
418 *m_stream << static_cast<TQ_UINT8>( 1 );
419 *m_stream << static_cast<TQ_UINT8>( 1 );
420 *m_stream << static_cast<TQ_UINT8>( 1 );
421 *m_stream << static_cast<TQ_UINT8>( 1 );
422 *m_stream << static_cast<TQ_UINT8>( 1 );
423 *m_stream << static_cast<TQ_UINT8>( 1 );
424 *m_stream << static_cast<TQ_UINT8>( 1 );
425
426
427 // Save end offset.
428 end = m_stream->device()->at();
429
430 // Return to current offset.
431 m_stream->device()->at( current );
432
433 // Save tile offset.
434 *m_stream << start;
435
436 // Increment offset.
437 current = m_stream->device()->at();
438
439 // Return to end offset.
440 m_stream->device()->at( end );
441 }
442}
443
444int
445XcfExport::levels( int layerSize, int tileSize )
446{
447 int l = 1;
448
449 while( layerSize > tileSize )
450 {
451 layerSize /= 2;
452 l += 1;
453 }
454
455 return l;
456}
457
458#include "xcfexport.moc"