Esempio n. 1
0
    def filename(self):
        """
        The filename that this object should create

        Objects that don't create new files should simply return `None`.

        """
        r = self.renderer
        try:
            return r.files[self]
        except KeyError:
            pass

        filename = None
        override = None
        try:
            # Nothing in the plasTeX code base actually ever
            # sets a filenameoverride on a Node
            override = str(self.filenameoverride.encode('ascii','ignore')) if self.filenameoverride is not None else None
            if override:
                assert override is not None
                userdata = self.ownerDocument.userdata
                config = self.ownerDocument.config
                newFilename = Filenames(override,
                                        (config['files']['bad-chars'],
                                         config['files']['bad-chars-sub']),
                                         {'jobname': userdata.get('jobname','')},
                                        r.fileExtension)
                newFilename.forceExtension = True
                filename = r.files[self] = newFilename()

        except (AttributeError, ValueError) as e:
            if isinstance( e, ValueError ):
                log.exception( "Failed to generate filename given override %s", override )

            if not hasattr(self, 'config'):
                return

            level = getattr(self, 'splitlevel', self.config['files']['split-level'])

            # If our level doesn't invoke a split, don't return a filename
            if self.level > level:
                return

            # Populate vars of filename generator
            # and call the generator to get the filename.
            # FIXME: Eww, not thread safe. Not really even re-entrant.
            # Closely coupled to the implementation of `id`
            ns = r.newFilename.vars
            if hasattr(self, 'id') and getattr(self, '@hasgenid', None) is None:
                ns['id'] = self.id
            if hasattr(self, 'title'):
                if hasattr(self.title, 'textContent'):
                    ns['title'] = self.title.textContent
                elif isinstance(self.title, string_types):
                    ns['title'] = self.title

            r.files[self] = filename = r.newFilename()

        return filename
Esempio n. 2
0
    def filename(self):
        """
        The filename that this object should create

        Objects that don't create new files should simply return `None`.

        """
        r = Node.renderer

        try:
            return r.files[self]
        except (KeyError, TypeError):
            pass

        filename = None

        try:
            override = str(self.filenameoverride)
            if override:
                userdata = self.ownerDocument.userdata
                config = self.ownerDocument.config
                newFilename = Filenames(
                    override, (config['files']['bad-chars'],
                               config['files']['bad-chars-sub']),
                    {'jobname': userdata.get('jobname', '')}, r.fileExtension)
                filename = r.files[self] = newFilename()

        except AttributeError as msg:
            if not hasattr(self, 'config'):
                return

            level = getattr(self, 'splitlevel',
                            self.config['files']['split-level'])

            # If our level doesn't invoke a split, don't return a filename
            if self.level > level:
                return

            # Populate vars of filename generator
            # and call the generator to get the filename.
            ns = r.newFilename.variables
            if hasattr(self,
                       'id') and getattr(self, '@hasgenid', None) is None:
                ns['id'] = self.id
            if hasattr(self, 'title'):
                if hasattr(self.title, 'textContent'):
                    ns['title'] = self.title.textContent
                elif isinstance(self.title, str):
                    ns['title'] = self.title
            r.files[self] = filename = r.newFilename()


#       print type(self), filename

        return filename
Esempio n. 3
0
    def __init__(self, document):
        self.config = document.config
        self.ownerDocument = document

        # Images that are simply copied from the source directory
        self.staticimages = ordereddict()

        # Filename generator
        self.newFilename = Filenames(
            self.config['images'].get('filenames', raw=True),
            vars={'jobname': document.userdata.get('jobname', '')},
            extension=self.fileExtension,
            invalid={})
