1 /****************************************************************************
3 * export_import.c -- Lunapaint, *
4 * http://developer.berlios.de/projects/lunapaintami/ *
5 * Copyright (C) 2006, 2007, Hogne Titlestad <hogga@sub-ether.org> *
6 * Copyright (C) 2009-2011 LunaPaint Development Team *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the Free Software Foundation, *
20 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ****************************************************************************/
24 #include "export_import.h"
27 Object
*exportBtnCancel
;
28 Object
*exportBtnExport
;
29 Object
*exportPopFilename
;
32 Object
*exportAnimMethod
;
33 Object
*exportAnimMode
;
34 Object
*exportAnimRangeStart
;
35 Object
*exportAnimRangeEnd
;
36 Object
*exportAnimBtnExport
;
37 Object
*exportAnimBtnCancel
;
40 Object
*importBtnCancel
;
41 Object
*importBtnImport
;
42 Object
*importPopFilename
;
47 struct Hook export_hook
;
48 struct Hook import_hook
;
49 struct Hook exportanimation_hook
;
51 static STRPTR exp_datatypes
[] = { NULL
, NULL
, NULL
, NULL
, NULL
};
52 static STRPTR exp_mode
[] = { NULL
, NULL
, NULL
};
53 static STRPTR exp_titles
[] = { NULL
, NULL
, NULL
};
54 static STRPTR exp_anim_mode
[] = { NULL
, NULL
, NULL
};
55 static STRPTR exp_anim_method
[] = { NULL
, NULL
, NULL
};
56 static STRPTR imp_datatypes
[] = { NULL
, NULL
};
58 HOOKPROTONHNO(exportanimation_func
, void, int *param
)
62 unsigned char *filename
= NULL
;
63 get ( exportCycDT
, MUIA_Cycle_Active
, &datatype
);
64 get ( exportPopFilename
, MUIA_String_Contents
, &filename
);
66 if ( filename
== NULL
)
69 createImageFromAnimation ( globalActiveCanvas
, datatype
, filename
);
75 HOOKPROTONHNO(export_func
, void, int *param
)
78 int mode
= 0, datatype
= 0;
79 unsigned char *filename
= NULL
;
80 get ( exportMode
, MUIA_Cycle_Active
, &mode
);
81 get ( exportCycDT
, MUIA_Cycle_Active
, &datatype
);
82 get ( exportPopFilename
, MUIA_String_Contents
, &filename
);
84 if ( filename
== NULL
)
87 unsigned int *buffer
= generateExportableBuffer ( globalActiveCanvas
, mode
, datatype
);
89 // Export with the JPEG datatype
92 exportDT ( globalActiveCanvas
->width
, globalActiveCanvas
->height
, buffer
, filename
, "jpeg" );
94 // Export with PNG code
95 else if ( datatype
== 1 )
97 exportPNG ( globalActiveCanvas
->width
, globalActiveCanvas
->height
, buffer
, filename
);
99 // Save in RAW (64-bit) format
100 else if ( datatype
== 2 )
103 if ( ( myfile = Open ( filename, MODE_READWRITE ) ) != NULL )
105 Write ( myfile, globalActiveCanvas->activebuffer, sizeof ( unsigned long long int ) * ( globalActiveCanvas->width * globalActiveCanvas->height ) );
108 else printf ( "Failed to save image raw..\n" );*/
109 printf ( "64-bit export temporarily disabled.\n" );
111 // Save another in raw format
112 else if ( datatype
== 3 )
115 if ( ( myfile
= Open ( filename
, MODE_NEWFILE
) ) != BNULL
)
117 Write ( myfile
, buffer
, sizeof ( unsigned int ) * ( globalActiveCanvas
->width
* globalActiveCanvas
->height
) );
120 else printf ( "Failed to save image raw..\n" );
126 HOOKPROTONHNO(import_func
, void, int *param
)
130 unsigned char *filename
= NULL
;
131 get ( importCycDT
, MUIA_Cycle_Active
, &datatype
);
132 get ( importPopFilename
, MUIA_String_Contents
, &filename
);
137 // We have a filename!!
138 if ( filename
!= NULL
)
141 if ( ( myfile
= Open ( filename
, MODE_OLDFILE
) ) != BNULL
)
144 myfile
, globalActiveCanvas
->activebuffer
,
145 8 * globalActiveCanvas
->width
* globalActiveCanvas
->height
148 globalActiveCanvas
->winHasChanged
= TRUE
;
149 DoMethod ( globalActiveWindow
->area
, MUIM_Draw
, FALSE
);
150 set ( importWindow
, MUIA_Window_Open
, FALSE
);
152 else printf ( "Failed to load image raw..\n" );
159 unsigned int *generateExportableBuffer ( struct oCanvas
*canvas
, int mode
, int datatype
)
161 unsigned int *buffer
= NULL
;
165 if ( ( buffer
= AllocVec ( 4 * canvas
->width
* canvas
->height
, MEMF_ANY
|MEMF_CLEAR
) ) == NULL
)
168 int size
= canvas
->width
* canvas
->height
;
169 int i
= 0; for ( ; i
< size
; i
++ )
171 struct rgba64 c64
= *( struct rgba64
*)&canvas
->activebuffer
[ i
];
173 // Align the colors reverse
174 c64
= ( struct rgba64
){ c64
.a
, c64
.b
, c64
.g
, c64
.r
};
176 // Set the colors in 32-but order
177 // datatype 0 is JPEG
180 buffer
[ i
] = *( unsigned int *)&( ( struct rgba32
){
181 ( double )c64
.a
/ 256, ( double )c64
.r
/ 256,
182 ( double )c64
.g
/ 256, ( double )c64
.b
/ 256
185 // If datatype is png, include all channels
186 else if ( datatype
== 1 )
188 buffer
[ i
] = *( unsigned int *)&( ( struct rgba32
){
189 ( double )c64
.r
/ 256, ( double )c64
.g
/ 256,
190 ( double )c64
.b
/ 256, ( double )c64
.a
/ 256
196 buffer
[ i
] = *( unsigned int *)&( ( struct rgba32
){
197 ( double )c64
.b
/ 256, ( double )c64
.g
/ 256,
198 ( double )c64
.r
/ 256, ( double )c64
.a
/ 256
203 else if ( mode
== 1 )
205 // Remove tool graphic that's overlayn
206 removePrevToolPreview ( );
207 ULONG tool
= globalCurrentTool
;
208 globalCurrentTool
= -1;
210 // Get flattened layers without tool preview
211 buffer
= renderCanvas ( canvas
, 0, 0, canvas
->width
, canvas
->height
, TRUE
);
213 // Reset tool setting
214 globalCurrentTool
= tool
;
216 // Fix color order for different storage formats
217 int size
= canvas
->width
* canvas
->height
;
218 int i
= 0; for ( ; i
< size
; i
++ )
220 struct rgba32 c
= *( struct rgba32
*)&buffer
[ i
];
222 // Set the colors in 32-bit order
223 // datatype 0 is JPEG
225 c
= ( struct rgba32
){ c
.a
, c
.r
, c
.g
, c
.b
};
226 else if ( datatype
== 1 )
227 c
= ( struct rgba32
){ c
.r
, c
.g
, c
.b
, c
.a
};
229 c
= ( struct rgba32
){ c
.b
, c
.g
, c
.r
, c
.a
};
231 buffer
[ i
] = *( unsigned int *)&c
;
237 void makeExportWindow ( )
239 exp_datatypes
[0] = _(MSG_EXPORT_JPEG
);
240 exp_datatypes
[1] = _(MSG_EXPORT_PNG
);
241 exp_datatypes
[2] = _(MSG_EXPORT_RAW64
);
242 exp_datatypes
[3] = _(MSG_EXPORT_RAW32
);
244 exp_mode
[0] = _(MSG_EXPORT_ACTIV_LAYER
);
245 exp_mode
[1] = _(MSG_EXPORT_FLAT_LAYER
);
247 exp_titles
[0] = _(MSG_EXPORT_ONE_FRAME
);
248 exp_titles
[1] = _(MSG_EXPORT_FRAMES
);
250 exp_anim_mode
[0] = _(MSG_EXPORT_ACTIV_LAYER
);
251 exp_anim_mode
[1] = _(MSG_EXPORT_FLAT_LAYER
);
253 exp_anim_method
[0] = _(MSG_EXPORT_FILEPERFRAME
);
254 exp_anim_method
[1] = _(MSG_EXPORT_STRIP
);
256 exportWindow
= WindowObject
,
257 MUIA_Window_ScreenTitle
, __(MSG_EXPORT_SCR
),
258 MUIA_Window_Title
, __(MSG_EXPORT_WIN
),
259 MUIA_Window_CloseGadget
, TRUE
,
260 MUIA_Window_Screen
, ( IPTR
)lunaPubScreen
,
261 MUIA_Window_ID
, MAKE_ID('L','P','W','E'),
262 WindowContents
, VGroup
,
264 MUIA_Frame
, MUIV_Frame_Group
,
266 MUIA_Text_Contents
, _(MSG_EXPORT_FILENAME
),
270 ASLFR_DoSaveMode
, TRUE
,
271 MUIA_Popstring_String
, exportPopFilename
= MUI_MakeObject (
272 MUIO_String
, NULL
, 200
274 MUIA_Popstring_Button
, PopButton ( MUII_PopFile
),
280 MUIA_Text_Contents
, _(MSG_EXPORT_DT
),
282 Child
, exportCycDT
= CycleObject
,
283 MUIA_Cycle_Entries
, exp_datatypes
,
288 Child
, RegisterObject
,
289 MUIA_Register_Titles
, exp_titles
,
290 MUIA_Register_Frame
, MUIV_Frame_Group
,
296 MUIA_Frame
, MUIV_Frame_Group
,
299 Child
, exportMode
= CycleObject
,
300 MUIA_Cycle_Entries
, exp_mode
,
305 Child
, exportBtnExport
= SimpleButton ( __(MSG_EXPORT_EXPORT
) ),
306 Child
, exportBtnCancel
= SimpleButton ( __(MSG_EXPORT_CANCEL
) ),
315 MUIA_Frame
, MUIV_Frame_Group
,
318 Child
, exportAnimMode
= CycleObject
,
319 MUIA_Cycle_Entries
, exp_anim_mode
,
322 Child
, exportAnimMethod
= CycleObject
,
323 MUIA_Cycle_Entries
, exp_anim_method
,
330 MUIA_Text_Contents
, __(MSG_EXPORT_FRAMERANGE
),
332 Child
, exportAnimRangeStart
= StringObject
,
333 MUIA_String_Accept
, ( IPTR
)"0123456789",
334 MUIA_String_Format
, MUIV_String_Format_Right
,
335 MUIA_String_Integer
, 1,
336 MUIA_String_MaxLen
, 10,
337 MUIA_Frame
, MUIV_Frame_String
,
341 MUIA_Text_Contents
, " - ",
343 Child
, exportAnimRangeEnd
= StringObject
,
344 MUIA_String_Accept
, ( IPTR
)"0123456789",
345 MUIA_String_Format
, MUIV_String_Format_Right
,
346 MUIA_String_Integer
, 1,
347 MUIA_String_MaxLen
, 10,
348 MUIA_Frame
, MUIV_Frame_String
,
353 Child
, exportAnimBtnExport
= SimpleButton ( __(MSG_EXPORT_FRAMES
) ),
354 Child
, exportAnimBtnCancel
= SimpleButton ( __(MSG_EXPORT_CANCEL
) ),
364 exportWindow
, MUIM_Notify
, MUIA_Window_CloseRequest
, TRUE
,
365 ( IPTR
)exportWindow
, 2, MUIM_Set
, MUIA_Window_Open
368 exportBtnCancel
, MUIM_Notify
, MUIA_Pressed
, FALSE
,
369 ( IPTR
)exportWindow
, 2, MUIM_Set
, MUIA_Window_Open
372 exportAnimBtnCancel
, MUIM_Notify
, MUIA_Pressed
, FALSE
,
373 ( IPTR
)exportWindow
, 2, MUIM_Set
, MUIA_Window_Open
377 MakeStaticHook(export_hook
, &export_func
);
379 exportBtnExport
, MUIM_Notify
, MUIA_Pressed
, FALSE
,
380 ( IPTR
)exportWindow
, 2, MUIM_CallHook
, &export_hook
382 MakeStaticHook(exportanimation_hook
, &exportanimation_func
);
384 exportAnimBtnExport
, MUIM_Notify
, MUIA_Pressed
, FALSE
,
385 ( IPTR
)exportWindow
, 2, MUIM_CallHook
, &exportanimation_hook
389 void makeImportWindow ( )
391 imp_datatypes
[0] = _(MSG_EXPORT_RAW64
);
393 importWindow
= WindowObject
,
394 MUIA_Window_ScreenTitle
, __(MSG_IMPORT_SCR
),
395 MUIA_Window_Title
, __(MSG_IMPORT_WIN
),
396 MUIA_Window_CloseGadget
, TRUE
,
397 MUIA_Window_Screen
, ( IPTR
)lunaPubScreen
,
398 MUIA_Window_ID
, MAKE_ID('L','P','W','I'),
399 WindowContents
, VGroup
,
401 MUIA_Frame
, MUIV_Frame_Group
,
404 MUIA_Text_Contents
, __(MSG_IMPORT_FILENAME
),
408 ASLFR_DoSaveMode
, TRUE
,
409 MUIA_Popstring_String
, importPopFilename
= MUI_MakeObject ( MUIO_String
, NULL
, 200 ),
411 MUIA_Popstring_Button
, PopButton ( MUII_PopFile
),
415 MUIA_Text_Contents
, __(MSG_IMPORT_ACTIV_LAYER
),
418 MUIA_Text_Contents
, __(MSG_IMPORT_DT
),
420 Child
, importCycDT
= CycleObject
,
421 MUIA_Cycle_Entries
, imp_datatypes
,
427 MUIA_Frame
, MUIV_Frame_Group
,
429 Child
, importBtnImport
= SimpleButton ( __(MSG_IMPORT_IMPORT
) ),
430 Child
, importBtnCancel
= SimpleButton ( __(MSG_IMPORT_CANCEL
) ),
437 importWindow
, MUIM_Notify
, MUIA_Window_CloseRequest
, TRUE
,
438 ( IPTR
)importWindow
, 3, MUIM_Set
, MUIA_Window_Open
, FALSE
441 importBtnCancel
, MUIM_Notify
, MUIA_Pressed
, FALSE
,
442 ( IPTR
)importWindow
, 3, MUIM_Set
, MUIA_Window_Open
, FALSE
446 MakeStaticHook(import_hook
, &import_func
);
448 importBtnImport
, MUIM_Notify
, MUIA_Pressed
, FALSE
,
449 ( IPTR
)importWindow
, 3, MUIM_CallHook
, &import_hook
453 void createImageFromAnimation ( struct oCanvas
*canv
, int datatype
, char *filename
)
456 int AnimMode
= 0, AnimMethod
= 0, FrameStart
= 0, FrameEnd
= 0;
457 get ( exportAnimMode
, MUIA_Cycle_Active
, &AnimMode
);
458 get ( exportAnimMethod
, MUIA_Cycle_Active
, &AnimMethod
);
459 get ( exportAnimRangeStart
, MUIA_String_Integer
, &FrameStart
);
460 get ( exportAnimRangeEnd
, MUIA_String_Integer
, &FrameEnd
);
462 // Restrict the export frame range
463 if ( FrameStart
< 1 ) FrameStart
= 1;
464 if ( FrameEnd
< 1 ) FrameEnd
= 1;
465 if ( FrameStart
> FrameEnd
)
467 int tmp
= FrameStart
;
468 FrameStart
= FrameEnd
;
471 if ( FrameEnd
> canv
->totalFrames
)
472 FrameEnd
= canv
->totalFrames
;
474 // One vertical strip
475 if ( AnimMethod
== 1 )
477 // Make room for buffer
478 int framecount
= 1 + FrameEnd
- FrameStart
;
479 int framesize
= canv
->width
* canv
->height
* 4;
480 int framelength
= canv
->width
* canv
->height
;
481 int bufsize
= framesize
* framecount
;
482 int tmpFrame
= canv
->currentFrame
;
485 unsigned int *animBuf
= NULL
;
487 if ( ( animBuf
= AllocVec ( bufsize
, MEMF_ANY
|MEMF_CLEAR
) ) == NULL
)
490 int f
= FrameStart
; for ( ; f
<= FrameEnd
; f
++ )
492 canv
->currentFrame
= f
- 1;
493 setActiveBuffer ( canv
);
495 unsigned int *buf
= NULL
;
496 if ( ( buf
= generateExportableBuffer ( canv
, AnimMode
, datatype
) ) == 0 )
498 // not enough memory...
503 // Copy pixels from buf to animbuf
504 int i
= 0; for ( ; i
< framelength
; i
++ )
506 animBuf
[ offset
+ i
] = buf
[ i
];
510 offset
+= framelength
;
513 // Export with the JPEG datatype
518 canv
->height
* framecount
, animBuf
, filename
, "jpeg"
521 // Export with png export code
522 else if ( datatype
== 1 )
524 exportPNG ( canv
->width
, canv
->height
* framecount
, animBuf
, filename
);
526 // Save in RAW (64-bit) format
527 else if ( datatype
== 2 )
529 // NOT YET IMPLEMENTED!
530 printf ( "64-bit animation export is not yet implemented!\n" );
532 // Save another in raw format
533 else if ( datatype
== 3 )
536 if ( ( myfile
= Open ( filename
, MODE_NEWFILE
) ) != BNULL
)
538 Write ( myfile
, animBuf
, bufsize
);
541 else printf ( "Failed to save image raw..\n" );
547 // Reset the currentframe to where it was
548 canv
->currentFrame
= tmpFrame
;
549 setActiveBuffer ( canv
);
551 // One image pr frame
554 // Make room for buffer
555 int framesize
= canv
->width
* canv
->height
* 4;
556 int tmpFrame
= canv
->currentFrame
;
558 unsigned int *buf
= NULL
;
562 for ( ; f
<= FrameEnd
; f
++ )
564 char *tmpFilename
= AllocVec ( 255, MEMF_ANY
|MEMF_CLEAR
);
565 sprintf ( tmpFilename
, "%s%04d", filename
, ( f
- FrameStart
+ 1 ) );
567 canv
->currentFrame
= f
- 1;
568 setActiveBuffer ( canv
);
570 buf
= generateExportableBuffer ( canv
, AnimMode
, datatype
);
572 // Export with the JPEG datatype
575 exportDT ( canv
->width
, canv
->height
, buf
, tmpFilename
, "jpeg" );
577 else if ( datatype
== 1 )
579 exportPNG ( canv
->width
, canv
->height
, buf
, tmpFilename
);
581 // Save in RAW (64-bit) format
582 else if ( datatype
== 2 )
584 // NOT YET IMPLEMENTED!
585 printf ( "64-bit animation export is not yet implemented!\n" );
587 // Save another in raw format
588 else if ( datatype
== 3 )
591 if ( ( myfile
= Open ( tmpFilename
, MODE_NEWFILE
) ) != BNULL
)
593 Write ( myfile
, buf
, framesize
);
596 else printf ( "Failed to save image raw..\n" );
599 FreeVec ( tmpFilename
);
603 // Reset the currentframe to where it was
604 canv
->currentFrame
= tmpFrame
;
605 setActiveBuffer ( canv
);
609 void exportDT ( int w
, int h
, unsigned int *buffer
, unsigned char *filename
, const char *format
)
611 if ( filename
!= NULL
)
613 // Generate a datatype object
614 Object
*DTImage
= NewDTObject (
616 DTA_SourceType
, DTST_RAM
,
617 DTA_BaseName
, ( IPTR
)format
,
618 PDTA_DestMode
, PMODE_V43
,
621 // Return if this doesn't work
626 struct BitMapHeader
*bmhdr
;
627 if ( !( GetDTAttrs ( DTImage
, PDTA_BitMapHeader
, ( IPTR
)&bmhdr
, TAG_DONE
) ) )
630 // Write the data in memory
631 struct pdtBlitPixelArray dtObj
;
633 dtObj
.MethodID
= PDTM_WRITEPIXELARRAY
;
634 dtObj
.pbpa_PixelFormat
= PBPAFMT_ARGB
;
635 dtObj
.pbpa_PixelArrayMod
= w
;
637 dtObj
.pbpa_Width
= w
;
638 dtObj
.pbpa_Height
= 1;
640 bmhdr
->bmh_Width
= w
;
641 bmhdr
->bmh_Height
= h
;
642 bmhdr
->bmh_Depth
= 24;
643 bmhdr
->bmh_PageWidth
= 320;
644 bmhdr
->bmh_PageHeight
= 240;
646 int y
= 0; for ( ; y
< h
; y
++ )
649 dtObj
.pbpa_PixelData
= ( APTR
)( buffer
+ ( y
* w
) );
650 DoMethodA ( DTImage
, ( Msg
)&dtObj
);
653 // Write the data to disk
655 if ( ( filehandle
= Open ( filename
, MODE_NEWFILE
) ) )
657 struct dtWrite dtwObj
;
658 dtwObj
.MethodID
= DTM_WRITE
;
659 dtwObj
.dtw_GInfo
= NULL
;
660 dtwObj
.dtw_FileHandle
= filehandle
;
661 dtwObj
.dtw_Mode
= DTWM_RAW
;
662 dtwObj
.dtw_AttrList
= NULL
;
663 DoMethodA ( DTImage
, ( Msg
)&dtwObj
);
664 Close ( filehandle
);
668 DisposeDTObject ( DTImage
);
672 static void png_user_write( png_structp png_ptr
, png_bytep data
, png_size_t length
)
674 Write ( png_get_io_ptr(png_ptr
), data
, length
);
676 static void png_user_flush( png_structp png_ptr
)
678 // do nothing - nothing to flush!
680 void exportPNG ( int w
, int h
, unsigned int *buffer
, unsigned char *filename
)
687 // Create a write struct.
688 if ( !(png_ptr
= png_create_write_struct( PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
) ) )
691 // Create an info struct.
692 if ( !( info_ptr
= png_create_info_struct( png_ptr
) ) )
694 // Free the unused write struct.
695 png_destroy_write_struct ( &png_ptr
, ( png_infopp
)NULL
);
699 // Open file for writing
700 if ( ( file
= Open ( filename
, MODE_NEWFILE
) ) == BNULL
)
703 // Register the write function.
704 png_set_write_fn ( png_ptr
, (APTR
) file
, png_user_write
, png_user_flush
);
706 // Create the info header.
708 png_ptr
, info_ptr
, w
, h
, 8,
711 PNG_COMPRESSION_TYPE_DEFAULT
,
712 PNG_FILTER_TYPE_DEFAULT
715 // Write the info header.
716 png_write_info ( png_ptr
, info_ptr
);
719 for ( i
= 0; i
< h
; i
++ )
720 png_write_row( png_ptr
, ( png_bytep
)&buffer
[ i
* w
] );
722 // Write file end and clean up
723 png_write_end( png_ptr
, info_ptr
);
724 png_destroy_write_struct( &png_ptr
, &info_ptr
);
726 // Close file and done!