Esempio n. 1
0
    def get_backend(self, uri, client):
        '''Given the filename of an image, returns (fname, backend)
        where fname is the filename to be used (could be the same as
        filename, or something different if the image had to be converted
        or is missing), and backend is an Image class that can handle 
        fname.'''

        backend = defaultimage

        # Extract all the information from the URI
        filename, extension, options = self.split_uri(uri)

        # If the image doesn't exist, we use a 'missing' image
        if not os.path.exists(filename):
            log.error("Missing image file: %s", filename)
            filename = missing

        if extension in ['svg', 'svgz']:
            if SVGImage.available():
                log.info('Backend for %s is SVGIMage' % filename)
                backend = SVGImage
            else:
                filename = missing

        elif extension in [
                'ai', 'ccx', 'cdr', 'cgm', 'cmx', 'fig', 'sk1', 'sk', 'xml',
                'wmf'
        ]:
            log.info('Backend for %s is VectorImage' % filename)
            backend = VectorImage

        elif extension in ['pdf']:
            if VectorPdf is not None and filename is not missing:
                backend = VectorPdf
                filename = uri

            # PDF images are implemented by converting via PythonMagick
            # w,h are in pixels. I need to set the density
            # of the image to  the right dpi so this
            # looks decent
            elif LazyImports.PMImage or LazyImports.gfx:
                filename = self.raster(filename, client)
            else:
                log.warning("Minimal PDF image support "\
                    "requires PythonMagick [%s]", filename)
                filename = missing
        elif extension != 'jpg' and not LazyImports.PILImage:
            if LazyImports.PMImage:
                # Need to convert to JPG via PythonMagick
                filename = self.raster(filename)
            else:
                # No way to make this work
                log.error('To use a %s image you need PIL installed [%s]',
                          extension, filename)
                filename = missing
        return filename, backend
Esempio n. 2
0
    def parse(self, str):
        """Parse equation object string representation."""

        str = str.rstrip("\r\n")
        l = str.split(';')
        if len(l) != 5:
            _logger.error(_('Equation.parse() string invalid (%s)'), str)
            return False

        if l[2].startswith("<svg>"):
            l[2] = SVGImage(data=base64.b64decode(l[2][5:]))


# Should figure out how to use MathLib directly in a non-hacky way
        else:
            try:
                l[2] = Decimal(l[2])
            except Exception, inst:
                pass
Esempio n. 3
0
    def parse(self, str):
        """Parse equation object string representation."""

        str = str.rstrip("\r\n")
        k = str.split(';')
        if len(k) != 5:
            _logger.error(_('Equation.parse() string invalid (%s)'), str)
            return False

        if k[2].startswith("<svg>"):
            k[2] = SVGImage(data=base64.b64decode(k[2][5:]))

        # Should figure out how to use MathLib directly in a non-hacky way
        else:
            try:
                k[2] = Decimal(k[2])
            except Exception:
                pass

        self.set(k[0], k[1], k[2], XoColor(color_string=k[3]), k[4])
Esempio n. 4
0
    def process(self):
        """Parse the equation entered and show the result."""

        s = _s(self.text_entry.get_text())
        label = self.label_entry.get_text()
        _logger.debug('process(): parsing %r, label: %r', s, label)
        try:
            tree = self.parser.parse(s)
            res = self.parser.evaluate(tree)
        except ParserError as e:
            res = e
            self.showing_error = True

        if isinstance(res, str) and res.find('</svg>') > -1:
            res = SVGImage(data=res)

        _logger.debug('Result: %r', res)

        # Check whether assigning this label would cause recursion
        if not isinstance(res, ParserError) and len(label) > 0:
            lastpos = self.parser.get_var_used_ofs(label)
            if lastpos is not None:
                res = RuntimeError(
                    _('Can not assign label: will cause recursion'),
                    lastpos)

        # If parsing went ok, see if we have to replace the previous answer
        # to get a (more) exact result
        if self.ans_inserted and not isinstance(res, ParserError) \
                and not isinstance(res, SVGImage):
            ansvar = self.format_insert_ans()
            pos = s.find(ansvar)
            if len(ansvar) > 6 and pos != -1:
                s2 = s.replace(ansvar, 'LastEqn')
                _logger.debug(
                    'process(): replacing previous answer %r: %r', ansvar, s2)
                tree = self.parser.parse(s2)
                res = self.parser.evaluate(tree)

        if isinstance(res, ParserError):
            eqn = Equation(label, _n(s), res, self.color,
                           self.get_owner_id(), ml=self.ml)
            self.set_error_equation(eqn)
        else:
            eqn = Equation(label, _n(s), _n(str(res)), self.color,
                           self.get_owner_id(), ml=self.ml)
            self.add_equation(eqn, drawlasteq=True, tree=tree)
            self.send_message("add_eq", value=str(eqn))

            self.parser.set_var('Ans', eqn.result)

            # Setting LastEqn to the parse tree would certainly be faster,
            # however, it introduces recursion problems
            self.parser.set_var('LastEqn', eqn.result)

            self.showing_error = False
            self.ans_inserted = False
            self.text_entry.set_text('')
            self.label_entry.set_text('')

        return res is not None