Esempio n. 4
0
    def __init__(self, document, imageTypes=None):
        self.config = document.config
        self.ownerDocument = document

        if imageTypes is None:
            self.imageTypes = [self.fileExtension]
        else:
            self.imageTypes = imageTypes[:]

        # Dictionary that makes sure each image is only generated once.
        # The key is the LaTeX source and the value is the image instance.
        self._cache = {}
        usednames = {}
        # JAM: FIXME: This writes into some arbitrary directory that may or
        # may not be related to the document we are processing. It at least
        # needs to take document name/path into consideration (see below on
        # graphicspath)
        self._filecache = os.path.abspath(
            os.path.join('.cache', self.__class__.__name__ + '.images'))

        if self.config['images']['cache']:
            usednames = self._read_cache()

        # List of images in the order that they appear in the LaTeX file
        self.images = ordereddict()

        # Images that are simply copied from the source directory
        self.staticimages = ordereddict()

        # Filename generator
        self.newFilename = Filenames(
            self.config['images'].get('filenames', raw=True),
            vars={'jobname': document.userdata.get('jobname', '')},
            extension=self.fileExtension,
            invalid=usednames)

        # Start the document with a preamble
        self.source = StringIO()
        self.source.write('\\batchmode\n')
        self.writePreamble(document)
        self.source.write('\\begin{document}\n')

        #We inject \graphicspath here because this processing occurs in some temp space but the image urls
        #are relative to the original working directory.
        #Documentation suggests that we could just set the TEXINPUTS environment variable but it does not work
        self.source.write('\\graphicspath{{%s/}}\n' %
                          (self.ownerDocument.userdata['working-dir']))

        # Set up additional options
        self._configOptions = self.formatConfigOptions(self.config['images'])
Esempio n. 5
0
    def __init__(self, document, imageTypes=None):
        self.config = document.config
        self.ownerDocument = document

        if imageTypes is None:
            self.imageTypes = [self.fileExtension]
        else:
            self.imageTypes = imageTypes[:]

        # Dictionary that makes sure each image is only generated once.
        # The key is the LaTeX source and the value is the image instance.
        self._cache = {}
        usednames = {}
        self._filecache = os.path.abspath(
            os.path.join('.cache', self.__class__.__name__ + '.images'))
        if self.config['images']['cache'] and os.path.isfile(self._filecache):
            try:
                self._cache = pickle.load(open(self._filecache, 'r'))
                for key, value in self._cache.items():
                    if not os.path.isfile(value.filename):
                        del self._cache[key]
                        continue
                    usednames[value.filename] = None
            except ImportError:
                os.remove(self._filecache)

        # List of images in the order that they appear in the LaTeX file
        self.images = ordereddict()

        # Images that are simply copied from the source directory
        self.staticimages = ordereddict()

        # Filename generator
        self.newFilename = Filenames(
            self.config['images'].get('filenames', raw=True),
            vars={'jobname': document.userdata.get('jobname', '')},
            extension=self.fileExtension,
            invalid=usednames)

        # Start the document with a preamble
        self.source = StringIO()
        self.source.write('\\scrollmode\n')
        self.writePreamble(document)
        self.source.write('\\begin{document}\n')

        # Set up additional options
        self._configOptions = self.formatConfigOptions(self.config['images'])
Esempio n. 6
0
    def __init__(self, document):
        self.config = document.config
        self.ownerDocument = document

        # Cache of already seen images
        self.staticimages = {}

        # Filename generator

        # Python 2 compatibility: the second keyword argument for the Filenames
        # class changed name from vars to variables in Python 3 version.  When
        # Python 2 compatibility is dropped, change the following command to
        # self.newFilename = Filenames(self.config['images'].get('filenames', raw=True),
        #                              variables={'jobname': document.userdata.get('jobname', '')},
        #                              extension=self.fileExtension, invalid={})
        self.newFilename = Filenames(
            self.config['images'].get('filenames', raw=True),
            None, {'jobname': document.userdata.get('jobname', '')},
            extension=self.fileExtension,
            invalid={})
