def render(self): """Render the map composition to an image and save that to disk. :returns: A three-tuple of: * str: image_path - absolute path to png of rendered map * QImage: image - in memory copy of rendered map * QRectF: target_area - dimensions of rendered map :rtype: tuple """ LOGGER.debug('InaSAFE Map renderComposition called') # NOTE: we ignore self.composition.printAsRaster() and always rasterise width = int(self.page_dpi * self.page_width / 25.4) height = int(self.page_dpi * self.page_height / 25.4) image = QtGui.QImage(QtCore.QSize(width, height), QtGui.QImage.Format_ARGB32) image.setDotsPerMeterX(dpi_to_meters(self.page_dpi)) image.setDotsPerMeterY(dpi_to_meters(self.page_dpi)) # Only works in Qt4.8 #image.fill(QtGui.qRgb(255, 255, 255)) # Works in older Qt4 versions image.fill(55 + 255 * 256 + 255 * 256 * 256) image_painter = QtGui.QPainter(image) source_area = QtCore.QRectF(0, 0, self.page_width, self.page_height) target_area = QtCore.QRectF(0, 0, width, height) self.composition.render(image_painter, target_area, source_area) image_painter.end() image_path = unique_filename(prefix='mapRender_', suffix='.png', dir=temp_dir()) image.save(image_path) return image_path, image, target_area
def render(self): """Render the map composition to an image and save that to disk. :returns: A three-tuple of: * str: myImagePath - absolute path to png of rendered map * QImage: myImage - in memory copy of rendered map * QRectF: myTargetArea - dimensions of rendered map :rtype: tuple """ LOGGER.debug('InaSAFE Map renderComposition called') # NOTE: we ignore self.composition.printAsRaster() and always rasterise myWidth = int(self.pageDpi * self.pageWidth / 25.4) myHeight = int(self.pageDpi * self.pageHeight / 25.4) myImage = QtGui.QImage(QtCore.QSize(myWidth, myHeight), QtGui.QImage.Format_ARGB32) myImage.setDotsPerMeterX(dpi_to_meters(self.pageDpi)) myImage.setDotsPerMeterY(dpi_to_meters(self.pageDpi)) # Only works in Qt4.8 #myImage.fill(QtGui.qRgb(255, 255, 255)) # Works in older Qt4 versions myImage.fill(55 + 255 * 256 + 255 * 256 * 256) myImagePainter = QtGui.QPainter(myImage) mySourceArea = QtCore.QRectF(0, 0, self.pageWidth, self.pageHeight) myTargetArea = QtCore.QRectF(0, 0, myWidth, myHeight) self.composition.render(myImagePainter, myTargetArea, mySourceArea) myImagePainter.end() myImagePath = unique_filename(prefix='mapRender_', suffix='.png', dir=temp_dir()) myImage.save(myImagePath) return myImagePath, myImage, myTargetArea
def render(self): """Render the map composition to an image and save that to disk. :returns: A three-tuple of: * str: myImagePath - absolute path to png of rendered map * QImage: myImage - in memory copy of rendered map * QRectF: myTargetArea - dimensions of rendered map :rtype: tuple """ LOGGER.debug('InaSAFE Map renderComposition called') # NOTE: we ignore self.composition.printAsRaster() and always rasterise myWidth = (int)(self.pageDpi * self.pageWidth / 25.4) myHeight = (int)(self.pageDpi * self.pageHeight / 25.4) myImage = QtGui.QImage(QtCore.QSize(myWidth, myHeight), QtGui.QImage.Format_ARGB32) myImage.setDotsPerMeterX(dpi_to_meters(self.pageDpi)) myImage.setDotsPerMeterY(dpi_to_meters(self.pageDpi)) # Only works in Qt4.8 #myImage.fill(QtGui.qRgb(255, 255, 255)) # Works in older Qt4 versions myImage.fill(55 + 255 * 256 + 255 * 256 * 256) myImagePainter = QtGui.QPainter(myImage) mySourceArea = QtCore.QRectF(0, 0, self.pageWidth, self.pageHeight) myTargetArea = QtCore.QRectF(0, 0, myWidth, myHeight) self.composition.render(myImagePainter, myTargetArea, mySourceArea) myImagePainter.end() myImagePath = unique_filename(prefix='mapRender_', suffix='.png', dir=temp_dir()) myImage.save(myImagePath) return myImagePath, myImage, myTargetArea
def grow_legend(self): """Grow the legend pixmap enough to accommodate one more legend entry. """ LOGGER.debug('InaSAFE Map Legend extendLegend called') if self.legendImage is None: self.legendImage = QtGui.QImage(self.legendWidth, 95, QtGui.QImage.Format_RGB32) self.legendImage.setDotsPerMeterX(dpi_to_meters(self.dpi)) self.legendImage.setDotsPerMeterY(dpi_to_meters(self.dpi)) # Only works in Qt4.8 #self.legendImage.fill(QtGui.QColor(255, 255, 255)) # Works in older Qt4 versions self.legendImage.fill(255 + 255 * 256 + 255 * 256 * 256) myPainter = QtGui.QPainter(self.legendImage) myFontWeight = QtGui.QFont.Bold myItalicsFlag = False myFont = QtGui.QFont('verdana', self.legendFontSize, myFontWeight, myItalicsFlag) myPainter.setFont(myFont) myPainter.drawText(10, 25, self.legendTitle) if self.legendUnits is not None: myFontWeight = QtGui.QFont.StyleNormal myItalicsFlag = True legendUnitsFontSize = self.legendFontSize / 2 myFont = QtGui.QFont( 'verdana', legendUnitsFontSize, myFontWeight, myItalicsFlag) myPainter.setFont(myFont) myPainter.drawText(10, 45, self.legendUnits) else: # extend the existing legend down for the next class myImage = QtGui.QImage( self.legendWidth, self.legendImage.height() + self.legendIncrement, QtGui.QImage.Format_RGB32) myImage.setDotsPerMeterX(dpi_to_meters(self.dpi)) myImage.setDotsPerMeterY(dpi_to_meters(self.dpi)) # Only works in Qt4.8 #myImage.fill(QtGui.qRgb(255, 255, 255)) # Works in older Qt4 versions myImage.fill(255 + 255 * 256 + 255 * 256 * 256) myPainter = QtGui.QPainter(myImage) myRect = QtCore.QRectF(0, 0, self.legendImage.width(), self.legendImage.height()) myPainter.drawImage(myRect, self.legendImage, myRect) self.legendImage = myImage
def test_windowsDrawingArtifacts(self): """Test that windows rendering does not make artifacts""" # sometimes spurious lines are drawn on the layout LOGGER.info('Testing windowsDrawingArtifacts') myPath = unique_filename( prefix='artifacts', suffix='.pdf', dir=temp_dir('test')) myMap = Map(IFACE) setup_printer(myPath) myMap.setup_composition() myImage = QtGui.QImage(10, 10, QtGui.QImage.Format_RGB32) myImage.setDotsPerMeterX(dpi_to_meters(300)) myImage.setDotsPerMeterY(dpi_to_meters(300)) #myImage.fill(QtGui.QColor(250, 250, 250)) # Look at the output, you will see antialiasing issues around some # of the boxes drawn... # myImage.fill(QtGui.QColor(200, 200, 200)) myImage.fill(200 + 200 * 256 + 200 * 256 * 256) myFilename = os.path.join(temp_dir(), 'greyBox') myImage.save(myFilename, 'PNG') for i in range(10, 190, 10): myPicture = QgsComposerPicture(myMap.composition) myPicture.setPictureFile(myFilename) if qgis_version() >= 10800: # 1.8 or newer myPicture.setFrameEnabled(False) else: myPicture.setFrame(False) myPicture.setItemPosition(i, # x i, # y 10, # width 10) # height myMap.composition.addItem(myPicture) # Same drawing drawn directly as a pixmap # noinspection PyCallByClass,PyTypeChecker,PyArgumentList myPixmapItem = myMap.composition.addPixmap( QtGui.QPixmap.fromImage(myImage)) myPixmapItem.setOffset(i, i + 20) # Same drawing using our drawImage Helper myWidthMM = 1 myMap.draw_image(myImage, myWidthMM, i, i + 40) myImagePath, _, _ = myMap.render() # when this test no longer matches our broken render hash # we know the issue is fixed myTolerance = 0 myFlag, myMessage = check_images( 'windowsArtifacts', myImagePath, myTolerance) myMessage += ('\nWe want these images to match, if they do not ' 'there may be rendering artifacts in windows.\n') assert myFlag, myMessage
def grow_legend(self): """Grow the legend pixmap enough to accommodate one more legend entry. """ LOGGER.debug('InaSAFE Map Legend extendLegend called') if self.legend_image is None: self.legend_image = QtGui.QImage( self.legend_width, 95, QtGui.QImage.Format_RGB32) self.legend_image.setDotsPerMeterX(dpi_to_meters(self.dpi)) self.legend_image.setDotsPerMeterY(dpi_to_meters(self.dpi)) # Only works in Qt4.8 #self.legendImage.fill(QtGui.QColor(255, 255, 255)) # Works in older Qt4 versions self.legend_image.fill(255 + 255 * 256 + 255 * 256 * 256) painter = QtGui.QPainter(self.legend_image) font_weight = QtGui.QFont.Bold italics_flag = False font = QtGui.QFont( 'verdana', self.legend_font_size, font_weight, italics_flag) painter.setFont(font) painter.drawText(10, 25, self.legend_title) if self.legend_units is not None: font_weight = QtGui.QFont.StyleNormal italics_flag = True legend_units_font_size = self.legend_font_size / 2 font = QtGui.QFont( 'verdana', legend_units_font_size, font_weight, italics_flag) painter.setFont(font) painter.drawText(10, 45, self.legend_units) else: # extend the existing legend down for the next class image = QtGui.QImage( self.legend_width, self.legend_image.height() + self.legend_increment, QtGui.QImage.Format_RGB32) image.setDotsPerMeterX(dpi_to_meters(self.dpi)) image.setDotsPerMeterY(dpi_to_meters(self.dpi)) # Only works in Qt4.8 #myImage.fill(QtGui.qRgb(255, 255, 255)) # Works in older Qt4 versions image.fill(255 + 255 * 256 + 255 * 256 * 256) painter = QtGui.QPainter(image) rect = QtCore.QRectF( 0, 0, self.legend_image.width(), self.legend_image.height()) painter.drawImage(rect, self.legend_image, rect) self.legend_image = image
def grow_legend(self): """Grow the legend pixmap enough to accommodate one more legend entry. """ LOGGER.debug('InaSAFE Map Legend extendLegend called') if self.legend_image is None: self.legend_image = QtGui.QImage(self.legend_width, 95, QtGui.QImage.Format_RGB32) self.legend_image.setDotsPerMeterX(dpi_to_meters(self.dpi)) self.legend_image.setDotsPerMeterY(dpi_to_meters(self.dpi)) # Only works in Qt4.8 # self.legendImage.fill(QtGui.QColor(255, 255, 255)) # Works in older Qt4 versions self.legend_image.fill(255 + 255 * 256 + 255 * 256 * 256) painter = QtGui.QPainter(self.legend_image) font_weight = QtGui.QFont.Bold italics_flag = False font = QtGui.QFont('verdana', self.legend_font_size, font_weight, italics_flag) painter.setFont(font) painter.drawText(10, 25, self.legend_title) if self.legend_units is not None: font_weight = QtGui.QFont.StyleNormal italics_flag = True legend_units_font_size = self.legend_font_size / 2 font = QtGui.QFont('verdana', legend_units_font_size, font_weight, italics_flag) painter.setFont(font) painter.drawText(10, 45, self.legend_units) else: # extend the existing legend down for the next class image = QtGui.QImage( self.legend_width, self.legend_image.height() + self.legend_increment, QtGui.QImage.Format_RGB32) image.setDotsPerMeterX(dpi_to_meters(self.dpi)) image.setDotsPerMeterY(dpi_to_meters(self.dpi)) # Only works in Qt4.8 # myImage.fill(QtGui.qRgb(255, 255, 255)) # Works in older Qt4 versions image.fill(255 + 255 * 256 + 255 * 256 * 256) painter = QtGui.QPainter(image) rect = QtCore.QRectF(0, 0, self.legend_image.width(), self.legend_image.height()) painter.drawImage(rect, self.legend_image, rect) self.legend_image = image
def grow_legend(self): """Grow the legend pixmap enough to accommodate one more legend entry. """ LOGGER.debug('InaSAFE Map Legend extendLegend called') if self.legendImage is None: self.legendImage = QtGui.QImage(self.legendWidth, 95, QtGui.QImage.Format_RGB32) self.legendImage.setDotsPerMeterX(dpi_to_meters(self.dpi)) self.legendImage.setDotsPerMeterY(dpi_to_meters(self.dpi)) # Only works in Qt4.8 #self.legendImage.fill(QtGui.QColor(255, 255, 255)) # Works in older Qt4 versions self.legendImage.fill(255 + 255 * 256 + 255 * 256 * 256) myPainter = QtGui.QPainter(self.legendImage) myFontWeight = QtGui.QFont.Bold myItalicsFlag = False myFont = QtGui.QFont('verdana', self.legendFontSize, myFontWeight, myItalicsFlag) myPainter.setFont(myFont) myPainter.drawText(10, 25, self.legendTitle) if self.legendUnits is not None: myFontWeight = QtGui.QFont.StyleNormal myItalicsFlag = True legendUnitsFontSize = self.legendFontSize / 2 myFont = QtGui.QFont('verdana', legendUnitsFontSize, myFontWeight, myItalicsFlag) myPainter.setFont(myFont) myPainter.drawText(10, 45, self.legendUnits) else: # extend the existing legend down for the next class myImage = QtGui.QImage( self.legendWidth, self.legendImage.height() + self.legendIncrement, QtGui.QImage.Format_RGB32) myImage.setDotsPerMeterX(dpi_to_meters(self.dpi)) myImage.setDotsPerMeterY(dpi_to_meters(self.dpi)) # Only works in Qt4.8 #myImage.fill(QtGui.qRgb(255, 255, 255)) # Works in older Qt4 versions myImage.fill(255 + 255 * 256 + 255 * 256 * 256) myPainter = QtGui.QPainter(myImage) myRect = QtCore.QRectF(0, 0, self.legendImage.width(), self.legendImage.height()) myPainter.drawImage(myRect, self.legendImage, myRect) self.legendImage = myImage
def testDpiToMeters(self): """Test conversion from dpi to dpm.""" myDpi = 300 myDpm = dpi_to_meters(myDpi) myExpectedDpm = 11811.023622 myMessage = ('Conversion from dpi to dpm failed\n' ' Got: %s Expected: %s\n' % (myDpm, myExpectedDpm)) self.assertAlmostEqual(myDpm, myExpectedDpm, msg=myMessage)
def test_dpi_to_meters(self): """Test conversion from dpi to dpm.""" dpi = 300 dpm = dpi_to_meters(dpi) expected_dpm = 11811.023622 message = ('Conversion from dpi to dpm failed\n' ' Got: %s Expected: %s\n' % (dpm, expected_dpm)) self.assertAlmostEqual(dpm, expected_dpm, msg=message)
def html_to_image(self, html, width_mm): """Render some HTML to a pixmap. :param html: HTML to be rendered. It is assumed that the html is a snippet only, containing no body element - a standard header and footer will be appended. :type html: str :param width_mm: width of the table in mm - will be converted to points based on the resolution of our page. :type width_mm: int :returns: An image containing the rendered html. :rtype: QImage """ LOGGER.debug('InaSAFE Map renderHtmlToImage called') width_px = mm_to_points(width_mm, self.page_dpi) self.load_and_wait(html_snippet=html) frame = self.web_view.page().mainFrame() # Using 150dpi as the baseline, work out a standard text size # multiplier so that page renders equally well at different print # resolutions. #myBaselineDpi = 150 #myFactor = float(self.page_dpi) / myBaselineDpi #myFrame.setTextSizeMultiplier(myFactor) size = frame.contentsSize() size.setWidth(width_px) self.web_view.page().setViewportSize(size) image = QtGui.QImage(size, QtGui.QImage.Format_RGB32) image.setDotsPerMeterX(dpi_to_meters(self.page_dpi)) image.setDotsPerMeterY(dpi_to_meters(self.page_dpi)) # Only works in Qt4.8 #image.fill(QtGui.qRgb(255, 255, 255)) # Works in older Qt4 versions image.fill(255 + 255 * 256 + 255 * 256 * 256) painter = QtGui.QPainter(image) frame.render(painter) painter.end() return image
def html_to_image(self, html, width_mm): """Render some HTML to a pixmap. :param html: HTML to be rendered. It is assumed that the html is a snippet only, containing no body element - a standard header and footer will be appended. :type html: str :param width_mm: width of the table in mm - will be converted to points based on the resolution of our page. :type width_mm: int :returns: An image containing the rendered html. :rtype: QImage """ LOGGER.debug('InaSAFE Map renderHtmlToImage called') myWidthPx = mm_to_points(width_mm, self.pageDpi) self.load_and_wait(html_snippet=html) myFrame = self.webView.page().mainFrame() # Using 150dpi as the baseline, work out a standard text size # multiplier so that page renders equally well at different print # resolutions. #myBaselineDpi = 150 #myFactor = float(self.page_dpi) / myBaselineDpi #myFrame.setTextSizeMultiplier(myFactor) mySize = myFrame.contentsSize() mySize.setWidth(myWidthPx) self.webView.page().setViewportSize(mySize) myImage = QtGui.QImage(mySize, QtGui.QImage.Format_RGB32) myImage.setDotsPerMeterX(dpi_to_meters(self.pageDpi)) myImage.setDotsPerMeterY(dpi_to_meters(self.pageDpi)) # Only works in Qt4.8 #myImage.fill(QtGui.qRgb(255, 255, 255)) # Works in older Qt4 versions myImage.fill(255 + 255 * 256 + 255 * 256 * 256) myPainter = QtGui.QPainter(myImage) myFrame.render(myPainter) myPainter.end() myImage.save('/tmp/test.png') return myImage
def renderHtmlToImage(self, theHtml, theWidthMM): """Render some HTML to a pixmap. Args: * theHtml - HTML to be rendered. It is assumed that the html is a snippet only, containing no body element - a standard header and footer will be appended. * theWidthMM- width of the table in mm - will be converted to points based on the resolution of our page. Returns: QImage Raises: Any exceptions raised by the InaSAFE library will be propagated. """ LOGGER.debug('InaSAFE Map renderHtmlToImage called') myWidthPx = mm_to_points(theWidthMM, self.pageDpi) self.loadAndWait(theHtmlSnippet=theHtml) myFrame = self.webView.page().mainFrame() # Using 150dpi as the baseline, work out a standard text size # multiplier so that page renders equally well at different print # resolutions. #myBaselineDpi = 150 #myFactor = float(self.pageDpi) / myBaselineDpi #myFrame.setTextSizeMultiplier(myFactor) mySize = myFrame.contentsSize() mySize.setWidth(myWidthPx) self.webView.page().setViewportSize(mySize) myImage = QtGui.QImage(mySize, QtGui.QImage.Format_RGB32) myImage.setDotsPerMeterX(dpi_to_meters(self.pageDpi)) myImage.setDotsPerMeterY(dpi_to_meters(self.pageDpi)) # Only works in Qt4.8 #myImage.fill(QtGui.qRgb(255, 255, 255)) # Works in older Qt4 versions myImage.fill(255 + 255 * 256 + 255 * 256 * 256) myPainter = QtGui.QPainter(myImage) myFrame.render(myPainter) myPainter.end() myImage.save('/tmp/test.png') return myImage
def test_dpi_to_meters(self): """Test conversion from dpi to dpm.""" dpi = 300 dpm = dpi_to_meters(dpi) expected_dpm = 11811.023622 message = ( 'Conversion from dpi to dpm failed\n' ' Got: %s Expected: %s\n' % (dpm, expected_dpm)) self.assertAlmostEqual(dpm, expected_dpm, msg=message)