Esempio n. 5
0
    def size_for_node(self, node, client):
        '''Given a docutils image node, returns the size the image should have
        in the PDF document, and what 'kind' of size that is. 
        That involves lots of guesswork'''

        uri = os.path.join(client.basedir, str(node.get("uri")))
        srcinfo = client, uri

        # Extract all the information from the URI
        imgname, extension, options = self.split_uri(uri)

        if not os.path.isfile(imgname):
            imgname = missing

        scale = float(node.get('scale', 100)) / 100
        size_known = False

        # Figuring out the size to display of an image is ... annoying.
        # If the user provides a size with a unit, it's simple, adjustUnits
        # will return it in points and we're done.

        # However, often the unit wil be "%" (specially if it's meant for
        # HTML originally. In which case, we will use a percentage of
        # the containing frame.

        # Find the image size in pixels:
        kind = 'direct'
        xdpi, ydpi = client.styles.def_dpi, client.styles.def_dpi
        extension = imgname.split('.')[-1].lower()
        if extension in ['svg', 'svgz'] and SVGImage.available():
            iw, ih = SVGImage(imgname, srcinfo=srcinfo).wrap(0, 0)
            # These are in pt, so convert to px
            iw = iw * xdpi / 72
            ih = ih * ydpi / 72

        elif extension in [
                "ai", "ccx", "cdr", "cgm", "cmx", "sk1", "sk", "xml", "wmf",
                "fig"
        ] and VectorImage.available():
            iw, ih = VectorImage(imgname, srcinfo=srcinfo).wrap(0, 0)
            # These are in pt, so convert to px
            iw = iw * xdpi / 72
            ih = ih * ydpi / 72

        elif extension == 'pdf':
            if VectorPdf is not None:
                box = VectorPdf.load_xobj(srcinfo).BBox
            else:
                pdf = LazyImports.pdfinfo
                if pdf is None:
                    log.warning(
                        'PDF images are not supported without pyPdf or pdfrw [%s]',
                        nodeid(node))
                    return 0, 0, 'direct'
                reader = pdf.PdfFileReader(open(imgname, 'rb'))
                box = [float(x) for x in reader.getPage(0)['/MediaBox']]
            x1, y1, x2, y2 = box
            # These are in pt, so convert to px
            iw = float((x2 - x1) * xdpi / 72)
            ih = float((y2 - y1) * ydpi / 72)
            size_known = True  # Assume size from original PDF is OK

        else:
            keeptrying = True

            if LazyImports.PILImage:
                try:
                    img = LazyImports.PILImage.open(imgname)
                    img.load()
                    iw, ih = img.size
                    xdpi, ydpi = img.info.get('dpi', (xdpi, ydpi))
                    keeptrying = False
                except IOError:  # PIL throws this when it's a broken/unknown image
                    pass
            if keeptrying and LazyImports.PMImage:
                img = LazyImports.PMImage(imgname)
                iw = img.size().width()
                ih = img.size().height()
                density = img.density()
                # The density is in pixelspercentimeter (!?)
                xdpi = density.width() * 2.54
                ydpi = density.height() * 2.54
                keeptrying = False
            if keeptrying:
                log.error(
                    "The image (%s, %s) is broken or in an unknown format",
                    imgname, nodeid(node))
                raise ValueError

        # Try to get the print resolution from the image itself via PIL.
        # If it fails, assume a DPI of 300, which is pretty much made up,
        # and then a 100% size would be iw*inch/300, so we pass
        # that as the second parameter to adjustUnits
        #
        # Some say the default DPI should be 72. That would mean
        # the largest printable image in A4 paper would be something
        # like 480x640. That would be awful.
        #

        w = node.get('width')
        h = node.get('height')
        if h is None and w is None:  # Nothing specified
            # Guess from iw, ih
            log.warning(
                "Using image %s without specifying size."
                "Calculating based on image size at %ddpi [%s]", imgname, xdpi,
                nodeid(node))
            w = iw * inch / xdpi
            h = ih * inch / ydpi
        elif w is not None:
            # Node specifies only w
            # In this particular case, we want the default unit
            # to be pixels so we work like rst2html
            if w[-1] == '%':
                kind = 'percentage_of_container'
                w = int(w[:-1])
            else:
                # This uses default DPI setting because we
                # are not using the image's "natural size"
                # this is what LaTeX does, according to the
                # docutils mailing list discussion
                w = client.styles.adjustUnits(w,
                                              client.styles.tw,
                                              default_unit='px')

            if h is None:
                # h is set from w with right aspect ratio
                h = w * ih / iw
            else:
                h = client.styles.adjustUnits(h,
                                              ih * inch / ydpi,
                                              default_unit='px')
        elif h is not None and w is None:
            if h[-1] != '%':
                h = client.styles.adjustUnits(h,
                                              ih * inch / ydpi,
                                              default_unit='px')

                # w is set from h with right aspect ratio
                w = h * iw / ih
            else:
                log.error('Setting height as a percentage does **not** work. '\
                          'ignoring height parameter [%s]', nodeid(node))
                # Set both from image data
                w = iw * inch / xdpi
                h = ih * inch / ydpi

        # Apply scale factor
        w = w * scale
        h = h * scale

        # And now we have this probably completely bogus size!
        log.info("Image %s size calculated:  %fcm by %fcm [%s]", imgname,
                 w / cm, h / cm, nodeid(node))

        return w, h, kind