Esempio n. 7
0
    def render(self, document, postProcess=None):
        """
        Invoke the rendering process

        This method invokes the rendering process as well as handling
        the setup and shutdown of image processing.

        Required Arguments:
        document -- the document object to render
        postProcess -- a function that will be called with the content of

        """
        config = document.config

        # If there are no keys, print a warning.
        # This is most likely a problem.
        if not list(self.keys()):
            log.warning('There are no keys in the renderer.  ' +
                        'All objects will use the default rendering method.')

        # Mix in required methods and members
        mixin(Node, type(self).renderableClass)
        Node.renderer = self

        # Create a filename generator
        self.newFilename = Filenames(config['files'].get('filename', raw=True),
                                     (config['files']['bad-chars'],
                                      config['files']['bad-chars-sub']),
                                     {'jobname':document.userdata.get('jobname', '')}, self.fileExtension)

        self.cacheFilenames(document)

        # Instantiate appropriate imager
        names = [x for x in config['images']['imager'].split() if x]
        for name in names:
            if name == 'none':
                break
            elif name == 'dvipng':
                from plasTeX.Imagers.dvipng import Imager
            elif name == 'dvi2bitmap':
                from plasTeX.Imagers.dvi2bitmap  import Imager
            elif name == 'pdftoppm':
                from plasTeX.Imagers.pdftoppm  import Imager
            elif name == 'gspdfpng':
                from plasTeX.Imagers.gspdfpng  import Imager
            elif name == 'gsdvipng':
                from plasTeX.Imagers.gsdvipng  import Imager
            elif name == 'OSXCoreGraphics':
                from plasTeX.Imagers.OSXCoreGraphics  import Imager
            else:
                log.warning("Invalid imager '%s'" % name)
                continue

            self.imager = Imager(document, self.imageTypes)

            # Make sure that this imager works on this machine
            if self.imager.verify():
                log.info('Using the imager "%s".' % name)
                break

        # Still no imager? Just use the default.
        if self.imager is None:
            if 'none' not in names:
                log.warning('Could not find a valid imager in the list: %s.  The default imager will be used.' % ', '.join(names))
            from plasTeX.Imagers import Imager
            self.imager = Imager(document, self.imageTypes)

        if self.imageTypes and self.imager.fileExtension not in self.imageTypes:
            self.imager.fileExtension = self.imageTypes[0]
        if self.imageAttrs and not self.imager.imageAttrs:
            self.imager.imageAttrs = self.imageAttrs
        if self.imageUnits and not self.imager.imageUnits:
            self.imager.imageUnits = self.imageUnits

        # Instantiate appropriate vector imager
        names = [x for x in config['images']['vector-imager'].split() if x]
        for name in names:
            if name == 'none':
                break
            elif name == 'dvisvgm':
                from plasTeX.Imagers.dvisvgm import Imager as VectorImager
            elif name == 'pdf2svg':
                from plasTeX.Imagers.pdf2svg import Imager as VectorImager
            else:
                log.warning("Invalid imager '%s'" % name)
                continue

            self.vectorImager = VectorImager(document, self.vectorImageTypes)

            # Make sure that this imager works on this machine
            if self.vectorImager.verify():
                log.info('Using the vector imager "%s".' % name)
                break

            self.vectorImager = None

        # Still no vector imager? Just use the default.
        if self.vectorImager is None:
            if 'none' not in names:
                log.warning('Could not find a valid vector imager in the list: %s.  The default vector imager will be used.' % ', '.join(names))
            from plasTeX.Imagers import VectorImager
            self.vectorImager = VectorImager(document, self.vectorImageTypes)

        if self.vectorImageTypes and \
           self.vectorImager.fileExtension not in self.vectorImageTypes:
            self.vectorImager.fileExtension = self.vectorImageTypes[0]
        if self.imageAttrs and not self.vectorImager.imageAttrs:
            self.vectorImager.imageAttrs = self.imageAttrs
        if self.imageUnits and not self.vectorImager.imageUnits:
            self.vectorImager.imageUnits = self.imageUnits

        # Invoke the rendering process
        if type(self).renderMethod:
            getattr(document, type(self).renderMethod)()
        else:
            str(document)

        # Finish rendering images
        self.imager.close()
        self.vectorImager.close()

        # Run any cleanup activities
        self.cleanup(document, list(self.files.values()), postProcess=postProcess)

        # Write out auxilliary information
        pauxname = os.path.join(document.userdata.get('working-dir','.'),
                                '%s.paux' % document.userdata.get('jobname',''))
        rname = config['general']['renderer']
        document.context.persist(pauxname, rname)

        # Remove mixins
        del Node.renderer
        unmix(Node, type(self).renderableClass)
