#!/usr/local/bin/perl # a converter from magicpoint (mgp) to OpenOffice Impress (odp) # Copyright (C) 2008 Kengo Ichiki # $Id: mgp2odp,v 1.2 2008/02/10 05:44:20 ichiki Exp $ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. use OpenOffice::OODoc; use Image::Size; ooLocalEncoding 'utf8'; # global variables my $dpcm; # dot per cm $dpcm = 1024.0 / 25.0; #------------------------------------------------------------------------------ # INPUT # $p : $presentation # $page : $page # $text : text of the item sub add_title (@) { my ($p, $page, $text) = @_; my $draw_frame = $p->appendElement ($page, 'draw:frame', attribute => { 'presentation:style-name' => 'pr1', 'draw:text-style-name' => 'P1', 'draw:layer' => 'layout', 'svg:width' => '25.199cm', 'svg:height' => '3.507cm', 'svg:x' => '1.4cm', 'svg:y' => '0.837cm', 'presentation:class' => 'title' } ); # attach a new box to the frame my $text_box = $p->appendElement($draw_frame, 'draw:text-box'); # put a new paragraph in the box $p->appendParagraph(attachment => $text_box, text => $text, style => "P1"); 1; } #------------------------------------------------------------------------------ # INPUT # $p : $presentation # $page : $page # $x, $y : (string) ex. $x = "1.4cm", $y = "4.914cm". # $width, $height : (string) ex. $width = "25.199cm", $height = "13.609cm". # $text : text of the item sub add_text (@) { my ($p, $page, $x, $y, $width, $height, $text) = @_; my $draw_frame = $p->appendElement ($page, 'draw:frame', attribute => { 'presentation:style-name' => 'pr1', 'draw:text-style-name' => 'P1', 'draw:layer' => 'layout', 'svg:width' => $width, 'svg:height' => $height, 'svg:x' => $x, 'svg:y' => $y, 'presentation:class' => 'title' } ); # attach a new box to the frame my $text_box = $p->appendElement($draw_frame, 'draw:text-box'); # put a new paragraph in the box #$p->appendParagraph(attachment => $text_box, text => $text, style => "P5"); $p->appendParagraph(attachment => $text_box, text => $text, style => "P6"); 1; } #------------------------------------------------------------------------------ # INPUT # $p : $presentation # $page : $page # $x, $y : (string) ex. $x = "1.4cm", $y = "4.914cm". # $width, $height : (string) ex. $width = "25.199cm", $height = "13.609cm". # OUTPUT # $text_box : (draw:text-box) : can be used by append_text() sub make_text_frame (@) { my ($p, $page, $x, $y, $width, $height, $text) = @_; my $draw_frame = $p->appendElement ($page, 'draw:frame', attribute => { 'presentation:style-name' => 'pr3', 'draw:text-style-name' => 'P6', 'draw:layer' => 'layout', 'svg:width' => $width, 'svg:height' => $height, 'svg:x' => $x, 'svg:y' => $y, 'presentation:class' => 'title', 'presentation:user-transformed' => 'true' } ); # attach a new box to the frame my $text_box = $p->appendElement($draw_frame, 'draw:text-box'); $text_box; } #------------------------------------------------------------------------------ # INPUT # $p : $presentation # $parent : # $text : text of the item (string) # $flag_bold : # $flag_italic : # $flag_underline : # $flag_shadow : sub append_text (@) { my ($p, $parent, $text, $flag_bold, $flag_italic, $flag_underline, $flag_shadow) = @_; my ($text); my ($n) = 0; $text[$n] = $p->appendElement($parent, 'text:span', attribute => {'text:style-name' => 'T1'}); $n++; if ($flag_bold == 1) { $text[$n] = $p->appendElement($text[$n-1], 'text:span', attribute => {'text:style-name' => 'T2'}); $n++; } if ($flag_italic == 1) { $text[$n] = $p->appendElement($text[$n-1], 'text:span', attribute => {'text:style-name' => 'T3'}); $n++; } if ($flag_underline == 1) { $text[$n] = $p->appendElement($text[$n-1], 'text:span', attribute => {'text:style-name' => 'T4'}); $n++; } if ($flag_shadow == 1) { $text[$n] = $p->appendElement($text[$n-1], 'text:span', attribute => {'text:style-name' => 'T6'}); $n++; } # put a new paragraph in the box $p->appendParagraph(attachment => $text[$n-1], text => $text, style => "P6"); 1; } #------------------------------------------------------------------------------ # INPUT # $p : $presentation # $page : $page # $x, $y : (string) ex. $x = "1.4cm", $y = "4.914cm". # $width, $height : (string) ex. $width = "25.199cm", $height = "13.609cm". # OUTPUT # $test_box : draw:text-box sub add_outline (@) { my ($p, $page, $x, $y, $width, $height) = @_; my $draw_frame = $p->appendElement ($page, 'draw:frame', attribute => { 'presentation:style-name' => 'pr2', 'draw:layer' => 'layout', 'svg:width' => $width, 'svg:height' => $height, 'svg:x' => $x, 'svg:y' => $y, 'presentation:class' => 'outline'}); # attach a new box to the frame my $text_box = $p->appendElement($draw_frame, 'draw:text-box'); $text_box; } #------------------------------------------------------------------------------ # INPUT # $p : $presentation # $tb : $text_box # $n : level of the list (1, 2, 3, ...) # $text : text of the item sub add_list_item (@) { my ($p, $tb, $n1, $text) = @_; if ($n1 < 1){ 0; } # $n is shifted as (0, 1, 2, ...) $n = $n1 - 1; my (@tli, @tl); # draw:text-box -> text:list $tl[0] = $p->appendElement($tb, 'text:list', attribute => {'text:style-name' => 'L2'}); for ($i = 0; $i < $n; $i ++) { $tli[$i] = $p->appendElement($tl[$i], 'text:list-item'); $tl [$i+1] = $p->appendElement($tli[$i], 'text:list'); } # draw:text-box -> text:list -> test:list-item $tli[$n] = $p->appendElement($tl[$n], 'text:list-item'); # put a new paragraph in the box $p->appendParagraph(attachment => $tli[$n], text => $text, style => 'P'.($n1+1)); 1; } #------------------------------------------------------------------------------ # INPUT # $p : $presentation # $tb : $text_box # $n : level of the list (1, 2, 3, ...) # $text : text of the item # OUTPUT # (text:list-item) : can be used by append_text() sub make_list_item (@) { my ($p, $tb, $n1, $text) = @_; if ($n1 < 1){ 0; } # $n is shifted as (0, 1, 2, ...) $n = $n1 - 1; my (@tli, @tl); # draw:text-box -> text:list $tl[0] = $p->appendElement($tb, 'text:list', attribute => {'text:style-name' => 'L2'}); for ($i = 0; $i < $n; $i ++) { $tli[$i] = $p->appendElement($tl[$i], 'text:list-item'); $tl [$i+1] = $p->appendElement($tli[$i], 'text:list'); } # draw:text-box -> text:list -> test:list-item $tli[$n] = $p->appendElement($tl[$n], 'text:list-item'); $tli[$n]; } #------------------------------------------------------------------------------ # add image by appendElement # INPUT # $p : $presentation # $page : $page # $x, $y : (string) ex. $x = "1.4cm", $y = "4.914cm". # $width, $height : (string) ex. $width = "25.199cm", $height = "13.609cm". # $file : image file sub add_image (@) { my ($p, $page, $x, $y, $width, $height, $file) = @_; my $draw_frame = $p->appendElement ($page, 'draw:frame', attribute => { 'draw:style-name' => 'gr1', 'draw:text-style-name' => 'P6', 'draw:layer' => 'layout', 'presentation:class' => 'graphic', 'svg:width' => $width, 'svg:height' => $height, 'svg:x' => $x, 'svg:y' => $y } ); my $draw_image = $p->appendElement ($draw_frame, 'draw:image', attribute => { 'xlink:type' => 'simple', 'xlink:show' => 'embed', 'xlink:actuate' => 'onLoad' } ); $p->appendParagraph (attachment => $draw_image, text => "", style => "P1"); # import the image my ($base, $path, $suffix) = File::Basename::fileparse($file, '\..*'); my $tmpl = $p->{'image_fpath'}; my $element = $p->getImageElement($draw_frame); my $link = $tmpl . $base . $suffix; $p->imageLink($element, $link); $p->raw_import($link, $file); 1; } #------------------------------------------------------------------------------ # Magicpoint related sub get_mgp_options ($) { my ($s) = @_; my ($flag_page, $flag_cont, $flag_center, $flag_left, $flag_right, $fore, $back, $size, $flag_filter, $flag_endfilter, $str_image); $flag_page = 0; $flag_cont = 0; $flag_center = 0; $flag_left = 0; $flag_right = 0; $fore = ""; $back = ""; $size = 0; $flag_filter = 0; $flag_endfilter = 0; $str_image = ""; if (not $s =~ /^%%/) { $s =~ s/^%//; my @opts = split(/,/, $s); $n = @opts; for ($i = 0; $i < $n; $i++) { #print "# opts[$i] = ", $opts[$i], "\n"; $opts[$i] =~ s/^ //g; #print "# =>", $opts[$i], "\n"; my @opt = split(/ /, $opts[$i]); if ($opt[0] eq "page" or $opt[0] eq "PAGE") { $flag_page = 1; } elsif ($opt[0] eq 'cont' or $opt[0] eq 'CONT') { $flag_cont = 1; } elsif ($opt[0] eq 'center' or $opt[0] eq 'CENTER') { $flag_center = 1; } elsif ($opt[0] eq 'left' or $opt[0] eq 'LEFT') { $flag_left = 1; } elsif ($opt[0] eq 'right' or $opt[0] eq 'RIGHT') { $flag_right = 1; } elsif ($opt[0] eq 'fore' or $opt[0] eq 'FORE') { $opt[1] =~ s/\"//g; $fore = $opt[1]; } elsif ($opt[0] eq 'back' or $opt[0] eq 'BACK') { $opt[1] =~ s/\"//g; $back = $opt[1]; } elsif ($opt[0] eq 'size' or $opt[0] eq 'SIZE') { $size = $opt[1]; } elsif ($opt[0] eq 'filter' or $opt[0] eq 'FILTER') { $flag_filter = 1; } elsif ($opt[0] eq 'endfilter' or $opt[0] eq 'ENDFILTER') { $flag_endfilter = 1; } elsif ($opt[0] eq 'image' or $opt[0] eq 'IMAGE') { $str_image = $opts[$i]; } elsif ($opt[0] eq 'newimage' or $opt[0] eq 'NEWIMAGE') { $str_image = $opts[$i]; } } } ($flag_page, $flag_cont, $flag_center, $flag_left, $flag_right, $fore, $back, $size, $flag_filter, $flag_endfilter, $str_image); } #------------------------------------------------------------------------------ # bet bounding box from eps file by ghostscript's bbox device # INPUT # $file : eps filename # OUTPUT # ($x, $y) : size in cm sub bbox_eps ($) { my $file = shift; my ($x0, $y0, $x1, $y1); open(GS, "gs -dNOPAUSE -dBATCH -sDEVICE=bbox -sOutputFile=- $file 2>&1 |"); while () { chop; if (/^\%\%BoundingBox: (\d+) +(\d+) +(\d+) +(\d+)/) { $x0 = $1; $y0 = $2; $x1 = $3; $y1 = $4; break; } } close(GS); my ($x, $y); $x = 2.54 * ($x1-$x0) / 75.0; $y = 2.54 * ($y1-$y0) / 75.0; # 1 inch = 2.54 cm ($x, $y); } #------------------------------------------------------------------------------ # parse image command line # INPUT # $line : # $path : sub parse_image (@) { my ($line) = shift; $line =~ s/ / /g; my ($path) = shift; my @opt = split(/ /, $line); print "# line : ", $line, "\n"; my ($n, $i); $n = @opt; my ($width, $height, $img_file); $width = "2cm"; # now fixed $height = "1cm"; # now fixed $img_file = ""; my $flag_eps = 0; my ($scr_x, $scr_y) = (0, 0); my ($x_cm, $y_cm); if ($opt[0] eq "image" or $opt[0] eq "IMAGE" or $opt[0] eq "newimage" or $opt[0] eq "NEWIMAGE") { for ($i = 1; $i < $n; $i++) { if ($opt[$i] =~ /^\"(.+)\"$/) { my $tmp = $1; if ($tmp =~ /\.jpg$/ or $tmp =~ /\.jpeg$/ or $tmp =~ /\.png$/ or $tmp =~ /\.gif$/) { $img_file = $tmp; # by Image::Size my ($pix_x, $pix_y) = imgsize($path . $img_file); # (global) $dpcm : dot per cm $x_cm = $pix_x / $dpcm; $y_cm = $pix_y / $dpcm; $width = "$x_cm" . "cm"; $height = "$y_cm" . "cm"; } elsif ($tmp =~ /\.eps$/) { $flag_eps = 1; $img_file = $tmp; ($x_cm, $y_cm) = bbox_eps ($path . $img_file); $width = "$x_cm" . "cm"; $height = "$y_cm" . "cm"; } else { print "invalid image format\n"; } } elsif ($opt[$i] eq "-xscrzoom") { # zoom -- just ignore $n ++; } elsif ($opt[$i] eq "-rotate") { # zoom -- just ignore $n ++; } elsif ($opt[$i] =~ /(\d+)x(\d+)/) { # the original screensize for auto-rescale (to 1024x768) $scr_x = $1; $scr_y = $2; } } } if ($flag_eps == 1 and $scr_x != 0) { $x_cm *= 1024.0 / $scr_x; $y_cm *= 768.0 / $scr_y; $width = "$x_cm" . "cm"; $height = "$y_cm" . "cm"; } print "# size : $width, $height \n"; ($width, $height, $img_file); } #------------------------------------------------------------------------------ # remove the entry style:protect="size" # INPUT # $p : $presentation # $name : style name to remove sub remove_style_protect ($) { my $p = shift; my $name = shift; unless ($name) { $name = "gr1"; } my @style_graphic = $p->selectElementsByAttribute ('//style:style', 'style:family', 'graphic'); my $n = @style_graphic; my $i; for ($i = 0; $i < $n; $i++) { my $style_name = $p->getAttribute ($style_graphic[$i], 'style:name'); if ($style_name eq $name) { my $prop = $style_graphic[$i]->first_child ('style:graphic-properties'); $p->removeAttribute($prop, 'style:protect'); } } 1; } #------------------------------------------------------------------------------ # convert mgp to odp # INPUT # $input : mgp file # $output : odp file # $path : current path of the mgp file sub convert_mgp_to_odp (@) { my ($input, $output, $path) = @_; my $presentation = ooDocument (file => $output, create => 'presentation'); remove_style_protect ($presentation); my $ip = 0; # page number my (@page); # OODoc page my ($tb); # OODoc text-box for list my $flag_body = 0; # line count for each page (from 1, ...) my $flag_outline = 0; # flag for the body entry my ($title); my $flag_fltcmd = 0; # flag for the filter command my ($img_x, $img_y); open(MGPFILE, "< $input") or die "Cannot open $input"; while () { Encode::from_to($_, 'iso-2022-jp', 'utf-8'); $line = $_; $line =~ s/\n$//; if (/^%/) { my ($flag_page, $flag_cont, $flag_center, $flag_left, $flag_right, $fore, $back, $size, $flag_filter, $flag_endfilter, $str_image) = get_mgp_options ($line); if ($str_image ne "") { my ($width, $height, $img_file) = parse_image($str_image, $path); add_image($presentation, $page[$ip-1], "$img_x"."cm", "$img_y"."cm", $width, $height, $path . $img_file); $img_y += $height; } if ($flag_page == 1) { print "start page $ip ($flag_page)\n"; $flag_nodefault = 0; $flag_body = 0; $flag_outline = 0; $img_x = 12.0; $img_y = 4.914; $ip ++; $page[$ip-1] = $presentation->appendDrawPage(name => "page".$ip); } if ($flag_fltcmd == 0 and $flag_filter == 1) { $flag_fltcmd = 1; } if ($flag_fltcmd == 1 and $flag_endfilter == 1) { $flag_fltcmd = 0; } } else { if ($flag_body == 0) { # print "the first line is just ignored\n"; $flag_body ++; } elsif ($flag_body == 1) { add_title($presentation, $page[$ip-1], $line); $flag_body ++; } elsif ($flag_body == 2) { # print "the third line is just ignored\n"; $flag_body ++; } else { if ($flag_outline == 0) { $flag_outline = 1; $tb = add_outline($presentation, $page[$ip-1], "1.4cm", "4.914cm", "25.199cm", "13.609cm"); } # body part if ($flag_fltcmd == 1){ # skip parsing } else { my ($level); # list level if (/^\t\t\t/) { $level = 4; } elsif (/^\t\t/) { $level = 3; } elsif (/^\t/) { $level = 2; } else { $level = 1; } # cut the tab $line =~ s/\t//g; add_list_item ($presentation, $tb, $level, $line); } } } } close MGPFILE; $presentation->save; } sub usage () { print "mgp2odp is a converter from Magicpoint (mgp) file to OpenOffice (odp) file.\n"; print "USAGE: mgp2odp.pl mgp-file\n"; exit 1; } ############################################################################### # MAIN if ($#ARGV != 0) { usage(); } else { $input = $ARGV[0]; } my ($base, $path, $suffix) = File::Basename::fileparse($input, '\..*'); if ($input =~ /\.mgp$/) { $output = $base . ".odp"; } else { usage(); exit 1; } print "converting $input to $output\n"; convert_mgp_to_odp ($input, $output, $path); exit 0;