Esempio n. 6
0
    def process(self):
        """Parse the equation entered and show the result"""

        s = unicode(self.text_entry.get_text())
        label = unicode(self.label_entry.get_text())
        _logger.debug('process(): parsing %r, label: %r', s, label)
        try:
            tree = self.parser.parse(s)
            res = self.parser.evaluate(tree)
        except ParserError, e:
            res = e
            self.showing_error = True

        if isinstance(res, str) and res.find('</svg>') > -1:
            res = SVGImage(data=res)

        _logger.debug('Result: %r', res)

        # Check whether assigning this label would cause recursion
        if not isinstance(res, ParserError) and len(label) > 0:
            lastpos = self.parser.get_var_used_ofs(label)
            if lastpos is not None:
                res = RuntimeError(
                    _('Can not assign label: will cause recursion'), lastpos)

# If parsing went ok, see if we have to replace the previous answer
# to get a (more) exact result
        if self.ans_inserted and not isinstance(res, ParserError) \
                and not isinstance(res, SVGImage):
            ansvar = self.format_insert_ans()
Esempio n. 7
0
    def get_backend(self, uri, client):
        '''Given the filename of an image, returns (fname, backend)
        where fname is the filename to be used (could be the same as
        filename, or something different if the image had to be converted
        or is missing), and backend is an Image class that can handle
        fname.


        If uri ensd with '.*' then the returned filename will be the best
        quality supported at the moment.

        That means:  PDF > SVG > anything else

        '''

        backend = defaultimage

        # Extract all the information from the URI
        filename, extension, options = self.split_uri(uri)

        if '*' in filename:
            preferred = ['gif', 'jpg', 'png']
            if SVGImage.available():
                preferred.append('svg')
            preferred.append('pdf')

            # Find out what images are available
            available = glob.glob(filename)
            cfn = available[0]
            cv = -10
            for fn in available:
                ext = fn.split('.')[-1]
                if ext in preferred:
                    v = preferred.index(ext)
                else:
                    v = -1
                if v > cv:
                    cv = v
                    cfn = fn
            # cfn should have our favourite type of
            # those available
            filename = cfn
            extension = cfn.split('.')[-1]
            uri = filename

        # If the image doesn't exist, we use a 'missing' image
        if not os.path.exists(filename):
            log.error("Missing image file: %s", filename)
            filename = missing

        if extension in ['svg', 'svgz']:
            if SVGImage.available():
                log.info('Backend for %s is SVGIMage' % filename)
                backend = SVGImage
            else:
                filename = missing

        elif extension in ['pdf']:
            if VectorPdf is not None and filename is not missing:
                backend = VectorPdf
                filename = uri

            # PDF images are implemented by converting via PythonMagick
            # w,h are in pixels. I need to set the density
            # of the image to  the right dpi so this
            # looks decent
            elif LazyImports.PMImage or LazyImports.gfx:
                filename = self.raster(filename, client)
            else:
                log.warning("Minimal PDF image support "\
                    "requires PythonMagick or the vectorpdf extension [%s]", filename)
                filename = missing
        elif extension != 'jpg' and not LazyImports.PILImage:
            if LazyImports.PMImage:
                # Need to convert to JPG via PythonMagick
                filename = self.raster(filename, client)
            else:
                # No way to make this work
                log.error('To use a %s image you need PIL installed [%s]',
                          extension, filename)
                filename = missing
        return filename, backend