Esempio n. 8
0
    def render(self, document, postProcess=None):
        """
        Invoke the rendering process

        This method invokes the rendering process as well as handling
        the setup and shutdown of image processing.

        Required Arguments:
        document -- the document object to render
        postProcess -- a function that will be called with the content of

        """
        config = document.config

        # If there are no keys, print a warning.
        # This is most likely a problem.
        if not bool(self):
            log.warning('There are no keys in the renderer.  ' +
                        'All objects will use the default rendering method.')

        document.renderer = self  # JAM: Make thread safe. See above

        # XXX JAM FIXME: Not thread safe because this manipulates
        # the Node class system wide
        # We can get very close to being thread safe by instead
        # operating on a zope proxy object that extends self.renderableClass
        # and takes care to wrap self.childNodes, but this
        # ultimately fails because some things like SectionUtils
        # are already mixed-in to the node and depend on things defined
        # by renderableClass (filename)...thus they can only be used
        # during the rendering process anyway, but they don't get to
        # work on the proxy object. Obviously that's a design flaw
        # to rectify.
        mixin(Node, self.renderableClass)
        try:

            # Create a filename generator
            self.newFilename = Filenames(
                config['files'].get('filename', raw=True),
                (config['files']['bad-chars'],
                 config['files']['bad-chars-sub']),
                {'jobname': document.userdata.get('jobname', '')},
                self.fileExtension)

            self.cacheFilenames(document)

            # Instantiate appropriate imager
            self.imager = _create_imager(config, document, DefaultImager,
                                         self.imageTypes, self.imageUnits,
                                         self.imageAttrs)

            # Instantiate appropriate vector imager
            self.vectorImager = _create_imager(config,
                                               document,
                                               DefaultVectorImager,
                                               self.vectorImageTypes,
                                               self.imageUnits,
                                               self.imageAttrs,
                                               kind='vector-imager')

            # Invoke the rendering process
            if self.renderMethod:
                getattr(document, self.renderMethod)()
            else:
                unicode(document)

            # Finish rendering images
            self.imager.close()
            self.vectorImager.close()

            # Run any cleanup activities
            self.cleanup(document,
                         list(self.files.values()),
                         postProcess=postProcess)

            # Write out auxilliary information
            pauxname = os.path.join(
                document.userdata.get('working-dir', '.'),
                '%s.paux' % document.userdata.get('jobname', ''))
            rname = config['general']['renderer']
            document.context.persist(pauxname, rname)
        finally:
            # Remove mixins
            unmix(Node, self.renderableClass)
            del document.renderer
Esempio n. 9
0
    def filename(self):
        """
        The filename that this object should create

        Objects that don't create new files should simply return `None`.

        """
        r = self.renderer
        try:
            return r.files[self]
        except KeyError:
            pass

        filename = None
        override = None
        try:
            # Nothing in the plasTeX code base actually ever
            # sets a filenameoverride on a Node
            override = str(self.filenameoverride.encode(
                'ascii',
                'ignore')) if self.filenameoverride is not None else None
            if override:
                assert override is not None
                userdata = self.ownerDocument.userdata
                config = self.ownerDocument.config
                newFilename = Filenames(
                    override, (config['files']['bad-chars'],
                               config['files']['bad-chars-sub']),
                    {'jobname': userdata.get('jobname', '')}, r.fileExtension)
                newFilename.forceExtension = True
                filename = r.files[self] = newFilename()

        except (AttributeError, ValueError) as e:
            if isinstance(e, ValueError):
                log.exception("Failed to generate filename given override %s",
                              override)

            if not hasattr(self, 'config'):
                return

            level = getattr(self, 'splitlevel',
                            self.config['files']['split-level'])

            # If our level doesn't invoke a split, don't return a filename
            if self.level > level:
                return

            # Populate vars of filename generator
            # and call the generator to get the filename.
            # FIXME: Eww, not thread safe. Not really even re-entrant.
            # Closely coupled to the implementation of `id`
            ns = r.newFilename.vars
            if hasattr(self,
                       'id') and getattr(self, '@hasgenid', None) is None:
                ns['id'] = self.id
            if hasattr(self, 'title'):
                if hasattr(self.title, 'textContent'):
                    ns['title'] = self.title.textContent
                elif isinstance(self.title, string_types):
                    ns['title'] = self.title

            r.files[self] = filename = r.newFilename()

        return filename