# The LearningOnline Network with CAPA # programatic image drawing # # $Id: drawimage.pm,v 1.14 2024/04/09 20:01:31 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # # This file is part of the LearningOnline Network with CAPA (LON-CAPA). # # LON-CAPA 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. # # LON-CAPA 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 LON-CAPA; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # /home/httpd/html/adm/gpl.txt # # http://www.lon-capa.org/ # package Apache::drawimage; use strict; use Apache::loncommon; use Apache::lonnet; use Apache::lonxml; use Apache::edit; use lib '/home/httpd/lib/perl/'; use Time::HiRes qw(gettimeofday); use LONCAPA; my %args; my $cgi_id; my @cgi_ids; BEGIN { &Apache::lonxml::register('Apache::drawimage',('drawimage')); } sub start_drawimage { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; &Apache::lonxml::register('Apache::drawimage',('text','line','rectangle','arc','fill','polygon','image')); push(@Apache::lonxml::namespace,'drawimage'); my $result; if ($target eq 'web' || $target eq 'tex') { my $new_id=&Apache::loncommon::get_cgi_id(); if ($cgi_id) { push(@cgi_ids,$cgi_id); } else { undef(%args); } $cgi_id=$new_id; } elsif ($target eq 'edit') { $result .= &Apache::edit::tag_start($target,$token). &Apache::edit::text_arg('Background color:','bgcolor' ,$token,8). &Apache::edit::text_arg('Width(pixel):' ,'width' ,$token,6). &Apache::edit::text_arg('Height(pixel):' ,'height' ,$token,6). &Apache::edit::text_arg('TeXWidth(mm):' ,'texwidth',$token,6). &Apache::edit::end_row().&Apache::edit::start_spanning_row(); } elsif ($target eq 'modified') { my $constructtag=&Apache::edit::get_new_args($token,$parstack, $safeeval,'bgcolor','width', 'height','texwidth'); if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); } } return $result; } sub end_drawimage { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; # need to call rand everytime start_script would evaluate, as the # safe space rand number generator and the global rand generator # are not separate my $randnumber; if ($target eq 'web' || $target eq 'tex' || $target eq 'grade' || $target eq 'answer') { $randnumber=int(rand(1000)); } if ($target eq 'web' || $target eq 'tex') { my $width = &Apache::lonxml::get_param('width',$parstack,$safeeval); my $height =&Apache::lonxml::get_param('height',$parstack,$safeeval); my $bgcolor =&Apache::lonxml::get_param('bgcolor',$parstack,$safeeval); if (!$width) { $width=300; } if (!$height) { $height=300; } $args{"cgi.$cgi_id.BGCOLOR"}=join(':',($bgcolor)); if ($target eq 'tex') { my $texwidth=&Apache::lonxml::get_param('texwidth',$parstack,$safeeval,undef,1); if (!$texwidth) { $texwidth='90'; } $args{"cgi.$cgi_id.SIZE"}=join(':',($width,$height,$texwidth)); my $tmpdir = LONCAPA::tempdir(); # Where temporary files live: ## Determine filename my ($seconds, $microseconds) = gettimeofday; my $filename = $env{'user.name'}.'_'.$env{'user.domain'}. '_'.$seconds.'_'.$microseconds.'_'.$$.$randnumber.'_drawimage.eps'; $args{"cgi.$cgi_id.EPSFILE"} = $env{'user.name'}.'_'.$env{'user.domain'}. '_'.$seconds.'_'.$microseconds.'_'.$$.$randnumber. '_drawimage.eps'; $result = "%DYNAMICIMAGE:$width:$height:$texwidth\n"; $result .= '\graphicspath{{'.$tmpdir.'}}'."\n"; $result .= '\includegraphics[width='.$texwidth.' mm]{'.$filename.'}'; &Apache::lonxml::register_ssi('/adm/randomlabel.png?token='.$cgi_id); } else { $args{"cgi.$cgi_id.SIZE"}=join(':',($width,$height)); $result.="\n"; } &Apache::lonnet::appenv(\%args); if (@cgi_ids) { $cgi_id=pop(@cgi_ids); } else { undef($cgi_id); } } elsif ($target eq 'edit') { $result.=&Apache::edit::end_table; } pop(@Apache::lonxml::namespace); &Apache::lonxml::deregister('Apache::drawimage', ('text','line','rectangle','arc','fill', 'polygon')); return $result; } sub start_text { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq 'web' || $target eq 'tex') { &Apache::lonxml::startredirection(); } elsif ($target eq 'edit') { $result = &Apache::edit::tag_start($target,$token). &Apache::edit::text_arg('x:','x',$token,6). &Apache::edit::text_arg('y:','y',$token,6). &Apache::edit::text_arg('font:','font',$token,12). &Apache::edit::text_arg('color:','color',$token,8). &Apache::edit::select_arg('direction:','direction', ['vertical','horizontal'],$token). &Apache::edit::text_arg('rotation:','rotation',$token,6); my $text=&Apache::lonxml::get_all_text('/text',$parser,$style); $result .= &Apache::edit::editfield($token->[1],$text,'Text',60,2). &Apache::edit::end_row(); } elsif ($target eq 'modified') { my $constructtag=&Apache::edit::get_new_args($token,$parstack, $safeeval,'x','y', 'font','color', 'direction','rotation'); if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); } else { $result = $token->[4]; } $result .= &Apache::edit::modifiedfield('/text',$parser); } return $result; } sub end_text { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq 'web' || $target eq 'tex') { my $x = &Apache::lonxml::get_param('x',$parstack,$safeeval); my $y = &Apache::lonxml::get_param('y',$parstack,$safeeval); my $font = &Apache::lonxml::get_param('font',$parstack,$safeeval); my $color = &Apache::lonxml::get_param('color',$parstack,$safeeval); my $direction = &Apache::lonxml::get_param('direction',$parstack,$safeeval); my $rotation = &Apache::lonxml::get_param('rotation',$parstack,$safeeval); my $text = &Apache::lonxml::endredirection(); $text = &escape($text); $args{"cgi.$cgi_id.OBJTYPE"}.='LABEL:'; my $i=$args{"cgi.$cgi_id.OBJCOUNT"}++; $args{"cgi.$cgi_id.OBJ$i"}=join(':',($x,$y,$text,$font,$color,$direction,$rotation)); } elsif ($target eq 'edit') { $result=&Apache::edit::end_table(); } return $result; } sub start_line { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq 'web' || $target eq 'tex') { my $x1 = &Apache::lonxml::get_param('x1',$parstack,$safeeval); my $y1 = &Apache::lonxml::get_param('y1',$parstack,$safeeval); my $x2 = &Apache::lonxml::get_param('x2',$parstack,$safeeval); my $y2 = &Apache::lonxml::get_param('y2',$parstack,$safeeval); my $color = &Apache::lonxml::get_param('color',$parstack,$safeeval); my $thickness = &Apache::lonxml::get_param('thickness',$parstack,$safeeval); my $i=$args{"cgi.$cgi_id.OBJCOUNT"}++; $args{"cgi.$cgi_id.OBJ$i"}=join(':',($x1,$y1,$x2,$y2,$color,$thickness)); $args{"cgi.$cgi_id.OBJTYPE"}.='LINE:'; } elsif ($target eq 'edit') { $result .= &Apache::edit::tag_start($target,$token). &Apache::edit::text_arg('x1:','x1' ,$token,6). &Apache::edit::text_arg('y1:','y1' ,$token,6). &Apache::edit::text_arg('x2:','x2' ,$token,6). &Apache::edit::text_arg('y2:','y2' ,$token,6). &Apache::edit::text_arg('color:','color',$token,8). &Apache::edit::text_arg('thickness:','thickness',$token,6). &Apache::edit::end_row(); } elsif ($target eq 'modified') { my $constructtag=&Apache::edit::get_new_args($token,$parstack, $safeeval,'x1','y1', 'x2','y2','color','thickness'); if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); } } return $result; } sub end_line { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq 'edit') { $result=&Apache::edit::end_table(); } return $result; } sub start_rectangle { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq 'web' || $target eq 'tex') { my $x1 = &Apache::lonxml::get_param('x1',$parstack,$safeeval); my $y1 = &Apache::lonxml::get_param('y1',$parstack,$safeeval); my $x2 = &Apache::lonxml::get_param('x2',$parstack,$safeeval); my $y2 = &Apache::lonxml::get_param('y2',$parstack,$safeeval); my $color = &Apache::lonxml::get_param('color',$parstack,$safeeval); my $thickness = &Apache::lonxml::get_param('thickness',$parstack, $safeeval); my $filled = &Apache::lonxml::get_param('filled',$parstack, $safeeval); my $i=$args{"cgi.$cgi_id.OBJCOUNT"}++; $args{"cgi.$cgi_id.OBJ$i"}= join(':',($x1,$y1,$x2,$y2,$color,$thickness,$filled)); $args{"cgi.$cgi_id.OBJTYPE"}.='RECTANGLE:'; } elsif ($target eq 'edit') { $result .= &Apache::edit::tag_start($target,$token). &Apache::edit::text_arg('x1:','x1' ,$token,6). &Apache::edit::text_arg('y1:','y1' ,$token,6). &Apache::edit::text_arg('x2:','x2' ,$token,6). &Apache::edit::text_arg('y2:','y2' ,$token,6). &Apache::edit::text_arg('color:','color',$token,8). &Apache::edit::text_arg('thickness:','thickness',$token,6). &Apache::edit::select_arg('filled:','filled', ['no','yes'],$token). &Apache::edit::end_row(); } elsif ($target eq 'modified') { my $constructtag=&Apache::edit::get_new_args($token,$parstack, $safeeval,'x1','y1', 'x2','y2','color','thickness', 'filled'); if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); } } return $result; } sub end_rectangle { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq 'edit') { $result=&Apache::edit::end_table(); } return $result; } sub start_arc { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq 'web' || $target eq 'tex') { my $x = &Apache::lonxml::get_param('x',$parstack,$safeeval); my $y = &Apache::lonxml::get_param('y',$parstack,$safeeval); my $width = &Apache::lonxml::get_param('width',$parstack,$safeeval); my $height = &Apache::lonxml::get_param('height',$parstack,$safeeval); my $start = &Apache::lonxml::get_param('start',$parstack,$safeeval); my $end = &Apache::lonxml::get_param('end',$parstack,$safeeval); my $color = &Apache::lonxml::get_param('color',$parstack,$safeeval); my $thickness = &Apache::lonxml::get_param('thickness',$parstack,$safeeval); my $filled = &Apache::lonxml::get_param('filled',$parstack,$safeeval); my $i=$args{"cgi.$cgi_id.OBJCOUNT"}++; $args{"cgi.$cgi_id.OBJ$i"}= join(':',($x,$y,$width,$height,$start,$end,$color,$thickness, $filled)); $args{"cgi.$cgi_id.OBJTYPE"}.='ARC:'; } elsif ($target eq 'edit') { $result .= &Apache::edit::tag_start($target,$token). &Apache::edit::text_arg('x:','x',$token,6). &Apache::edit::text_arg('y:','y',$token,6). &Apache::edit::text_arg('width:','width',$token,6). &Apache::edit::text_arg('height:','height',$token,6). &Apache::edit::text_arg('start:','start',$token,6). &Apache::edit::text_arg('end:','end',$token,6). &Apache::edit::text_arg('color:','color',$token,8). &Apache::edit::text_arg('thickness:','thickness',$token,6). &Apache::edit::select_arg('filled:','filled', ['no','yes'],$token). &Apache::edit::end_row(); } elsif ($target eq 'modified') { my $constructtag=&Apache::edit::get_new_args($token,$parstack, $safeeval,'x','y', 'width','height', 'start','end', 'color','thickness', 'filled'); if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); } } return $result; } sub end_arc { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq 'edit') { $result=&Apache::edit::end_table(); } return $result; } sub start_fill { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq 'web' || $target eq 'tex') { my $x = &Apache::lonxml::get_param('x',$parstack,$safeeval); my $y = &Apache::lonxml::get_param('y',$parstack,$safeeval); my $color = &Apache::lonxml::get_param('color',$parstack,$safeeval); my $i=$args{"cgi.$cgi_id.OBJCOUNT"}++; $args{"cgi.$cgi_id.OBJ$i"}=join(':',($x,$y,$color)); $args{"cgi.$cgi_id.OBJTYPE"}.='FILL:'; } elsif ($target eq 'edit') { $result .= &Apache::edit::tag_start($target,$token). &Apache::edit::text_arg('x:','x' ,$token,6). &Apache::edit::text_arg('y:','y' ,$token,6). &Apache::edit::text_arg('color:','color',$token,8). &Apache::edit::end_row(); } elsif ($target eq 'modified') { my $constructtag=&Apache::edit::get_new_args($token,$parstack, $safeeval,'x','y', 'color'); if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); } } return $result; } sub end_fill { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq 'edit') { $result=&Apache::edit::end_table(); } return $result; } my @polygon; sub start_polygon { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; push(@Apache::lonxml::namespace,'polygon'); &Apache::lonxml::register('Apache::drawimage',('point')); if ($target eq 'web' || $target eq 'tex') { undef(@polygon); } elsif ($target eq 'edit') { $result = &Apache::edit::tag_start($target,$token). &Apache::edit::text_arg('color:','color',$token,8). &Apache::edit::select_arg('Open:','open', ['no','yes'],$token). &Apache::edit::select_arg('Filled:','filled', ['no','yes'],$token). &Apache::edit::text_arg('thickness:','thickness',$token,6). &Apache::edit::end_row(). &Apache::edit::start_spanning_row(); } elsif ($target eq 'modified') { my $constructtag=&Apache::edit::get_new_args($token,$parstack, $safeeval,'open','filled'); if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); } } return $result; } sub end_polygon { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq 'web' || $target eq 'tex') { my $color=&Apache::lonxml::get_param('color',$parstack,$safeeval); my $filled=&Apache::lonxml::get_param('filled',$parstack,$safeeval); my $open=&Apache::lonxml::get_param('open',$parstack,$safeeval); my $thickness = &Apache::lonxml::get_param('thickness',$parstack, $safeeval); my $i=$args{"cgi.$cgi_id.OBJCOUNT"}++; $args{"cgi.$cgi_id.OBJTYPE"}.='POLYGON:'; $args{"cgi.$cgi_id.OBJ$i"}=join(':',($color,$thickness,$open,$filled)); $args{"cgi.$cgi_id.OBJEXTRA$i"}=join('-',@polygon); } elsif ($target eq 'edit') { $result=&Apache::edit::end_table(); } pop(@Apache::lonxml::namespace); &Apache::lonxml::deregister('Apache::drawimage',('point')); return $result; } sub start_point { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq 'web' || $target eq 'tex') { my $x = &Apache::lonxml::get_param('x',$parstack,$safeeval); my $y = &Apache::lonxml::get_param('y',$parstack,$safeeval); push (@polygon,"($x,$y)"); } elsif ($target eq 'edit') { $result.= &Apache::edit::tag_start($target,$token). &Apache::edit::text_arg('x:','x' ,$token,6). &Apache::edit::text_arg('y:','y' ,$token,6). &Apache::edit::end_row(); } elsif ($target eq 'modified') { my $constructtag=&Apache::edit::get_new_args($token,$parstack, $safeeval,'x','y'); if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); } } return $result; } sub end_point { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq 'edit') { $result=&Apache::edit::end_table(); } return $result; } sub start_image { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq 'web' || $target eq 'tex') { &Apache::lonxml::startredirection(); } elsif ($target eq 'edit') { my $bgimg=&Apache::lonxml::get_all_text('/image',$parser,$style); $Apache::edit::bgimgsrc=$bgimg; $Apache::edit::bgimgsrcdepth=$Apache::lonxml::curdepth; my $only = join(',',&Apache::loncommon::filecategorytypes('Pictures')); $result=&Apache::edit::tag_start($target,$token,'Background Image'). &Apache::edit::editline($token->[1],$bgimg,'Image Source File',40). &Apache::edit::browse_or_search(undef,'textnode',undef,$only,undef,1). '
'. &Apache::edit::text_arg('x:','x',$token,6). &Apache::edit::text_arg('y:','y',$token,6). &Apache::edit::text_arg('clipx:','clipx',$token,6). &Apache::edit::text_arg('clipy:','clipy',$token,6). &Apache::edit::text_arg('Clip width(pixel):','clipwidth',$token,6). &Apache::edit::text_arg('Clip height(pixel):','clipheight',$token,6). &Apache::edit::text_arg('Scaled width:','scaledwidth',$token,6). &Apache::edit::text_arg('Scaled height:','scaledheight',$token,6). &Apache::edit::text_arg('Transparent:','transparent',$token,6). &Apache::edit::end_row(); } elsif ($target eq 'modified') { my $constructtag=&Apache::edit::get_new_args($token,$parstack, $safeeval,'x','y', 'clipx','clipy','clipwidth','clipheight', 'scaledwidth','scaledheight','transparent'); if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); } else { $result = $token->[4]; } $result .= &Apache::edit::modifiedfield('/image',$parser); } return $result; } sub end_image { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq 'web' || $target eq 'tex') { my $bgimg=&Apache::lonxml::endredirection(); my $x = &Apache::lonxml::get_param('x',$parstack,$safeeval); my $y = &Apache::lonxml::get_param('y',$parstack,$safeeval); my $clipx = &Apache::lonxml::get_param('clipx',$parstack,$safeeval); my $clipy = &Apache::lonxml::get_param('clipy',$parstack,$safeeval); my $clipwidth = &Apache::lonxml::get_param('clipwidth',$parstack,$safeeval); my $clipheight = &Apache::lonxml::get_param('clipheight',$parstack,$safeeval); my $scaledwidth = &Apache::lonxml::get_param('scaledwidth',$parstack,$safeeval); my $scaledheight = &Apache::lonxml::get_param('scaledheight',$parstack,$safeeval); my $transparent = &Apache::lonxml::get_param('transparent',$parstack,$safeeval); $bgimg=&Apache::imageresponse::clean_up_image($bgimg); my $i=$args{"cgi.$cgi_id.OBJCOUNT"}++; $args{"cgi.$cgi_id.OBJTYPE"}.='IMAGE:'; $args{"cgi.$cgi_id.OBJ$i"} = join(':',($x,$y,&escape($bgimg),$transparent, $clipx,$clipy,$scaledwidth,$scaledheight,$clipwidth,$clipheight)); } elsif ($target eq 'edit') { $result=&Apache::edit::end_table(); } return $result; } 1; __END__