Esempio n. 8
0
    def size_for_node(self, node, client):
        '''Given a docutils image node, returns the size the image should have
        in the PDF document, and what 'kind' of size that is.
        That involves lots of guesswork'''

        uri = str(node.get("uri"))
        if uri.split("://")[0].lower() not in ('http','ftp','https'):
            uri = os.path.join(client.basedir,uri)
        else:
            uri, _ = urllib.urlretrieve(uri)
            client.to_unlink.append(uri)

        srcinfo = client, uri
        # Extract all the information from the URI
        imgname, extension, options = self.split_uri(uri)

        if not os.path.isfile(imgname):
            imgname = missing

        scale = float(node.get('scale', 100))/100
        size_known = False

        # Figuring out the size to display of an image is ... annoying.
        # If the user provides a size with a unit, it's simple, adjustUnits
        # will return it in points and we're done.

        # However, often the unit wil be "%" (specially if it's meant for
        # HTML originally. In which case, we will use a percentage of
        # the containing frame.

        # Find the image size in pixels:
        kind = 'direct'
        xdpi, ydpi = client.styles.def_dpi, client.styles.def_dpi
        extension = imgname.split('.')[-1].lower()
        if extension in ['svg','svgz'] and SVGImage.available():
            iw, ih = SVGImage(imgname, srcinfo=srcinfo).wrap(0, 0)
            # These are in pt, so convert to px
            iw = iw * xdpi / 72
            ih = ih * ydpi / 72

        elif extension in [
                "ai", "ccx", "cdr", "cgm", "cmx",
                "sk1", "sk", "xml", "wmf", "fig"] and VectorImage.available():
            iw, ih = VectorImage(imgname, srcinfo=srcinfo).wrap(0, 0)
            # These are in pt, so convert to px
            iw = iw * xdpi / 72
            ih = ih * ydpi / 72

        elif extension == 'pdf':
            if VectorPdf is not None:
                box = VectorPdf.load_xobj(srcinfo).BBox
            else:
                pdf = LazyImports.pdfinfo
                if pdf is None:
                    log.warning('PDF images are not supported without pyPdf or pdfrw [%s]', nodeid(node))
                    return 0, 0, 'direct'
                reader = pdf.PdfFileReader(open(imgname, 'rb'))
                box = [float(x) for x in reader.getPage(0)['/MediaBox']]
            x1, y1, x2, y2 = box
            # These are in pt, so convert to px
            iw = float((x2-x1) * xdpi / 72)
            ih = float((y2-y1) * ydpi / 72)
            size_known = True  # Assume size from original PDF is OK

        else:
            keeptrying = True
            if sys.platform[0:4] == 'java':
                try:
                    from javax.imageio import ImageIO
                    from java.io import File

                    iis = ImageIO.createImageInputStream(File(imgname))
                    readers = ImageIO.getImageReaders(iis)
                    if readers.hasNext():
                        reader = readers.next()
                        reader.setInput(iis, True)
                        metadata = reader.getImageMetadata(0)
                        iw = reader.getWidth(0)
                        ih = reader.getHeight(0)
                        xdpi = None
                        ydpi = None
                        if metadata.getNativeMetadataFormatName() == 'javax_imageio_png_1.0':
                            png_metadata = metadata.getAsTree(metadata.getNativeMetadataFormatName())
                            if png_metadata is not None:
                                phys_metadata = png_metadata.getElementsByTagName('pHYs')
                                if phys_metadata.getLength() == 1:
                                    xdpi = phys_metadata.item(0).getAttribute('pixelsPerUnitXAxis')
                                    if xdpi is not None:
                                        xdpi = float(xdpi)
                                    ydpi = phys_metadata.item(0).getAttribute('pixelsPerUnitYAxis')
                                    if ydpi is not None:
                                        ydpi = float(ydpi)
                        elif metadata.getNativeMetadataFormatName() == 'javax_imageio_jpeg_image_1.0':
                            jpg_metadata = metadata.getAsTree(metadata.getNativeMetadataFormatName())
                            if jpg_metadata is not None:
                                jfif_metadata = jpg_metadata.getElementsByTagName('app0JFIF')
                                if jfif_metadata.getLength() == 1:
                                    resUnits = jfif_metadata.item(0).getAttribute('resUnits')
                                    # 0 = plain aspect ratio, 1 = dots per inch, 2 = dots per cm
                                    if resUnits is not None and (resUnits == '1' or resUnits == '2'):
                                        xdpi = jfif_metadata.item(0).getAttribute('pixelsPerUnitXAxis')
                                        if xdpi is not None:
                                            xdpi = float(xdpi)
                                            if resUnits == '2':
                                                xdpi = xdpi * 2.54
                                        ydpi = jfif_metadata.item(0).getAttribute('pixelsPerUnitYAxis')
                                        if ydpi is not None:
                                            ydpi = float(ydpi)
                                            if resUnits == '2':
                                                ydpi = ydpi * 2.54
                        if xdpi is None:
                            xdpi = 300
                        if ydpi is None:
                            ydpi = 300
                        keeptrying = False
                except Exception, err:
                    log.error('Error %s', str(err))
                    pass
            if LazyImports.PILImage:
                try:
                    img = LazyImports.PILImage.open(imgname)
                    img.load()
                    iw, ih = img.size
                    xdpi, ydpi = img.info.get('dpi', (xdpi, ydpi))
                    keeptrying = False
                except IOError: # PIL throws this when it's a broken/unknown image
                    pass
            if keeptrying and LazyImports.PMImage:
                img = LazyImports.PMImage(imgname)
                iw = img.size().width()
                ih = img.size().height()
                density=img.density()
                # The density is in pixelspercentimeter (!?)
                xdpi=density.width()*2.54
                ydpi=density.height()*2.54
                keeptrying = False
            if keeptrying:
                if extension not in ['jpg', 'jpeg']:
                    log.error("The image (%s, %s) is broken or in an unknown format"
                                , imgname, nodeid(node))
                    raise ValueError
                else:
                    # Can be handled by reportlab
                    log.warning("Can't figure out size of the image (%s, %s). Install PIL for better results."
                                , imgname, nodeid(node))
                    iw = 1000
                    ih = 1000
