Advertisement
Guest User

Untitled

a guest
Sep 23rd, 2020
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.69 KB | None | 0 0
  1. import xml.dom.minidom;
  2. import os;
  3. import math;
  4. import svgwrite;
  5. import kanji_lists;
  6. from svgwrite import cm, mm, rgb;
  7.  
  8. # I had trouble rendering the now very css heavy designs in my normal
  9. # svg to pdf converter - so I now just build them all into one long
  10. # html file and print them from chrome - see here for a gist that
  11. # gives the basic idea:
  12. # https://gist.githubusercontent.com/s417-lama/84bf66de1096c4587e8187092fb41684/raw/e42345dcc91e198ca2983aaef93b87da6a70aa37/svg2pdf.bash
  13.  
  14. # you will need a kanjivg archive (e.g. kanjivg-20160426-all.zip ) unpacked
  15. # locally into the directory kanji/
  16.  
  17. # this program depends on the svgwrite and kanji_lists modules, both of which
  18. # can be obtained from pip
  19.  
  20. # still can't make it work? curious.jp@gmail.com
  21.  
  22. ## paper dimensions ########################################################
  23. # a4 sheets of paper are 210x297mm
  24.  
  25. # four item coordinates are l, t, r, b
  26.  
  27. class Configuration:
  28.     def __init__( self, width = 210, height = 297,
  29.                   inner_gutter = (15,15,15,15), outer_gutter = (10,10,10,10),
  30.                   box_size = 30,
  31.                   label_size = None, label_offset = (15,15),
  32.                   stroke_dot_size = None ):
  33.  
  34.         self.page_width = width;
  35.         self.page_height = height;
  36.  
  37.         self._inner_gutter = inner_gutter;
  38.         self._outer_gutter = outer_gutter;
  39.  
  40.         self._box_size = box_size;
  41.  
  42.         self._label_size = label_size;
  43.         self._label_offset = label_offset;
  44.  
  45.         self._stroke_dot_size = stroke_dot_size;
  46.  
  47.     def drawOuterGutter( self, dwg ):
  48.         if( self._outer_gutter == None ):
  49.             return;
  50.         r_l = self._outer_gutter[ 0 ];
  51.         r_t = self._outer_gutter[ 1 ];
  52.         r_r = self.page_width - self._outer_gutter[ 2 ];
  53.         r_b = self.page_height - self._outer_gutter[ 3 ];
  54.         r_w = r_r - r_l;
  55.         r_h = r_b - r_t;
  56.         rectangle = dwg.rect( insert = ( mm( r_l ), mm( r_t ) ),
  57.                               size = ( mm( r_w ), mm( r_h ) ),
  58.                               fill = "none",
  59.                               stroke = "black" );
  60.         dwg.add( rectangle );
  61.         return;
  62.  
  63.     def drawLabel( self, label, dwg ):
  64.         if( self._label_size == None ):
  65.             return;
  66.         # right aligned
  67.         if( self._label_offset[ 0 ] > self.page_width / 2 ):
  68.             l_s = "dominant-baseline: hanging; text-anchor: end";
  69.         # left aligned
  70.         else:
  71.             l_s = "dominant-baseline: hanging; text-anchor: start";
  72.         l_l, l_t = self._label_offset;
  73.         text = dwg.text( label,
  74.                          insert = ( mm( l_l ), mm( l_t ) ),
  75.                          font_size = mm( self._label_size ),
  76.                          fill = "black",
  77.                          stroke = "none",
  78.                          style = l_s );
  79.         dwg.add( text );
  80.         return;
  81.  
  82.     def _getGridDimensions( self ):
  83.         avail_h = self.page_height - self._inner_gutter[ 1 ] - self._inner_gutter[ 3 ];
  84.         boxes_h = math.floor( avail_h / self._box_size );
  85.         avail_w = self.page_width - self._inner_gutter[ 0 ] - self._inner_gutter[ 2 ];
  86.         boxes_w = math.floor( avail_w / self._box_size );
  87.         hline_w = boxes_w * self._box_size;
  88.         hline_l = self._inner_gutter[ 0 ] + ( avail_w - hline_w ) / 2;
  89.         hline_r = hline_l + hline_w;
  90.         vline_h = boxes_h * self._box_size;
  91.         vline_t = self._inner_gutter[ 1 ] + ( avail_h - vline_h ) / 2;
  92.         vline_b = vline_t + vline_h;
  93.         return ( boxes_w, boxes_h, hline_l, hline_r, vline_t, vline_b );
  94.  
  95.     def drawGrid( self, dwg ):
  96.         boxes_w, boxes_h, hline_l, hline_r, vline_t, vline_b = self._getGridDimensions();
  97.         # vertical guideline
  98.         for col in range( boxes_w ):
  99.             rule = dwg.line( stroke = "lightgrey",
  100.                              start = ( mm( hline_l + col * self._box_size + .5 * self._box_size ), mm( vline_t ) ),
  101.                              end = ( mm( hline_l + col * self._box_size + .5 * self._box_size ), mm( vline_b ) ),
  102.                              stroke_dasharray = "4" );
  103.             dwg.add( rule );
  104.         # vertical box edge
  105.         for col in range( boxes_w + 1 ):
  106.             rule = dwg.line( stroke = "grey",
  107.                              start = ( mm( hline_l + col * self._box_size ), mm( vline_t ) ),
  108.                              end = ( mm( hline_l + col * self._box_size ), mm( vline_b ) ) );
  109.             dwg.add( rule );
  110.         # horizontal guideline
  111.         for row in range( boxes_h + 1 ):
  112.             rule = dwg.line( stroke = "lightgrey",
  113.                              start = ( mm( hline_l ), mm( vline_t + row * self._box_size + 0.5 * self._box_size ) ),
  114.                              end = ( mm( hline_r ), mm( vline_t + row * self._box_size + 0.5 * self._box_size ) ),
  115.                              stroke_dasharray = "4" );
  116.             dwg.add( rule );
  117.         # horizontal box edge
  118.         for row in range( boxes_h + 1 ):
  119.             rule = dwg.line( stroke = "grey",
  120.                              start = ( mm( hline_l ), mm( vline_t + row * self._box_size ) ),
  121.                              end = ( mm( hline_r ), mm( vline_t + row * self._box_size ) ) );
  122.             dwg.add( rule );
  123.         return;
  124.  
  125.     def drawCharacters( self, k, dwg ):
  126.         boxes_w, boxes_h, hline_l, hline_r, vline_t, vline_b = self._getGridDimensions();
  127.         k_viewbox, k_strokes = loadStrokes( k );
  128.         subdrawing = svgwrite.container.SVG( id = "ghost", x = mm( 0 ), y = mm( 0 ),
  129.                                              size = ( mm( self._box_size ), mm( self._box_size ) ),
  130.                                              viewBox = k_viewbox,
  131.                                              style = 'stroke-linecap:round;stroke-linejoin:round', fill = 'none' );
  132.  
  133.         stroke_counter = 0;
  134.         for stroke in k_strokes:
  135.             subdrawing.add( dwg.path( d = stroke, style="marker-start: var(--stroke-{0}-marker); stroke: var(--stroke-{0}-colour); stroke-width: var(--stroke-{0}-width)".format( stroke_counter )  ) );
  136.             stroke_counter += 1;
  137.         dwg.defs.add( subdrawing );
  138.  
  139.         marker = dwg.marker( id = "pen_marker", insert = (2, 2), size = (4, 4) );
  140.         marker.add( dwg.circle( ( 2, 2 ), r = 1, fill = 'red' ) );
  141.         dwg.defs.add( marker );
  142.  
  143.         for stroke in range( len( k_strokes ) ):
  144.             dwg.defs.add( dwg.style( ".tutor{0} {{ --stroke-{0}-colour: black; --stroke-{0}-width: 3; }}".format( stroke ) ) );
  145.             dwg.defs.add( dwg.style( ".finaltutor{0} {{ --stroke-{0}-colour: red; --stroke-{0}-marker: url(#pen_marker); }}".format( stroke ) ) );
  146.         dwg.defs.add( dwg.style( ".grey { stroke: grey; stroke-width: 2; }" ) );
  147.  
  148.         cell_number = 0;
  149.         for row in range( boxes_h ):
  150.             for col in range( boxes_w ):
  151.                 if( cell_number < len( k_strokes ) ):
  152.                     css_class_string = " ".join( [ "tutor{0}".format( x ) for x in range( cell_number + 1 ) ] ) + " finaltutor{0} grey".format( cell_number );
  153.                 else:
  154.                     css_class_string = "grey";
  155.                 dwg.add( dwg.use( href="#ghost", class_ = css_class_string, insert = ( mm( hline_l + col * self._box_size ), mm( vline_t + row * self._box_size ) ) ) );
  156.                 cell_number += 1;
  157.         return;
  158.  
  159. def loadStrokes( kanji ):
  160.     codePoint = ord( kanji[0] );
  161.     codePointFN = os.path.join( "kanji", "{0:05x}.svg".format( codePoint ) );
  162.     kanjiSVG = xml.dom.minidom.parse( codePointFN );
  163.     # obtain the viewport size for scaling purposes
  164.     svgTag = kanjiSVG.getElementsByTagName( "svg" )[ 0 ];
  165.     viewBox = svgTag.getAttribute( "viewBox" );
  166.     # obtain strokes
  167.     strokeLeader = "kvg:{0:05x}-s".format( codePoint );
  168.     strokes = [ ( int( x.getAttribute( "id" ).replace( strokeLeader, "" ) ), x.getAttribute( "d" ) )
  169.         for x in svgTag.getElementsByTagName( "path" )
  170.         if x.getAttribute( "id" ).startswith( strokeLeader ) ];
  171.     return ( viewBox, [ x[1] for x in sorted( strokes, key = lambda y: y[0] ) ] );
  172.  
  173. def draw_page( item, filename, config ):
  174.     dwg = svgwrite.Drawing( filename = filename, size = ( mm( config.page_width ), mm( config.page_height ) ) );
  175.     config.drawOuterGutter( dwg );
  176.     config.drawLabel( item, dwg );
  177.     config.drawGrid( dwg );
  178.     config.drawCharacters( item, dwg );
  179.     dwg.save();
  180.  
  181. if __name__ == '__main__':
  182.     config = Configuration( outer_gutter = (5,5,5,5), inner_gutter = ( 10, 297/3, 10, 10 ), label_size = 64, label_offset = ( 200, 25 ) );
  183.  
  184.     index = 0;
  185.     #for item in kanji_lists.JLPT.N5:
  186.     for item in kanji_lists.JOYO:
  187.         fn = "jy-{0}-{1:04}.svg".format( item, index );
  188.         index += 1;
  189.         draw_page( item, fn, config );
  190.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement