| 1 | #!/usr/bin/env python
|
|---|
| 2 |
|
|---|
| 3 | ############################################################################
|
|---|
| 4 | #
|
|---|
| 5 | # MODULE: m.printws
|
|---|
| 6 | #
|
|---|
| 7 | # AUTHOR(S): Robert Kuszinger
|
|---|
| 8 | #
|
|---|
| 9 | # PURPOSE: Creates carographic-like map sheet page from
|
|---|
| 10 | # a workspace composition
|
|---|
| 11 | #
|
|---|
| 12 | # COPYRIGHT: (C) 2016 by GRASS development team
|
|---|
| 13 | #
|
|---|
| 14 | # This program is free software under the GNU General
|
|---|
| 15 | # Public License (>=v2). Read the file COPYING that
|
|---|
| 16 | # comes with GRASS for details.
|
|---|
| 17 | #
|
|---|
| 18 | #############################################################################
|
|---|
| 19 |
|
|---|
| 20 | #%module
|
|---|
| 21 | #% description: Opens a workspace file and creates a map sheet according to its visible contents.
|
|---|
| 22 | #% keyword: map
|
|---|
| 23 | #% keyword: print
|
|---|
| 24 | #% keyword: layout
|
|---|
| 25 | #% keyword: workspace
|
|---|
| 26 | #%end
|
|---|
| 27 | #%option G_OPT_F_BIN_INPUT
|
|---|
| 28 | #% key: input
|
|---|
| 29 | #% description: Name of workspace file to process
|
|---|
| 30 | #% required: YES
|
|---|
| 31 | #% gisprompt: old,bin,file
|
|---|
| 32 | #% guisection: Input
|
|---|
| 33 | #%end
|
|---|
| 34 | #%option
|
|---|
| 35 | #% key: dpi
|
|---|
| 36 | #% type: integer
|
|---|
| 37 | #% answer: 150
|
|---|
| 38 | #% multiple: no
|
|---|
| 39 | #% description: DPI for the generated page
|
|---|
| 40 | #% guisection: Output
|
|---|
| 41 | #%end
|
|---|
| 42 | #%option G_OPT_F_OUTPUT
|
|---|
| 43 | #% description: Name of output file without extension
|
|---|
| 44 | #% key: output
|
|---|
| 45 | #% gisprompt: new,file,file
|
|---|
| 46 | #% guisection: Output
|
|---|
| 47 | #%end
|
|---|
| 48 | #%option
|
|---|
| 49 | #% key: page
|
|---|
| 50 | #% type: string
|
|---|
| 51 | #% options: A4landscape,A4portrait,LETTERlandscape,LETTERportrait,A3landscape,A3portrait,Flexi
|
|---|
| 52 | #% answer: A4landscape
|
|---|
| 53 | #% description: Output map page size
|
|---|
| 54 | #% guisection: Output
|
|---|
| 55 | #%end
|
|---|
| 56 | #%option
|
|---|
| 57 | #% key: format
|
|---|
| 58 | #% type: string
|
|---|
| 59 | #% options: pdf,png,tiff,bmp,ppm,jpg
|
|---|
| 60 | #% answer: pdf
|
|---|
| 61 | #% description: Output file format
|
|---|
| 62 | #% guisection: Output
|
|---|
| 63 | #%end
|
|---|
| 64 | #%option
|
|---|
| 65 | #% key: maintitle
|
|---|
| 66 | #% type: string
|
|---|
| 67 | #% description: Main title of map sheet
|
|---|
| 68 | #% guisection: Titles
|
|---|
| 69 | #%end
|
|---|
| 70 | #%option
|
|---|
| 71 | #% key: font
|
|---|
| 72 | #% type: string
|
|---|
| 73 | #% description: Font for title above and postscript under the map
|
|---|
| 74 | #% guisection: Titles
|
|---|
| 75 | #%end
|
|---|
| 76 | #%option G_OPT_C
|
|---|
| 77 | #% key: titlecolor
|
|---|
| 78 | #% type: string
|
|---|
| 79 | #% description: Title text color
|
|---|
| 80 | #% guisection: Titles
|
|---|
| 81 | #%end
|
|---|
| 82 | #%option
|
|---|
| 83 | #% key: maintitlesize
|
|---|
| 84 | #% type: integer
|
|---|
| 85 | #% description: Main title font size in layout units
|
|---|
| 86 | #% guisection: Titles
|
|---|
| 87 | #%end
|
|---|
| 88 | #%option
|
|---|
| 89 | #% key: subtitle
|
|---|
| 90 | #% type: string
|
|---|
| 91 | #% description: Subtitle text above the map sheet in the middle
|
|---|
| 92 | #% guisection: Titles
|
|---|
| 93 | #%end
|
|---|
| 94 | #%option
|
|---|
| 95 | #% key: subtitlesize
|
|---|
| 96 | #% type: integer
|
|---|
| 97 | #% description: Subtitle font size in layout units
|
|---|
| 98 | #% guisection: Titles
|
|---|
| 99 | #%end
|
|---|
| 100 | #%option
|
|---|
| 101 | #% key: psunderleft
|
|---|
| 102 | #% type: string
|
|---|
| 103 | #% description: Postscript text under the map sheet on the left
|
|---|
| 104 | #% guisection: Titles
|
|---|
| 105 | #%end
|
|---|
| 106 | #%option
|
|---|
| 107 | #% key: psunderright
|
|---|
| 108 | #% type: string
|
|---|
| 109 | #% description: Postscript text under the map sheet on the right
|
|---|
| 110 | #% guisection: Titles
|
|---|
| 111 | #%end
|
|---|
| 112 | #%option
|
|---|
| 113 | #% key: psundercentral
|
|---|
| 114 | #% type: string
|
|---|
| 115 | #% description: Postscript text under the map sheet, centered
|
|---|
| 116 | #% guisection: Titles
|
|---|
| 117 | #%end
|
|---|
| 118 | #%option
|
|---|
| 119 | #% key: pssize
|
|---|
| 120 | #% type: integer
|
|---|
| 121 | #% description: Postscript text font size in layout units
|
|---|
| 122 | #% guisection: Titles
|
|---|
| 123 | #%end
|
|---|
| 124 | #%option G_OPT_M_REGION
|
|---|
| 125 | #% key:region
|
|---|
| 126 | #% description: Name of region to use - uses workspace displayed area if empty
|
|---|
| 127 | #% required: NO
|
|---|
| 128 | #% gisprompt: old,windows,region
|
|---|
| 129 | #% guisection: Input
|
|---|
| 130 | #%end
|
|---|
| 131 | #%flag
|
|---|
| 132 | #% key: d
|
|---|
| 133 | #% description: Debug - Leave temp files as is for alternative usage or checkup
|
|---|
| 134 | #% guisection: Optional
|
|---|
| 135 | #% suppress_required: yes
|
|---|
| 136 | #%end
|
|---|
| 137 | #%option
|
|---|
| 138 | #% key: layunits
|
|---|
| 139 | #% type: string
|
|---|
| 140 | #% options: cm,mm,inch
|
|---|
| 141 | #% answer: mm
|
|---|
| 142 | #% description: Unit used for layout specification
|
|---|
| 143 | #% guisection: Layout
|
|---|
| 144 | #%end
|
|---|
| 145 | #%option
|
|---|
| 146 | #% key: pagemargin
|
|---|
| 147 | #% type: string
|
|---|
| 148 | #% description: Margins in layout units left,right,top,bottom
|
|---|
| 149 | #% guisection: Layout
|
|---|
| 150 | #%end
|
|---|
| 151 | #%option
|
|---|
| 152 | #% key: mapupperleft
|
|---|
| 153 | #% type: string
|
|---|
| 154 | #% answer: -1,-1
|
|---|
| 155 | #% description: Map frame upper left coordinates - negative means centering
|
|---|
| 156 | #% guisection: Layout
|
|---|
| 157 | #%end
|
|---|
| 158 | #%option
|
|---|
| 159 | #% key: mapsize
|
|---|
| 160 | #% type: string
|
|---|
| 161 | #% answer: 1000
|
|---|
| 162 | #% description: Map frame size in layout units as width,height
|
|---|
| 163 | #% guisection: Layout
|
|---|
| 164 | #%end
|
|---|
| 165 | #%option
|
|---|
| 166 | #% key: screendpi
|
|---|
| 167 | #% type: integer
|
|---|
| 168 | #% answer: 100
|
|---|
| 169 | #% description: The DPI of your monitor
|
|---|
| 170 | #% guisection: Layout
|
|---|
| 171 | #%end
|
|---|
| 172 |
|
|---|
| 173 |
|
|---|
| 174 | import sys
|
|---|
| 175 | import os
|
|---|
| 176 |
|
|---|
| 177 | # Windows pwd module workaround
|
|---|
| 178 | hasPwd = True
|
|---|
| 179 | try:
|
|---|
| 180 | import pwd
|
|---|
| 181 | except ImportError:
|
|---|
| 182 | hasPwd = False
|
|---|
| 183 |
|
|---|
| 184 |
|
|---|
| 185 | import atexit
|
|---|
| 186 | import re
|
|---|
| 187 | import tempfile
|
|---|
| 188 | import grass.script as grass
|
|---|
| 189 | from grass.exceptions import CalledModuleError
|
|---|
| 190 | from grass.script.utils import try_rmdir
|
|---|
| 191 | import copy
|
|---|
| 192 | import time
|
|---|
| 193 | import unicodedata
|
|---|
| 194 |
|
|---|
| 195 | # workspace file is XML so we use an XML parser
|
|---|
| 196 | import xml.dom.minidom
|
|---|
| 197 |
|
|---|
| 198 | # initialize global vars
|
|---|
| 199 | TMPFORMAT = 'BMP'
|
|---|
| 200 | TMPLOC = None
|
|---|
| 201 | LAYERCOUNT = 10
|
|---|
| 202 | # Following declarations MAY will used in future for sure.
|
|---|
| 203 | SRCGISRC = None
|
|---|
| 204 | GISDBASE = None
|
|---|
| 205 | # temp dir
|
|---|
| 206 | REMOVE_TMPDIR = True
|
|---|
| 207 | PROXIES = {}
|
|---|
| 208 |
|
|---|
| 209 | # UPSIZE is better global as it is universal at a moment
|
|---|
| 210 | # an we save a lot of parameter passing when parsing xml
|
|---|
| 211 | global UPSIZE
|
|---|
| 212 | UPSIZE = 1.0
|
|---|
| 213 |
|
|---|
| 214 | # set upsize "constants"
|
|---|
| 215 |
|
|---|
| 216 | UPSD = {}
|
|---|
| 217 | ALLTASKDIC = {}
|
|---|
| 218 | ALLTASKDIC['width'] = 1.0 # 1 by 1 correction if any
|
|---|
| 219 | UPSD['*'] = ALLTASKDIC
|
|---|
| 220 |
|
|---|
| 221 | DVECTDIC = {}
|
|---|
| 222 | DVECTDIC['size'] = 1.0 # symbol size
|
|---|
| 223 | DVECTDIC['label_size'] = 1.5 # label size
|
|---|
| 224 | UPSD['d.vect'] = DVECTDIC
|
|---|
| 225 |
|
|---|
| 226 | DGRIDDIC = {}
|
|---|
| 227 | DGRIDDIC['size'] = 0.0 # force not touching grid line distance
|
|---|
| 228 | DGRIDDIC['fontsize'] = 1.0 # 1 by 1 correction if any
|
|---|
| 229 | UPSD['d.grid'] = DGRIDDIC
|
|---|
| 230 |
|
|---|
| 231 |
|
|---|
| 232 |
|
|---|
| 233 | # PAGE dictionary
|
|---|
| 234 |
|
|---|
| 235 | PAGEDIC = {}
|
|---|
| 236 | PAGEDIC['A4portrait'] = (210.0, 297.0, '', 'A4')
|
|---|
| 237 | PAGEDIC['A4landscape'] = (297.0, 210.0, '', 'A4')
|
|---|
| 238 | PAGEDIC['A3portrait'] = (297.0, 420.0, '', 'A3')
|
|---|
| 239 | PAGEDIC['A3landscape'] = (420.0, 297.0, '', 'A3')
|
|---|
| 240 | PAGEDIC['LETTERportrait'] = (215.9, 297.4, '', 'Letter')
|
|---|
| 241 | PAGEDIC['LETTERlandscape'] = (297.4, 215.9, '', 'Letter')
|
|---|
| 242 | PAGEDIC['Flexi'] = (300, 300, '', 'Flexi')
|
|---|
| 243 |
|
|---|
| 244 |
|
|---|
| 245 | # HTML DECODE
|
|---|
| 246 | HTMLDIC = {}
|
|---|
| 247 | HTMLDIC['>'] = '>'
|
|---|
| 248 | HTMLDIC['<'] = '<'
|
|---|
| 249 | HTMLDIC['&'] = '&'
|
|---|
| 250 | HTMLDIC['"'] = '"'
|
|---|
| 251 |
|
|---|
| 252 |
|
|---|
| 253 |
|
|---|
| 254 | def cleanthisandthat(intext):
|
|---|
| 255 | # As of 10. September 2016 some modules (d.wms) creates
|
|---|
| 256 | # lines in XML workspace files which are not well-formed
|
|---|
| 257 | # before parsing them, we need to correct it.
|
|---|
| 258 | # Handled errors:
|
|---|
| 259 | # single & which is not & in urls
|
|---|
| 260 | # Once workspace files are always good this function could be NOOP
|
|---|
| 261 | outtext = ''
|
|---|
| 262 | for line in intext.splitlines():
|
|---|
| 263 | m = re.search('http\://',line)
|
|---|
| 264 | if m:
|
|---|
| 265 | line2 = re.sub('\&\;','SAVED___amp\;',line)
|
|---|
| 266 | line3 = re.sub('\&','&',line2)
|
|---|
| 267 | line4 = re.sub('SAVED___amp\;','&',line3)
|
|---|
| 268 | outtext = outtext + line4 + "\n"
|
|---|
| 269 | else:
|
|---|
| 270 | outtext = outtext + line + "\n"
|
|---|
| 271 | return outtext
|
|---|
| 272 |
|
|---|
| 273 |
|
|---|
| 274 | def cleanup():
|
|---|
| 275 |
|
|---|
| 276 | # No cleanup is done here
|
|---|
| 277 | # see end of main()
|
|---|
| 278 | # kept for later
|
|---|
| 279 | grass.verbose(_("Module cleanup"))
|
|---|
| 280 |
|
|---|
| 281 | # test
|
|---|
| 282 | # m.printws.py --overwrite input=/home/kuszi/grassdata/workspaces_7/EURASEAA.gxw dpi=100 output=/home/kuszi/grassdata/mapdefs/euraseeaa.bmp page=A4portrait maintitle=$DISPLAY pagemargin=0
|
|---|
| 283 |
|
|---|
| 284 | def upsizeifnecessary(task, lastparam, value, upsize):
|
|---|
| 285 | val = UPSD.get('*').get(lastparam, 0.0)
|
|---|
| 286 | #print task + " " + lastparam + " " + str(value) + " " + str(upsize)
|
|---|
| 287 | if val > 0:
|
|---|
| 288 | #print "## " + task + " " + lastparam + " " + str(value) + " " + str(upsize) + " > " + str(float(value) * val * upsize)
|
|---|
| 289 | return str(float(value) * val * UPSIZE)
|
|---|
| 290 | val = UPSD.get(task, {}).get(lastparam, 0.0)
|
|---|
| 291 | if val > 0:
|
|---|
| 292 | #print "## " + task + " " + lastparam + " " + str(value) + " " + str(upsize) + " > " + str(float(value) * val * upsize)
|
|---|
| 293 | return str(float(value) * val * UPSIZE)
|
|---|
| 294 | return value
|
|---|
| 295 |
|
|---|
| 296 |
|
|---|
| 297 | def htmldecode(str):
|
|---|
| 298 | dic = HTMLDIC
|
|---|
| 299 | answer = str
|
|---|
| 300 | for key in dic:
|
|---|
| 301 | answer = answer.replace(key, dic[key])
|
|---|
| 302 | return answer
|
|---|
| 303 |
|
|---|
| 304 |
|
|---|
| 305 |
|
|---|
| 306 | def processlayer(dom,flagdic,paramdic):
|
|---|
| 307 | task = dom.getElementsByTagName("task")[0]
|
|---|
| 308 | command = task.getAttribute('name')
|
|---|
| 309 | params = task.getElementsByTagName("parameter")
|
|---|
| 310 | paramdic['task'] = command
|
|---|
| 311 | for p in params:
|
|---|
| 312 | elements = p.getElementsByTagName("value") #sometimes there are empty <value> tags in workspace files
|
|---|
| 313 | if len(elements) > 0:
|
|---|
| 314 | nodes = elements[0].childNodes
|
|---|
| 315 | if len(nodes) > 0:
|
|---|
| 316 | paramdic[p.getAttribute('name')] = upsizeifnecessary(paramdic['task'],p.getAttribute('name'),nodes[0].data,UPSIZE)
|
|---|
| 317 |
|
|---|
| 318 | flags = task.getElementsByTagName("flag")
|
|---|
| 319 | for f in flags:
|
|---|
| 320 | if (f.getAttribute('name') <> 'verbose') and (f.getAttribute('name') <> 'overwrite') and (f.getAttribute('name') <> 'quiet'):
|
|---|
| 321 | flagdic [f.getAttribute('name')] = f.getAttribute('name')
|
|---|
| 322 |
|
|---|
| 323 |
|
|---|
| 324 | def processoverlay(dom,flagdic,paramdic):
|
|---|
| 325 | params = dom.getElementsByTagName("parameter")
|
|---|
| 326 | for p in params:
|
|---|
| 327 | elements=p.getElementsByTagName("value") #sometimes there are empty <value> tags in workspace files
|
|---|
| 328 | if len(elements) > 0:
|
|---|
| 329 | paramdic[p.getAttribute('name')] = upsizeifnecessary(paramdic['task'],p.getAttribute('name'),elements[0].childNodes[0].data,UPSIZE)
|
|---|
| 330 |
|
|---|
| 331 | flags = dom.getElementsByTagName("flag")
|
|---|
| 332 | for f in flags:
|
|---|
| 333 | if (f.getAttribute('name') <> 'verbose') and (f.getAttribute('name') <> 'overwrite') and (f.getAttribute('name') <> 'quiet'):
|
|---|
| 334 | flagdic [f.getAttribute('name')] = f.getAttribute('name')
|
|---|
| 335 |
|
|---|
| 336 |
|
|---|
| 337 | def processlayers(dom,l):
|
|---|
| 338 | # processing layers of a display. Layers are returned in the l array
|
|---|
| 339 | for lay in dom:
|
|---|
| 340 | if lay.getAttribute('checked') == '1':
|
|---|
| 341 | paramdic = {}
|
|---|
| 342 | flagdic = {}
|
|---|
| 343 | opacity = lay.getAttribute('opacity')
|
|---|
| 344 | if opacity.startswith('1'):
|
|---|
| 345 | opacity = '1'
|
|---|
| 346 | processlayer(lay,flagdic,paramdic)
|
|---|
| 347 | l.insert(
|
|---|
| 348 | 0, (opacity, paramdic['task'] , paramdic, flagdic))
|
|---|
| 349 |
|
|---|
| 350 | def processoverlays(dom,l):
|
|---|
| 351 | # processing layers of a display. Layers are returned in the l array
|
|---|
| 352 | for lay in dom:
|
|---|
| 353 | paramdic = {}
|
|---|
| 354 | flagdic = {}
|
|---|
| 355 | task = lay.getAttribute('name')
|
|---|
| 356 | paramdic['task'] = task
|
|---|
| 357 | opacity = '1'
|
|---|
| 358 | processoverlay(lay,flagdic,paramdic)
|
|---|
| 359 | l.append((opacity, paramdic['task'] , paramdic, flagdic))
|
|---|
| 360 |
|
|---|
| 361 |
|
|---|
| 362 | def readworkspace(wspname):
|
|---|
| 363 | # READS WORKSPACE FILE
|
|---|
| 364 | displaydic = {} # adding support for more displays
|
|---|
| 365 | grass.verbose(_("Layers: "))
|
|---|
| 366 | f = open(wspname, 'r')
|
|---|
| 367 | textraw = f.read()
|
|---|
| 368 | f.close()
|
|---|
| 369 | text = cleanthisandthat(textraw)
|
|---|
| 370 | model = xml.dom.minidom.parseString(text)
|
|---|
| 371 | displays = model.getElementsByTagName("display")
|
|---|
| 372 | for display in displays:
|
|---|
| 373 | extents = []
|
|---|
| 374 | layers = []
|
|---|
| 375 | displayname = display.getAttribute('name')
|
|---|
| 376 | extentall = display.getAttribute('extent')
|
|---|
| 377 | extents = extentall.split(",")
|
|---|
| 378 | dimall = display.getAttribute('dim')
|
|---|
| 379 | dims = dimall.split(",")
|
|---|
| 380 | extents.extend(dims)
|
|---|
| 381 | layersmodel = display.getElementsByTagName('layer')
|
|---|
| 382 | processlayers(layersmodel,layers)
|
|---|
| 383 | overlaysmodel = display.getElementsByTagName('overlay')
|
|---|
| 384 | processoverlays(overlaysmodel,layers)
|
|---|
| 385 | layers.insert(0, extents)
|
|---|
| 386 | displaydic[displayname]=layers
|
|---|
| 387 | return displaydic
|
|---|
| 388 |
|
|---|
| 389 | def converttommfrom(value, fromunit):
|
|---|
| 390 | #converting some basic units to mm
|
|---|
| 391 | d = {'mm': 1, 'cm': 10, 'inch': 25.4}
|
|---|
| 392 | return (value * d[fromunit])
|
|---|
| 393 |
|
|---|
| 394 |
|
|---|
| 395 | def getpagemargins(option, unit):
|
|---|
| 396 | # we live on mm so convert user input as specified by unit
|
|---|
| 397 | d = {}
|
|---|
| 398 | if len(option) < 1:
|
|---|
| 399 | d['l'] = 25.0
|
|---|
| 400 | d['r'] = 25.0
|
|---|
| 401 | d['t'] = 25.0
|
|---|
| 402 | d['b'] = 25.0
|
|---|
| 403 | return d
|
|---|
| 404 | temp = option.split(",")
|
|---|
| 405 | d['l'] = converttommfrom(float(temp[0]), unit)
|
|---|
| 406 | if len(temp) < 4:
|
|---|
| 407 | d['r'] = d['l']
|
|---|
| 408 | d['t'] = d['l']
|
|---|
| 409 | d['b'] = d['l']
|
|---|
| 410 | return d
|
|---|
| 411 | d['r'] = converttommfrom(float(temp[1]), unit)
|
|---|
| 412 | d['t'] = converttommfrom(float(temp[2]), unit)
|
|---|
| 413 | d['b'] = converttommfrom(float(temp[3]), unit)
|
|---|
| 414 | return d
|
|---|
| 415 |
|
|---|
| 416 |
|
|---|
| 417 | def getpagedata(page):
|
|---|
| 418 | # returns page description data dictionary for the selected page
|
|---|
| 419 | d = PAGEDIC
|
|---|
| 420 | w = d[page][0]
|
|---|
| 421 | h = d[page][1]
|
|---|
| 422 | return {'width': w, 'w': w, 'height': h, 'h': h, 'page': d[page][3], 'parameters': d[page][2]}
|
|---|
| 423 |
|
|---|
| 424 |
|
|---|
| 425 | def getpagesizes(page):
|
|---|
| 426 | # return page sizes only in dictionary
|
|---|
| 427 | d = PAGEDIC
|
|---|
| 428 | w = d[page][0]
|
|---|
| 429 | h = d[page][1]
|
|---|
| 430 | return {'width': w, 'w': w, 'height': h, 'h': h}
|
|---|
| 431 |
|
|---|
| 432 |
|
|---|
| 433 | def dictodots(dic, dpi):
|
|---|
| 434 | # takes all values from a dictionary and returns another dic with
|
|---|
| 435 | # incoming mm values converted to dots
|
|---|
| 436 | d2 = {}
|
|---|
| 437 | for key in dic:
|
|---|
| 438 | d2[key] = int(round(dic[key] / 25.4 * dpi))
|
|---|
| 439 | return d2
|
|---|
| 440 |
|
|---|
| 441 |
|
|---|
| 442 | def dictomm(dic, dpi):
|
|---|
| 443 | # takes all values from a dictionary and returns another dic with
|
|---|
| 444 | # incoming dot values converted to mm
|
|---|
| 445 | d2 = {}
|
|---|
| 446 | for key in dic:
|
|---|
| 447 | d2[key] = dic[key] * 25.4 / dpi
|
|---|
| 448 | return d2
|
|---|
| 449 |
|
|---|
| 450 |
|
|---|
| 451 | def getmaxframeindots(marginsindots, pagesizesindots):
|
|---|
| 452 | #returns available area on page in print dots (=pixels)
|
|---|
| 453 | l = marginsindots['l']
|
|---|
| 454 | r = pagesizesindots['w'] - marginsindots['r']
|
|---|
| 455 | t = marginsindots['t']
|
|---|
| 456 | b = pagesizesindots['h'] - marginsindots['b']
|
|---|
| 457 | return {'t': t, 'b': b, 'l': l, 'r': r}
|
|---|
| 458 |
|
|---|
| 459 |
|
|---|
| 460 | def getmapUL(option, unit):
|
|---|
| 461 | # processes user entered option for map area upper left corner
|
|---|
| 462 | # r - right d - down from top left of page
|
|---|
| 463 | d = {}
|
|---|
| 464 | if len(option) < 1:
|
|---|
| 465 | d['r'] = 0.0
|
|---|
| 466 | d['d'] = 0.0
|
|---|
| 467 | return d
|
|---|
| 468 | temp = option.split(",")
|
|---|
| 469 | d['r'] = converttommfrom(float(temp[0]), unit)
|
|---|
| 470 | if len(temp) < 2:
|
|---|
| 471 | d['d'] = d['r']
|
|---|
| 472 | return d
|
|---|
| 473 | d['d'] = converttommfrom(float(temp[1]), unit)
|
|---|
| 474 | return d
|
|---|
| 475 |
|
|---|
| 476 |
|
|---|
| 477 | def getmapsizes(option, unit):
|
|---|
| 478 | # processes user entered option for map size
|
|---|
| 479 | # width and height
|
|---|
| 480 | d = {}
|
|---|
| 481 | if len(option) < 1:
|
|---|
| 482 | d['w'] = 1000.0
|
|---|
| 483 | d['h'] = 1000.0
|
|---|
| 484 | return d
|
|---|
| 485 | temp = option.split(",")
|
|---|
| 486 | d['w'] = converttommfrom(float(temp[0]), unit)
|
|---|
| 487 | if len(temp) < 2:
|
|---|
| 488 | d['h'] = d['w']
|
|---|
| 489 | return d
|
|---|
| 490 | d['h'] = converttommfrom(float(temp[1]), unit)
|
|---|
| 491 | return d
|
|---|
| 492 |
|
|---|
| 493 |
|
|---|
| 494 | def getmapframeindots(mapulindots, mapsizesindots, mxfd):
|
|---|
| 495 | d = {}
|
|---|
| 496 | # if map frame is bigger then area between margins it is
|
|---|
| 497 | # shrinked to fit
|
|---|
| 498 | mirrorwidth = abs(mxfd['r'] - mxfd['l']) + 1
|
|---|
| 499 | mirrorheight = abs(mxfd['b'] - mxfd['t']) + 1
|
|---|
| 500 | if mirrorwidth < mapsizesindots['w']:
|
|---|
| 501 | wr = float(mirrorwidth) / mapsizesindots['w']
|
|---|
| 502 | mapsizesindots['w'] = int(round(mapsizesindots['w'] * wr))
|
|---|
| 503 | mapsizesindots['h'] = int(round(mapsizesindots['h'] * wr))
|
|---|
| 504 | if mirrorheight < mapsizesindots['h']:
|
|---|
| 505 | hr = float(mirrorheight) / mapsizesindots['h']
|
|---|
| 506 | mapsizesindots['w'] = int(round(mapsizesindots['w'] * hr))
|
|---|
| 507 | mapsizesindots['h'] = int(round(mapsizesindots['h'] * hr))
|
|---|
| 508 | if mapulindots['r'] < 0:
|
|---|
| 509 | realw = min(mirrorwidth, mapsizesindots['w'])
|
|---|
| 510 | unusedhalf = int(round((mirrorwidth - realw) / 2))
|
|---|
| 511 | d['l'] = mxfd['l'] + unusedhalf
|
|---|
| 512 | d['r'] = mxfd['r'] - unusedhalf
|
|---|
| 513 | else:
|
|---|
| 514 | d['l'] = max(mxfd['l'], mapulindots['r'])
|
|---|
| 515 | d['r'] = min(mxfd['r'], mapulindots['r'] + mapsizesindots['w'])
|
|---|
| 516 | if mapulindots['d'] < 0:
|
|---|
| 517 | realh = min(mirrorheight, mapsizesindots['h'])
|
|---|
| 518 | unusedhalf = int(round((mirrorheight - realh) / 2))
|
|---|
| 519 | d['t'] = mxfd['t'] + unusedhalf
|
|---|
| 520 | d['b'] = mxfd['b'] - unusedhalf
|
|---|
| 521 | else:
|
|---|
| 522 | d['t'] = max(mxfd['t'], mapulindots['d'])
|
|---|
| 523 | d['b'] = min(mxfd['b'], mapulindots['d'] + mapsizesindots['h'])
|
|---|
| 524 | d['h'] = d['b'] - d['t'] + 1
|
|---|
| 525 | d['w'] = d['r'] - d['l'] + 1
|
|---|
| 526 | return d
|
|---|
| 527 |
|
|---|
| 528 |
|
|---|
| 529 | def render(astring, pdic, fdic):
|
|---|
| 530 | grass.verbose(_("printws: Rendering into - BASE: " + LASTFILE))
|
|---|
| 531 | grass.verbose(_("printws: Rendering command: " + astring))
|
|---|
| 532 |
|
|---|
| 533 | pdic = copy.deepcopy(pdic) # parameters
|
|---|
| 534 | fdic = copy.deepcopy(fdic) # flags
|
|---|
| 535 |
|
|---|
| 536 | flags = ''
|
|---|
| 537 | for key in fdic:
|
|---|
| 538 | if key:
|
|---|
| 539 | # grass.message(" KEY:"+str(key)) #was debug message
|
|---|
| 540 | flags = flags + key
|
|---|
| 541 | pdic['flags'] = flags
|
|---|
| 542 |
|
|---|
| 543 | task = pdic['task']
|
|---|
| 544 | del pdic['task']
|
|---|
| 545 | # it should be replaced by grass.* API calls
|
|---|
| 546 | # os.system(astring)
|
|---|
| 547 | grass.run_command(task, **pdic) # migration is going on
|
|---|
| 548 |
|
|---|
| 549 |
|
|---|
| 550 | def getfontbypattern(kindpattern):
|
|---|
| 551 | # truetype and others which are likely utf8 start with capital font names
|
|---|
| 552 | # also some fonts with _ in names seemed to be utf8 for sure
|
|---|
| 553 | # fonts with space and : and without capital letter are excluded from
|
|---|
| 554 | # randomization
|
|---|
| 555 | s = grass.read_command("d.fontlist")
|
|---|
| 556 | safe = 'romans'
|
|---|
| 557 | split = s.splitlines()
|
|---|
| 558 | for l in split:
|
|---|
| 559 | # check if it has : or space.
|
|---|
| 560 | m = re.search('[\:\ ]+', l, re.IGNORECASE)
|
|---|
| 561 | if not m:
|
|---|
| 562 | m = re.search('(.*' + kindpattern + '.*)', l, re.IGNORECASE)
|
|---|
| 563 | if m:
|
|---|
| 564 | if (safe == 'romans') or (len(safe) > len(l)):
|
|---|
| 565 | # change only to simpler variant
|
|---|
| 566 | # simpler variant names are usually shorter
|
|---|
| 567 | safe = l
|
|---|
| 568 | if safe == 'romans':
|
|---|
| 569 | for l in split:
|
|---|
| 570 | # check if it has : or space.
|
|---|
| 571 | m = re.search('[\:\ ]+', l, re.IGNORECASE)
|
|---|
| 572 | if not m:
|
|---|
| 573 | m = re.search('[A-Z].+[_].+', l, re.IGNORECASE)
|
|---|
| 574 | if m:
|
|---|
| 575 | safe = l
|
|---|
| 576 | return safe # returns first suitable font, won't run through all of them
|
|---|
| 577 | return safe
|
|---|
| 578 | # print "printws: Selected font: " + safe
|
|---|
| 579 |
|
|---|
| 580 |
|
|---|
| 581 | def decodetextmacros(text, dic):
|
|---|
| 582 | # Yes, indeed, macros ARE case sensitive !!!
|
|---|
| 583 | result = text
|
|---|
| 584 | for key in dic:
|
|---|
| 585 | result = re.sub(key, dic[key], result)
|
|---|
| 586 | return result
|
|---|
| 587 |
|
|---|
| 588 | #-----------------------------------------------------
|
|---|
| 589 | #-----------------------------------------------------
|
|---|
| 590 | #-----------------------------------------------------
|
|---|
| 591 | #------------------- MAIN ---------------------------
|
|---|
| 592 | #-----------------------------------------------------
|
|---|
| 593 | #-----------------------------------------------------
|
|---|
| 594 | #-----------------------------------------------------
|
|---|
| 595 | #-----------------------------------------------------
|
|---|
| 596 |
|
|---|
| 597 |
|
|---|
| 598 | def main():
|
|---|
| 599 |
|
|---|
| 600 | # Following declarations MAY will used in future for sure.
|
|---|
| 601 | global GISDBASE, LAYERCOUNT, LASTFILE
|
|---|
| 602 |
|
|---|
| 603 | # Check if ImageMagick is available since it is essential
|
|---|
| 604 | if os.name == 'nt':
|
|---|
| 605 | if grass.find_program('magick', '-version'):
|
|---|
| 606 | grass.verbose(_('printws: ImageMagick is available: OK!'))
|
|---|
| 607 | else:
|
|---|
| 608 | grass.fatal('ImageMagick is not accessible. See documentation of m.printws module for details.')
|
|---|
| 609 | else:
|
|---|
| 610 | if grass.find_program('convert', '-version'):
|
|---|
| 611 | grass.verbose(_('printws: ImageMagick is available: OK!'))
|
|---|
| 612 | else:
|
|---|
| 613 | grass.fatal('ImageMagick is not accessible. See documentation of m.printws module for details.')
|
|---|
| 614 |
|
|---|
| 615 | textmacros = {}
|
|---|
| 616 | # %nam% macros are kept for backward compatibility
|
|---|
| 617 | textmacros['%TIME24%'] = time.strftime("%H:%M:%S")
|
|---|
| 618 | textmacros['%DATEYMD%'] = time.strftime("%Y.%m.%d")
|
|---|
| 619 | textmacros['%DATEMDY%'] = time.strftime("%m/%d/%Y")
|
|---|
| 620 | if not hasPwd:
|
|---|
| 621 | textmacros['%USERNAME%'] = '(user unknown)'
|
|---|
| 622 | else:
|
|---|
| 623 | textmacros['%USERNAME%'] = pwd.getpwuid(os.getuid())[0]
|
|---|
| 624 | # using $ for macros in the future. New items should be created
|
|---|
| 625 | # exclusively as $macros later on
|
|---|
| 626 | textmacros['\$TIME24'] = textmacros['%TIME24%']
|
|---|
| 627 | textmacros['\$DATEYMD'] = textmacros['%DATEYMD%']
|
|---|
| 628 | textmacros['\$DATEMDY'] = textmacros['%DATEMDY%']
|
|---|
| 629 | textmacros['\$USERNAME'] = textmacros['%USERNAME%']
|
|---|
| 630 |
|
|---|
| 631 | textmacros['\$SPC'] = u'\u00A0' #?? d.text won't display this at string end hmmm
|
|---|
| 632 |
|
|---|
| 633 |
|
|---|
| 634 | # saves region for restoring at end
|
|---|
| 635 | # doing with official method:
|
|---|
| 636 | grass.use_temp_region()
|
|---|
| 637 |
|
|---|
| 638 | # getting/setting screen/print dpi ratio
|
|---|
| 639 |
|
|---|
| 640 | if len(options['dpi']) > 0:
|
|---|
| 641 | dpioption = float(options['dpi'])
|
|---|
| 642 | else:
|
|---|
| 643 | dpioption = 150.0
|
|---|
| 644 |
|
|---|
| 645 | if len(options['screendpi']) > 0:
|
|---|
| 646 | screendpioption = float(options['screendpi'])
|
|---|
| 647 | else:
|
|---|
| 648 | screendpioption = 100.0
|
|---|
| 649 |
|
|---|
| 650 | global UPSIZE
|
|---|
| 651 | UPSIZE = float(dpioption) / float(screendpioption)
|
|---|
| 652 |
|
|---|
| 653 | if len(options['input']) > 0:
|
|---|
| 654 | displays = readworkspace(options['input'])
|
|---|
| 655 | else:
|
|---|
| 656 | quit()
|
|---|
| 657 |
|
|---|
| 658 | textmacros['%GXW%'] = options['input']
|
|---|
| 659 | textmacros['\$GXW'] = textmacros['%GXW%']
|
|---|
| 660 |
|
|---|
| 661 | displaycounter = 0
|
|---|
| 662 |
|
|---|
| 663 | # there could be multiple displays in a workspace so we loop them
|
|---|
| 664 | # each display is a whole and independent file assembly
|
|---|
| 665 | for key in displays:
|
|---|
| 666 | textmacros['%DISPLAY%'] = key
|
|---|
| 667 | textmacros['\$DISPLAY'] = key
|
|---|
| 668 | grass.verbose(_('printws: rendering display: ' + key))
|
|---|
| 669 | displaycounter = displaycounter + 1
|
|---|
| 670 | layers = copy.deepcopy(displays[key])
|
|---|
| 671 |
|
|---|
| 672 | # extracting extent information from layers dic and erase the item
|
|---|
| 673 | # extents[0-5] w s e n minz maxz ; extents [6-9] window x y w h
|
|---|
| 674 | extents = layers[0]
|
|---|
| 675 | grass.verbose("m.printws: EXTENTS from workspace:" +
|
|---|
| 676 | str(extents)) # was debug message
|
|---|
| 677 | del layers[0]
|
|---|
| 678 |
|
|---|
| 679 | regionmode = ''
|
|---|
| 680 | if len(options['region']) > 0:
|
|---|
| 681 | grass.run_command("g.region", region=options['region'])
|
|---|
| 682 | regionmode = 'region'
|
|---|
| 683 | else:
|
|---|
| 684 | grass.run_command("g.region", "", w=extents[0], s=extents[
|
|---|
| 685 | 1], e=extents[2], n=extents[3])
|
|---|
| 686 | regionmode = 'window'
|
|---|
| 687 |
|
|---|
| 688 | # setting GRASS rendering environment
|
|---|
| 689 |
|
|---|
| 690 | # dummy file name is defined since the following lines
|
|---|
| 691 | # when switching on the cairo driver would create
|
|---|
| 692 | # an empty map.png in the current directory
|
|---|
| 693 | os.environ['GRASS_RENDER_FILE'] = os.path.join(TMPDIR, str(os.getpid(
|
|---|
| 694 | )) + '_DIS_' + str(00) + '_GEN_' + str(00) + '.png')
|
|---|
| 695 | os.environ['GRASS_RENDER_IMMEDIATE'] = 'cairo'
|
|---|
| 696 | os.environ['GRASS_RENDER_FILE_READ'] = 'TRUE'
|
|---|
| 697 | os.environ['GRASS_RENDER_TRANSPARENT'] = 'TRUE'
|
|---|
| 698 | os.environ['GRASS_RENDER_FILE_COMPRESSION'] = '0'
|
|---|
| 699 | os.environ['GRASS_RENDER_FILE_MAPPED'] = 'TRUE'
|
|---|
| 700 |
|
|---|
| 701 | # reading further options and setting defaults
|
|---|
| 702 |
|
|---|
| 703 | if len(options['page']) > 0:
|
|---|
| 704 | pageoption = options['page']
|
|---|
| 705 | else:
|
|---|
| 706 | pageoption = 'A4landscape'
|
|---|
| 707 |
|
|---|
| 708 | # parsing titles, etc.
|
|---|
| 709 | if len(options['font']) > 0:
|
|---|
| 710 | isAsterisk = options['font'].find('*')
|
|---|
| 711 | if isAsterisk > 0:
|
|---|
| 712 | titlefont = getfontbypattern(
|
|---|
| 713 | options['font'].replace('*', ''))
|
|---|
| 714 | else:
|
|---|
| 715 | titlefont = options['font']
|
|---|
| 716 | else:
|
|---|
| 717 | titlefont = getfontbypattern('Open') # try to find something UTF-8
|
|---|
| 718 | grass.verbose(_("printws: titlefont: " + titlefont))
|
|---|
| 719 |
|
|---|
| 720 | if len(options['titlecolor']) > 0:
|
|---|
| 721 | titlecolor = options['titlecolor']
|
|---|
| 722 | else:
|
|---|
| 723 | titlecolor = black
|
|---|
| 724 |
|
|---|
| 725 | if len(options['maintitlesize']) > 0:
|
|---|
| 726 | maintitlesize = converttommfrom(
|
|---|
| 727 | float(options['maintitlesize']), options['layunits'])
|
|---|
| 728 | else:
|
|---|
| 729 | maintitlesize = 10.0
|
|---|
| 730 |
|
|---|
| 731 | if len(options['subtitlesize']) > 0:
|
|---|
| 732 | subtitlesize = converttommfrom(
|
|---|
| 733 | float(options['subtitlesize']), options['layunits'])
|
|---|
| 734 | else:
|
|---|
| 735 | subtitlesize = 7.0
|
|---|
| 736 |
|
|---|
| 737 |
|
|---|
| 738 | if len(options['pssize']) > 0:
|
|---|
| 739 | pssize = converttommfrom(
|
|---|
| 740 | float(options['pssize']), options['layunits'])
|
|---|
| 741 | else:
|
|---|
| 742 | pssize = 5.0
|
|---|
| 743 |
|
|---|
| 744 | # Please fasten your seatbelts :) Calculations start here.
|
|---|
| 745 | # -------------------------------------------------------------------
|
|---|
| 746 |
|
|---|
| 747 | pagesizes = getpagesizes(pageoption)
|
|---|
| 748 | pagesizesindots = dictodots(pagesizes, dpioption)
|
|---|
| 749 |
|
|---|
| 750 | # Leave space for titles up and ps down - still in mm !!
|
|---|
| 751 | upperspace = 0
|
|---|
| 752 | subtitletop = 0
|
|---|
| 753 | titletop = 0
|
|---|
| 754 | if len(options['maintitle']) > 0:
|
|---|
| 755 | titletop = 0.4 * maintitlesize
|
|---|
| 756 | upperspace = upperspace + titletop + maintitlesize
|
|---|
| 757 | if len(options['subtitle']) > 0:
|
|---|
| 758 | subtitletop = upperspace + 0.4 * subtitlesize
|
|---|
| 759 | upperspace = subtitletop + subtitlesize + 1
|
|---|
| 760 | lowerspace = 0
|
|---|
| 761 | if (len(options['psundercentral']) > 0) or (len(options['psunderright']) > 0) or (len(options['psunderleft']) > 0):
|
|---|
| 762 | lowerspace = lowerspace + pssize + 2
|
|---|
| 763 |
|
|---|
| 764 | os.environ['GRASS_RENDER_WIDTH'] = str(pagesizesindots['w'])
|
|---|
| 765 | os.environ['GRASS_RENDER_HEIGHT'] = str(pagesizesindots['h'])
|
|---|
| 766 |
|
|---|
| 767 | pagemargins = getpagemargins(
|
|---|
| 768 | options['pagemargin'], options['layunits'])
|
|---|
| 769 | pagemarginsindots = dictodots(pagemargins, dpioption)
|
|---|
| 770 |
|
|---|
| 771 | # Getting max drawing area in dots
|
|---|
| 772 | mxfd = getmaxframeindots(pagemarginsindots, pagesizesindots)
|
|---|
| 773 | maxframe = str(mxfd['t']) + ',' + str(mxfd['b']) + \
|
|---|
| 774 | ',' + str(mxfd['l']) + ',' + str(mxfd['r'])
|
|---|
| 775 |
|
|---|
| 776 | # convert font size in mm to percentage for d.text
|
|---|
| 777 | mxfmm = dictomm(mxfd, dpioption)
|
|---|
| 778 | maintitlesize = float(maintitlesize) / (mxfmm['b'] - mxfmm['t']) * 100.0
|
|---|
| 779 | subtitlesize = float(subtitlesize) / (mxfmm['b'] - mxfmm['t']) * 100.0
|
|---|
| 780 |
|
|---|
| 781 | pssize = float(pssize) / (mxfmm['r'] - mxfmm['l']) * 100.0
|
|---|
| 782 | # subtitle location is another issue
|
|---|
| 783 | subtitletoppercent = 100.0 - subtitletop / \
|
|---|
| 784 | (mxfmm['b'] - mxfmm['t']) * 100.0
|
|---|
| 785 | titletoppercent = 100.0 - titletop / \
|
|---|
| 786 | (mxfmm['b'] - mxfmm['t']) * 100.0
|
|---|
| 787 |
|
|---|
| 788 | mapul = getmapUL(options['mapupperleft'], options['layunits'])
|
|---|
| 789 | mapulindots = dictodots(mapul, dpioption)
|
|---|
| 790 |
|
|---|
| 791 | mapsizes = getmapsizes(options['mapsize'], options['layunits'])
|
|---|
| 792 | mapsizesindots = dictodots(mapsizes, dpioption)
|
|---|
| 793 |
|
|---|
| 794 | # Correcting map area ratio to ratio of region edges
|
|---|
| 795 | # OR screen window edges depeding on "regionmode"
|
|---|
| 796 | # for later: grass.use_temp_region()
|
|---|
| 797 | s = grass.read_command("g.region", flags='p')
|
|---|
| 798 | kv = grass.parse_key_val(s, sep=':')
|
|---|
| 799 | regioncols = float(kv['cols'].strip())
|
|---|
| 800 | regionrows = float(kv['rows'].strip())
|
|---|
| 801 | ewres = float(kv['ewres'].strip())
|
|---|
| 802 | nsres = float(kv['nsres'].strip())
|
|---|
| 803 | sizex = regioncols * ewres
|
|---|
| 804 | sizey = regionrows * nsres
|
|---|
| 805 |
|
|---|
| 806 | if regionmode == 'region':
|
|---|
| 807 | hregionratio = sizex / sizey
|
|---|
| 808 | grass.verbose(_("printws: REGION MODE - region "))
|
|---|
| 809 | else: # surprisingly doing the SAME
|
|---|
| 810 | # using screen window ratio for map area
|
|---|
| 811 | # next line was a test for this but didn't help on gadgets positioning
|
|---|
| 812 | #hregionratio = float(extents[8]) / float(extents[9])
|
|---|
| 813 | hregionratio = sizex / sizey
|
|---|
| 814 | grass.verbose(_("printws: REGION MODE - window"))
|
|---|
| 815 | hmapratio = mapsizes['w'] / mapsizes['h']
|
|---|
| 816 |
|
|---|
| 817 | grass.verbose(_("printws: raw mapsizes: " + str(mapsizesindots)))
|
|---|
| 818 | grass.verbose(_("printws: hr: " + str(hregionratio)))
|
|---|
| 819 | grass.verbose(_("printws: hm: " + str(hmapratio)))
|
|---|
| 820 | if hregionratio > hmapratio:
|
|---|
| 821 | grass.verbose(
|
|---|
| 822 | _("printws: Map area height correction / " + str(hregionratio)))
|
|---|
| 823 | mapsizes['h'] = mapsizes['w'] / hregionratio
|
|---|
| 824 | elif hregionratio < hmapratio:
|
|---|
| 825 | grass.verbose(
|
|---|
| 826 | _("printws: Map area width correction * " + str(hregionratio)))
|
|---|
| 827 | mapsizes['w'] = mapsizes['h'] * hregionratio
|
|---|
| 828 | mapsizesindots = dictodots(mapsizes, dpioption)
|
|---|
| 829 |
|
|---|
| 830 | # changing region resolution to match print resolution
|
|---|
| 831 | # to eliminate unnecessary CPU heating/data transfer
|
|---|
| 832 | # so as to make it faster
|
|---|
| 833 | # with only invisible detail loss.
|
|---|
| 834 | colsregiontomap = mapsizesindots['w'] / regioncols
|
|---|
| 835 | rowsregiontomap = mapsizesindots['h'] / regionrows
|
|---|
| 836 |
|
|---|
| 837 | newewres = ewres
|
|---|
| 838 | newnsres = nsres
|
|---|
| 839 |
|
|---|
| 840 | # if colsregiontomap < 1:
|
|---|
| 841 | # CHANGE: also enables raising of resolution to prevent
|
|---|
| 842 | # pixelation because of low resolution setting...
|
|---|
| 843 | newewres = ewres / colsregiontomap
|
|---|
| 844 | # if rowsregiontomap < 1:
|
|---|
| 845 | newnsres = nsres / rowsregiontomap
|
|---|
| 846 |
|
|---|
| 847 | grass.run_command("g.region", ewres=str(newewres), nsres=str(newnsres))
|
|---|
| 848 |
|
|---|
| 849 | # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|---|
| 850 | # it seems that d.wms uses the GRASS_REGION from region info
|
|---|
| 851 | # others may also do so we set it
|
|---|
| 852 | # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|---|
| 853 | kv2 = {}
|
|---|
| 854 | kv2['e'] = kv['east']
|
|---|
| 855 | kv2['n'] = kv['north']
|
|---|
| 856 | kv2['s'] = kv['south']
|
|---|
| 857 | kv2['w'] = kv['west']
|
|---|
| 858 | kv2['ewres'] = str(newewres)
|
|---|
| 859 | kv2['nsres'] = str(newnsres)
|
|---|
| 860 | #kv2['rows'] #- autocalculated to resolution - no need to set explicitly
|
|---|
| 861 | #kv2['cols'] #- autocalculated to resolution - no need to set explicitly
|
|---|
| 862 | #grass.message(str(kv2))
|
|---|
| 863 | #grass.message(grass.region_env(**kv2))
|
|---|
| 864 | #grass.message(s)
|
|---|
| 865 | os.environ['GRASS_REGION'] = grass.region_env(**kv2)
|
|---|
| 866 |
|
|---|
| 867 |
|
|---|
| 868 | # Getting mapping area in dots
|
|---|
| 869 | # Correcting mxfd to leave space for title and subscript
|
|---|
| 870 | pagemarginstitles = copy.deepcopy(pagemargins)
|
|---|
| 871 | pagemarginstitles['t'] = pagemarginstitles['t'] + upperspace
|
|---|
| 872 | pagemarginstitles['b'] = pagemarginstitles['b'] + lowerspace
|
|---|
| 873 | pagemarginsindotstitles = dictodots(pagemarginstitles, dpioption)
|
|---|
| 874 | mxfdtitles = getmaxframeindots(
|
|---|
| 875 | pagemarginsindotstitles, pagesizesindots)
|
|---|
| 876 |
|
|---|
| 877 | mpfd = getmapframeindots(mapulindots, mapsizesindots, mxfdtitles)
|
|---|
| 878 | if pageoption == 'Flexi':
|
|---|
| 879 | # For 'Flexi' page we modify the setup to create
|
|---|
| 880 | # a page containing only the map without margins
|
|---|
| 881 | grass.verbose(_("printws: pre Flexi mapframe: " + str(mpfd)))
|
|---|
| 882 | mpfd['b'] = mpfd['b'] - mpfd['t']
|
|---|
| 883 | mpfd['t'] = 0
|
|---|
| 884 | mpfd['r'] = mpfd['r'] - mpfd['l']
|
|---|
| 885 | mpfd['l'] = 0
|
|---|
| 886 | os.environ['GRASS_RENDER_WIDTH'] = str(mpfd['r'])
|
|---|
| 887 | os.environ['GRASS_RENDER_HEIGHT'] = str(mpfd['b'])
|
|---|
| 888 | grass.verbose(_("printws: post Flexi mapframe: " + str(mpfd)))
|
|---|
| 889 | mapframe = str(mpfd['t']) + ',' + str(mpfd['b']) + \
|
|---|
| 890 | ',' + str(mpfd['l']) + ',' + str(mpfd['r'])
|
|---|
| 891 |
|
|---|
| 892 | grass.verbose(_("printws: DOT VALUES ARE:"))
|
|---|
| 893 | grass.verbose(_("printws: maxframe: " + str(mxfd)))
|
|---|
| 894 | grass.verbose(_("printws: maxframe: " + maxframe))
|
|---|
| 895 | grass.verbose(_("printws: mapframe: " + str(mpfd)))
|
|---|
| 896 | grass.verbose(_("printws: mapframe: " + mapframe))
|
|---|
| 897 | grass.verbose(_("printws: page: " + str(pagesizesindots)))
|
|---|
| 898 | grass.verbose(_("printws: margins: " + str(pagemarginsindots)))
|
|---|
| 899 | grass.verbose(_("printws: mapUL: " + str(mapulindots)))
|
|---|
| 900 | grass.verbose(_("printws: mapsizes (corrected): " + str(mapsizesindots)))
|
|---|
| 901 | grass.verbose(_("printws: ewres (corrected): " + str(newewres)))
|
|---|
| 902 | grass.verbose(_("printws: nsres (corrected): " + str(newnsres)))
|
|---|
| 903 |
|
|---|
| 904 | # quit()
|
|---|
| 905 |
|
|---|
| 906 | # ------------------- INMAP -------------------
|
|---|
| 907 |
|
|---|
| 908 |
|
|---|
| 909 |
|
|---|
| 910 | # Do not limit -map. It was: -limit map 720000000 before...
|
|---|
| 911 | # So we can grow on disk as long as it lasts
|
|---|
| 912 | imcommand = 'convert -limit memory 720000000 -units PixelsPerInch -density ' + \
|
|---|
| 913 | str(int(dpioption)) + ' '
|
|---|
| 914 |
|
|---|
| 915 | if os.name == 'nt':
|
|---|
| 916 | imcommand = 'magick ' + imcommand
|
|---|
| 917 |
|
|---|
| 918 | os.environ['GRASS_RENDER_FRAME'] = mapframe
|
|---|
| 919 |
|
|---|
| 920 | grass.verbose(_("printws: Rendering: the following layers: "))
|
|---|
| 921 | lastopacity = '-1'
|
|---|
| 922 |
|
|---|
| 923 | for lay in layers:
|
|---|
| 924 | grass.verbose(_(lay[1] + ' at: ' + lay[0] + ' opacity'))
|
|---|
| 925 | if lay[0] == '1':
|
|---|
| 926 | if lastopacity <> '1':
|
|---|
| 927 | LASTFILE = os.path.join(TMPDIR, str(os.getpid()) + \
|
|---|
| 928 | '_DIS_' + str(displaycounter) + '_GEN_' + \
|
|---|
| 929 | str(LAYERCOUNT) + '.' + TMPFORMAT)
|
|---|
| 930 | os.environ['GRASS_RENDER_FILE'] = LASTFILE
|
|---|
| 931 | LAYERCOUNT = LAYERCOUNT + 2
|
|---|
| 932 | imcommand = imcommand + ' ' + LASTFILE
|
|---|
| 933 | lastopacity = '1'
|
|---|
| 934 | render(lay[1], lay[2], lay[3])
|
|---|
| 935 | else:
|
|---|
| 936 | lastopacity = lay[0]
|
|---|
| 937 | LASTFILE = os.path.join(TMPDIR, str(os.getpid(
|
|---|
| 938 | )) + '_DIS_' + str(displaycounter) + '_GEN_' + str(LAYERCOUNT) + '.' + TMPFORMAT)
|
|---|
| 939 | LAYERCOUNT = LAYERCOUNT + 2
|
|---|
| 940 | os.environ['GRASS_RENDER_FILE'] = LASTFILE
|
|---|
| 941 | grass.verbose("LAY: " + str(lay))
|
|---|
| 942 | render(lay[1], lay[2], lay[3])
|
|---|
| 943 | imcommand = imcommand + \
|
|---|
| 944 | ' \( ' + LASTFILE + ' -channel a -evaluate multiply ' + \
|
|---|
| 945 | lay[0] + ' +channel \)'
|
|---|
| 946 |
|
|---|
| 947 | # setting resolution back to pre-script state since map rendering is
|
|---|
| 948 | # finished
|
|---|
| 949 | # CHANGE: not necessary anymore since we use temp_region now
|
|---|
| 950 | # However, since we did set GRASS_REGION, let's redo it here
|
|---|
| 951 |
|
|---|
| 952 | os.environ.pop('GRASS_REGION')
|
|---|
| 953 |
|
|---|
| 954 |
|
|---|
| 955 | # ------------------- OUTSIDE MAP texts, etc -------------------
|
|---|
| 956 | if pageoption =='Flexi':
|
|---|
| 957 | grass.verbose(_('m.printws: WARNING! Felxi mode, will not create titles, etc...'))
|
|---|
| 958 | else:
|
|---|
| 959 | os.environ['GRASS_RENDER_FRAME'] = maxframe
|
|---|
| 960 |
|
|---|
| 961 | dict = {}
|
|---|
| 962 | dict['task'] = "d.text"
|
|---|
| 963 | dict['color'] = titlecolor
|
|---|
| 964 | dict['font'] = titlefont
|
|---|
| 965 | dict['charset'] = "UTF-8"
|
|---|
| 966 |
|
|---|
| 967 | if len(options['maintitle']) > 1:
|
|---|
| 968 | dict['text'] = decodetextmacros(options['maintitle'], textmacros)
|
|---|
| 969 | dict['at'] = "50," + str(titletoppercent)
|
|---|
| 970 | dict['align'] = "uc"
|
|---|
| 971 | dict['size'] = str(maintitlesize)
|
|---|
| 972 | render(str(dict), dict, {})
|
|---|
| 973 |
|
|---|
| 974 | if len(options['subtitle']) > 1:
|
|---|
| 975 | dict['text'] = decodetextmacros(options['subtitle'], textmacros)
|
|---|
| 976 | dict['at'] = "50," + str(subtitletoppercent)
|
|---|
| 977 | dict['align'] = "uc"
|
|---|
| 978 | dict['size'] = str(subtitlesize)
|
|---|
| 979 | render(str(dict), dict, {})
|
|---|
| 980 |
|
|---|
| 981 | dict['size'] = str(pssize)
|
|---|
| 982 |
|
|---|
| 983 | if len(options['psundercentral']) > 1:
|
|---|
| 984 | dict['text'] = decodetextmacros(
|
|---|
| 985 | options['psundercentral'], textmacros)
|
|---|
| 986 | dict['at'] = "50,1"
|
|---|
| 987 | dict['align'] = "lc"
|
|---|
| 988 | render(str(dict), dict, {})
|
|---|
| 989 | if len(options['psunderleft']) > 1:
|
|---|
| 990 | dict['text'] = decodetextmacros(options['psunderleft'], textmacros)
|
|---|
| 991 | dict['at'] = "0,1"
|
|---|
| 992 | dict['align'] = "ll"
|
|---|
| 993 | render(str(dict), dict, {})
|
|---|
| 994 | if len(options['psunderright']) > 1:
|
|---|
| 995 | dict['text'] = decodetextmacros(
|
|---|
| 996 | options['psunderright'], textmacros)
|
|---|
| 997 | dict['at'] = "100,1"
|
|---|
| 998 | dict['align'] = "lr"
|
|---|
| 999 | render(str(dict), dict, {})
|
|---|
| 1000 |
|
|---|
| 1001 | # ------------------- GENERATING OUTPUT FILE -------------------
|
|---|
| 1002 |
|
|---|
| 1003 | if len(options['output']) > 1:
|
|---|
| 1004 | output = options['output']
|
|---|
| 1005 | else:
|
|---|
| 1006 | output = 'map_' + str(os.getpid())
|
|---|
| 1007 |
|
|---|
| 1008 | # remove extension AND display number and naming if any
|
|---|
| 1009 | output = os.path.splitext(output)[0]
|
|---|
| 1010 | output = re.sub('_DISPLAY_[0-9]+_.*', '', output)
|
|---|
| 1011 |
|
|---|
| 1012 | if len(options['format']) > 1:
|
|---|
| 1013 | extension = options['format']
|
|---|
| 1014 | else:
|
|---|
| 1015 | extension = 'pdf'
|
|---|
| 1016 |
|
|---|
| 1017 | displaypart = ''
|
|---|
| 1018 | if len(displays) > 1:
|
|---|
| 1019 | displaypart = '_DISPLAY_' + str(displaycounter) + '_' + key
|
|---|
| 1020 |
|
|---|
| 1021 | pagedata = getpagedata(pageoption)
|
|---|
| 1022 | #params= ' -extent '+str(pagesizesindots['w'])+'x'+str(pagesizesindots['h'])+' -gravity center -compress jpeg -page '+pagedata['page']+' '+pagedata['parameters']+' -units PixelsPerInch -density '+str(dpioption)+'x'+str(dpioption)+' '
|
|---|
| 1023 | params = ' -compress jpeg -quality 92 ' + \
|
|---|
| 1024 | pagedata['parameters'] + ' -units PixelsPerInch -density ' + \
|
|---|
| 1025 | str(int(dpioption)) + ' '
|
|---|
| 1026 |
|
|---|
| 1027 | imcommand = imcommand + ' -layers flatten ' + params + \
|
|---|
| 1028 | '"' + output + displaypart + '.' + extension + '"'
|
|---|
| 1029 |
|
|---|
| 1030 | grass.verbose(
|
|---|
| 1031 | _('printws: And the imagemagick command is... ' + imcommand))
|
|---|
| 1032 | os.system(imcommand)
|
|---|
| 1033 |
|
|---|
| 1034 | if not flags['d']:
|
|---|
| 1035 | grass.verbose(_('printws: Doing graceful cleanup...'))
|
|---|
| 1036 | os.system('rm ' + os.path.join(TMPDIR, str(os.getpid()) + '*_GEN_*'))
|
|---|
| 1037 | if REMOVE_TMPDIR:
|
|---|
| 1038 | try_rmdir(TMPDIR)
|
|---|
| 1039 | else:
|
|---|
| 1040 | grass.message("\n%s\n" % _(
|
|---|
| 1041 | "printws: Temp dir remove failed. Do it yourself, please:"))
|
|---|
| 1042 | sys.stderr.write('%s\n' % TMPDIR % ' <---- this')
|
|---|
| 1043 |
|
|---|
| 1044 | # restoring pre-script region
|
|---|
| 1045 | # - not necessary as we are using grass.use_temp_region() in the future
|
|---|
| 1046 |
|
|---|
| 1047 | return 0
|
|---|
| 1048 |
|
|---|
| 1049 | if __name__ == "__main__":
|
|---|
| 1050 | options, flags = grass.parser()
|
|---|
| 1051 | global TMPDIR
|
|---|
| 1052 | TMPDIR = tempfile.mkdtemp()
|
|---|
| 1053 | atexit.register(cleanup)
|
|---|
| 1054 | sys.exit(main())
|
|---|