Esempio n. 9
0
    def get_backend(self, uri, client):
        '''Given the filename of an image, returns (fname, backend)
        where fname is the filename to be used (could be the same as
        filename, or something different if the image had to be converted
        or is missing), and backend is an Image class that can handle
        fname.


        If uri ensd with '.*' then the returned filename will be the best
        quality supported at the moment.

        That means:  PDF > SVG > anything else

        '''

        backend = defaultimage


        # Extract all the information from the URI
        filename, extension, options = self.split_uri(uri)

        if '*' in filename:
            preferred=['gif','jpg','png']
            if SVGImage.available():
                preferred.append('svg')
            preferred.append('pdf')

            # Find out what images are available
            available = glob.glob(filename)
            cfn=available[0]
            cv=-10
            for fn in available:
                ext=fn.split('.')[-1]
                if ext in preferred:
                    v=preferred.index(ext)
                else:
                    v=-1
                if v > cv:
                    cv=v
                    cfn=fn
            # cfn should have our favourite type of
            # those available
            filename = cfn
            extension = cfn.split('.')[-1]
            uri = filename

        # If the image doesn't exist, we use a 'missing' image
        if not os.path.exists(filename):
            log.error("Missing image file: %s",filename)
            filename = missing

        if extension in ['svg','svgz']:
            if SVGImage.available():
                log.info('Backend for %s is SVGIMage'%filename)
                backend=SVGImage
            else:
                filename = missing

        elif extension in ['ai', 'ccx', 'cdr', 'cgm', 'cmx', 'fig',
                'sk1', 'sk', 'xml', 'wmf']:
            log.info('Backend for %s is VectorImage'%filename)
            backend=VectorImage

        elif extension in ['pdf']:
            if VectorPdf is not None and filename is not missing:
                backend = VectorPdf
                filename = uri

            # PDF images are implemented by converting via PythonMagick
            # w,h are in pixels. I need to set the density
            # of the image to  the right dpi so this
            # looks decent
            elif LazyImports.PMImage or LazyImports.gfx:
                filename=self.raster(filename, client)
            else:
                log.warning("Minimal PDF image support "\
                    "requires PythonMagick or the vectorpdf extension [%s]", filename)
                filename = missing

        elif extension != 'jpg' and not LazyImports.PILImage and not sys.platform[0:4] == 'java':
            if LazyImports.PMImage:
                # Need to convert to JPG via PythonMagick
                filename=self.raster(filename)
            else:
                # No way to make this work
                log.error('To use a %s image you need PIL installed [%s]',extension,filename)
                filename=missing
        return filename, backend
    def size_for_node(self, node, client):
        '''Given a docutils image node, returns the size the image should have
        in the PDF document, and what 'kind' of size that is. 
        That involves lots of guesswork'''

        uri = str(node.get("uri"))
        if uri.split("://")[0].lower() not in ('http','ftp','https'):
            uri = os.path.join(client.basedir,uri)
        else:
            uri, _ = urllib.urlretrieve(uri)
            client.to_unlink.append(uri)
            
        srcinfo = client, uri
        # Extract all the information from the URI
        imgname, extension, options = self.split_uri(uri)

        if not os.path.isfile(imgname):
            imgname = missing
            
        scale = float(node.get('scale', 100))/100
        size_known = False

        # Figuring out the size to display of an image is ... annoying.
        # If the user provides a size with a unit, it's simple, adjustUnits
        # will return it in points and we're done.

        # However, often the unit wil be "%" (specially if it's meant for
        # HTML originally. In which case, we will use a percentage of
        # the containing frame.

        # Find the image size in pixels:
        kind = 'direct'
        xdpi, ydpi = client.styles.def_dpi, client.styles.def_dpi
        extension = imgname.split('.')[-1].lower()
        if extension in ['svg','svgz'] and SVGImage.available():
            iw, ih = SVGImage(imgname, srcinfo=srcinfo).wrap(0, 0)
            # These are in pt, so convert to px
            iw = iw * xdpi / 72
            ih = ih * ydpi / 72
            
        elif extension in [
                "ai", "ccx", "cdr", "cgm", "cmx",
                "sk1", "sk", "xml", "wmf", "fig"] and VectorImage.available():
            iw, ih = VectorImage(imgname, srcinfo=srcinfo).wrap(0, 0)
            # These are in pt, so convert to px
            iw = iw * xdpi / 72
            ih = ih * ydpi / 72
                    
        elif extension == 'pdf':
            if VectorPdf is not None:
                box = VectorPdf.load_xobj(srcinfo).BBox
            else:
                pdf = LazyImports.pdfinfo
                if pdf is None:
                    log.warning('PDF images are not supported without pyPdf or pdfrw [%s]', nodeid(node))
                    return 0, 0, 'direct'
                reader = pdf.PdfFileReader(open(imgname, 'rb'))
                box = [float(x) for x in reader.getPage(0)['/MediaBox']]
            x1, y1, x2, y2 = box
            # These are in pt, so convert to px
            iw = float((x2-x1) * xdpi / 72)
            ih = float((y2-y1) * ydpi / 72)
            size_known = True  # Assume size from original PDF is OK
            
        else:
            keeptrying = True
            if LazyImports.PILImage:
                try:
                    img = LazyImports.PILImage.open(imgname)
                    img.load()
                    iw, ih = img.size
                    xdpi, ydpi = img.info.get('dpi', (xdpi, ydpi))
                    keeptrying = False
                except IOError: # PIL throws this when it's a broken/unknown image
                    pass
            if keeptrying and LazyImports.PMImage:
                img = LazyImports.PMImage(imgname)
                iw = img.size().width()
                ih = img.size().height()
                density=img.density() 
                # The density is in pixelspercentimeter (!?)
                xdpi=density.width()*2.54
                ydpi=density.height()*2.54
                keeptrying = False
            if keeptrying:
                if extension not in ['jpg', 'jpeg']:
                    log.error("The image (%s, %s) is broken or in an unknown format"
                                , imgname, nodeid(node))
                    raise ValueError
                else:
                    # Can be handled by reportlab
                    log.warning("Can't figure out size of the image (%s, %s). Install PIL for better results."
                                , imgname, nodeid(node))
                    iw = 1000
                    ih = 1000

        # Try to get the print resolution from the image itself via PIL.
        # If it fails, assume a DPI of 300, which is pretty much made up,
        # and then a 100% size would be iw*inch/300, so we pass
        # that as the second parameter to adjustUnits
        #
        # Some say the default DPI should be 72. That would mean
        # the largest printable image in A4 paper would be something
        # like 480x640. That would be awful.
        #

        w = node.get('width')
        h = node.get('height')
        if h is None and w is None: # Nothing specified
            # Guess from iw, ih
            log.debug("Using image %s without specifying size."
                "Calculating based on image size at %ddpi [%s]",
                imgname, xdpi, nodeid(node))
            w = iw*inch/xdpi
            h = ih*inch/ydpi
        elif w is not None:
            # Node specifies only w
            # In this particular case, we want the default unit
            # to be pixels so we work like rst2html
            if w[-1] == '%':
                kind = 'percentage_of_container'
                w=int(w[:-1])
            else:
                # This uses default DPI setting because we
                # are not using the image's "natural size"
                # this is what LaTeX does, according to the
                # docutils mailing list discussion
                w = client.styles.adjustUnits(w, client.styles.tw,
                                            default_unit='px')
            
            if h is None:
                # h is set from w with right aspect ratio
                h = w*ih/iw
            else:
                h = client.styles.adjustUnits(h, ih*inch/ydpi, default_unit='px')
        elif h is not None and w is None:
            if h[-1] != '%':
                h = client.styles.adjustUnits(h, ih*inch/ydpi, default_unit='px')

                # w is set from h with right aspect ratio
                w = h*iw/ih
            else:
                log.error('Setting height as a percentage does **not** work. '\
                          'ignoring height parameter [%s]', nodeid(node))
                # Set both from image data
                w = iw*inch/xdpi
                h = ih*inch/ydpi

        # Apply scale factor
        w = w*scale
        h = h*scale

        # And now we have this probably completely bogus size!
        log.info("Image %s size calculated:  %fcm by %fcm [%s]",
            imgname, w/cm, h/cm, nodeid(node))

        return w, h, kind
Esempio n. 11
0
class Calculate(ShareableActivity):

    TYPE_FUNCTION = 1
    TYPE_OP_PRE = 2
    TYPE_OP_POST = 3
    TYPE_TEXT = 4

    SELECT_NONE = 0
    SELECT_SELECT = 1
    SELECT_TAB = 2

    KEYMAP = {
        'Return': lambda o: o.process(),
        'period': '.',
        'equal': '=',
        'plus': '+',
        'minus': '-',
        'asterisk': '*',
        'multiply': '×',
        'divide': '÷',
        'slash': '/',
        'BackSpace': lambda o: o.remove_character(-1),
        'Delete': lambda o: o.remove_character(1),
        'parenleft': '(',
        'parenright': ')',
        'exclam': '!',
        'ampersand': '&',
        'bar': '|',
        'asciicircum': '^',
        'less': '<',
        'greater': '>',
        'percent': '%',
        'comma': ',',
        'underscore': '_',
        'Left': lambda o: o.move_left(),
        'Right': lambda o: o.move_right(),
        'Up': lambda o: o.get_older(),
        'Down': lambda o: o.get_newer(),
        'colon': lambda o: o.label_entered(),
        'Home': lambda o: o.text_entry.set_position(0),
        'End':
        lambda o: o.text_entry.set_position(len(o.text_entry.get_text())),
        'Tab': lambda o: o.tab_complete(),
    }

    CTRL_KEYMAP = {
        'c': lambda o: o.text_copy(),
        'v': lambda o: o.text_paste(),
        'x': lambda o: o.text_cut(),
        'q': lambda o: o.close(),
        'a': lambda o: o.text_select_all(),
    }

    SHIFT_KEYMAP = {
        'Left': lambda o: o.expand_selection(-1),
        'Right': lambda o: o.expand_selection(1),
        'Home': lambda o: o.expand_selection(-1000),
        'End': lambda o: o.expand_selection(1000),
    }

    IDENTIFIER_CHARS = \
        u"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_ "

    def __init__(self, handle):
        ShareableActivity.__init__(self, handle)

        self.old_eqs = []

        self.ml = MathLib()
        self.parser = AstParser(self.ml)

        # These will result in 'Ans <operator character>' being inserted
        self._chars_ans_diadic = [
            op[0] for op in self.parser.get_diadic_operators()
        ]
        try:
            self._chars_ans_diadic.remove('-')
        except:
            pass

        self.KEYMAP['multiply'] = self.ml.mul_sym
        self.KEYMAP['divide'] = self.ml.div_sym
        self.KEYMAP['equal'] = self.ml.equ_sym

        self.clipboard = gtk.Clipboard()
        self.select_reason = self.SELECT_SELECT
        self.buffer = u""
        self.showing_version = 0
        self.showing_error = False
        self.ans_inserted = False
        self.show_vars = False

        self.connect("key_press_event", self.keypress_cb)
        self.connect("destroy", self.cleanup_cb)
        self.color = sugar.profile.get_color()

        self.layout = CalcLayout(self)
        self.label_entry = self.layout.label_entry
        self.text_entry = self.layout.text_entry
        self.last_eq_sig = None
        self.last_eqn_textview = None

        self.reset()
        self.layout.show_it()

        self.connect('joined', self._joined_cb)

        self.parser.log_debug_info()

    def ignore_key_cb(self, widget, event):
        return True

    def cleanup_cb(self, arg):
        _logger.debug('Cleaning up...')

    def equation_pressed_cb(self, eqn):
        """Callback for when an equation box is clicked"""

        if isinstance(eqn.result, SVGImage):
            return True

        if len(eqn.label) > 0:
            text = eqn.label
        else:
            # don't insert plain text
            if type(eqn.result) in (types.StringType, types.UnicodeType):
                text = ''
            else:
                text = self.parser.ml.format_number(eqn.result)

        self.button_pressed(self.TYPE_TEXT, text)
        return True

    def set_last_equation(self, eqn):
        """Set the 'last equation' TextView"""

        if self.last_eq_sig is not None:
            self.layout.last_eq.disconnect(self.last_eq_sig)
            self.last_eq_sig = None

        if not isinstance(eqn.result, ParserError):
            self.last_eq_sig = self.layout.last_eq.connect(
                'button-press-event',
                lambda a1, a2, e: self.equation_pressed_cb(e), eqn)

        self.layout.last_eq.set_buffer(eqn.create_lasteq_textbuf())

    def set_error_equation(self, eqn):
        """Set equation with error markers. Since set_last_equation implements
        this we can just forward the call."""
        self.set_last_equation(eqn)

    def clear_equations(self):
        """Clear the list of old equations."""
        self.old_eqs = []
        self.showing_version = 0

    def add_equation(self, eq, prepend=False, drawlasteq=False, tree=None):
        """
        Insert equation in the history list and set variable if assignment.
        Input:
            eq: the equation object
            prepend: if True, prepend to list, else append
            drawlasteq: if True, draw in 'last equation' textbox and queue the
            buffer to be added to the history next time an equation is added.
            tree: the parsed tree, this will be used to set the label variable
            so that the equation can be used symbolicaly.
            """
        if eq.equation is not None and len(eq.equation) > 0:
            if prepend:
                self.old_eqs.insert(0, eq)
            else:
                self.old_eqs.append(eq)

            self.showing_version = len(self.old_eqs)

        if self.last_eqn_textview is not None and drawlasteq:
            # Prepending here should be the opposite: prepend -> eqn on top.
            # We always own this equation
            self.layout.add_equation(self.last_eqn_textview,
                                     True,
                                     prepend=not prepend)
            self.last_eqn_textview = None

        own = (eq.owner == self.get_owner_id())
        w = eq.create_history_object()
        w.connect('button-press-event',
                  lambda w, e: self.equation_pressed_cb(eq))
        if drawlasteq:
            self.set_last_equation(eq)

            # SVG images can't be plotted in last equation window
            if isinstance(eq.result, SVGImage):
                self.layout.add_equation(w, own, prepend=not prepend)
            else:
                self.last_eqn_textview = w
        else:
            self.layout.add_equation(w, own, prepend=not prepend)

        if eq.label is not None and len(eq.label) > 0:
            w = self.create_var_textview(eq.label, eq.result)
            if w is not None:
                self.layout.add_variable(eq.label, w)

            if tree is None:
                tree = self.parser.parse(eq.equation)
            self.parser.set_var(eq.label, tree)

    # FIXME: to be implemented
    def process_async(self, eqn):
        """Parse and process an equation asynchronously."""

    def process(self):
        """Parse the equation entered and show the result"""

        s = unicode(self.text_entry.get_text())
        label = unicode(self.label_entry.get_text())
        _logger.debug('process(): parsing %r, label: %r', s, label)
        try:
            tree = self.parser.parse(s)
            res = self.parser.evaluate(tree)
        except ParserError, e:
            res = e
            self.showing_error = True

        if isinstance(res, str) and res.find('</svg>') > -1:
            res = SVGImage(data=res)

        _logger.debug('Result: %r', res)

        # Check whether assigning this label would cause recursion
        if not isinstance(res, ParserError) and len(label) > 0:
            lastpos = self.parser.get_var_used_ofs(label)
            if lastpos is not None:
                res = RuntimeError(
                    _('Can not assign label: will cause recursion'), lastpos)

# If parsing went ok, see if we have to replace the previous answer
# to get a (more) exact result
        if self.ans_inserted and not isinstance(res, ParserError) \
                and not isinstance(res, SVGImage):
            ansvar = self.format_insert_ans()
            pos = s.find(ansvar)
            if len(ansvar) > 6 and pos != -1:
                s2 = s.replace(ansvar, 'LastEqn')
                _logger.debug('process(): replacing previous answer %r: %r',
                              ansvar, s2)
                tree = self.parser.parse(s2)
                res = self.parser.evaluate(tree)

        eqn = Equation(label,
                       s,
                       res,
                       self.color,
                       self.get_owner_id(),
                       ml=self.ml)

        if isinstance(res, ParserError):
            self.set_error_equation(eqn)
        else:
            self.add_equation(eqn, drawlasteq=True, tree=tree)
            self.send_message("add_eq", value=str(eqn))

            self.parser.set_var('Ans', eqn.result)

            # Setting LastEqn to the parse tree would certainly be faster,
            # however, it introduces recursion problems
            self.parser.set_var('LastEqn', eqn.result)

            self.showing_error = False
            self.ans_inserted = False
            self.text_entry.set_text(u'')
            self.label_entry.set_text(u'')

        return res is not None