from __future__ import print_function from types import IntType, FloatType, LongType, StringTypes from copy import deepcopy from binascii import hexlify from Constants import * from Styles import * class UnhandledParamError( Exception ) : def __init__( self, param ) : Exception.__init__( self, "Don't know what to do with param %s" % param ) # red green blue StandardColours = Colours() StandardColours.append( Colour( 'Black', 0, 0, 0 ) ) StandardColours.append( Colour( 'Blue', 0, 0, 255 ) ) StandardColours.append( Colour( 'Turquoise', 0, 255, 255 ) ) StandardColours.append( Colour( 'Green', 0, 255, 0 ) ) StandardColours.append( Colour( 'Pink', 255, 0, 255 ) ) StandardColours.append( Colour( 'Red', 255, 0, 0 ) ) StandardColours.append( Colour( 'Yellow', 255, 255, 0 ) ) StandardColours.append( Colour( 'White', 255, 255, 255 ) ) StandardColours.append( Colour( 'Blue Dark', 0, 0, 128 ) ) StandardColours.append( Colour( 'Teal', 0, 128, 128 ) ) StandardColours.append( Colour( 'Green Dark', 0, 128, 0 ) ) StandardColours.append( Colour( 'Violet', 128, 0, 128 ) ) StandardColours.append( Colour( 'Red Dark', 128, 0, 0 ) ) StandardColours.append( Colour( 'Yellow Dark', 128, 128, 0 ) ) StandardColours.append( Colour( 'Grey Dark', 128, 128, 128 ) ) StandardColours.append( Colour( 'Grey', 192, 192, 192 ) ) StandardFonts = Fonts() StandardFonts.append( Font( 'Arial' , 'swiss' , 0, 2, '020b0604020202020204' ) ) StandardFonts.append( Font( 'Arial Black' , 'swiss' , 0, 2, '020b0a04020102020204' ) ) StandardFonts.append( Font( 'Arial Narrow' , 'swiss' , 0, 2, '020b0506020202030204' ) ) StandardFonts.append( Font( 'Bitstream Vera Sans Mono', 'modern', 0, 1, '020b0609030804020204' ) ) StandardFonts.append( Font( 'Bitstream Vera Sans' , 'swiss' , 0, 2, '020b0603030804020204' ) ) StandardFonts.append( Font( 'Bitstream Vera Serif' , 'roman' , 0, 2, '02060603050605020204' ) ) StandardFonts.append( Font( 'Book Antiqua' , 'roman' , 0, 2, '02040602050305030304' ) ) StandardFonts.append( Font( 'Bookman Old Style' , 'roman' , 0, 2, '02050604050505020204' ) ) StandardFonts.append( Font( 'Castellar' , 'roman' , 0, 2, '020a0402060406010301' ) ) StandardFonts.append( Font( 'Century Gothic' , 'swiss' , 0, 2, '020b0502020202020204' ) ) StandardFonts.append( Font( 'Comic Sans MS' , 'script', 0, 2, '030f0702030302020204' ) ) StandardFonts.append( Font( 'Courier New' , 'modern', 0, 1, '02070309020205020404' ) ) StandardFonts.append( Font( 'Franklin Gothic Medium' , 'swiss' , 0, 2, '020b0603020102020204' ) ) StandardFonts.append( Font( 'Garamond' , 'roman' , 0, 2, '02020404030301010803' ) ) StandardFonts.append( Font( 'Georgia' , 'roman' , 0, 2, '02040502050405020303' ) ) StandardFonts.append( Font( 'Haettenschweiler' , 'swiss' , 0, 2, '020b0706040902060204' ) ) StandardFonts.append( Font( 'Impact' , 'swiss' , 0, 2, '020b0806030902050204' ) ) StandardFonts.append( Font( 'Lucida Console' , 'modern', 0, 1, '020b0609040504020204' ) ) StandardFonts.append( Font( 'Lucida Sans Unicode' , 'swiss' , 0, 2, '020b0602030504020204' ) ) StandardFonts.append( Font( 'Microsoft Sans Serif' , 'swiss' , 0, 2, '020b0604020202020204' ) ) StandardFonts.append( Font( 'Monotype Corsiva' , 'script', 0, 2, '03010101010201010101' ) ) StandardFonts.append( Font( 'Palatino Linotype' , 'roman' , 0, 2, '02040502050505030304' ) ) StandardFonts.append( Font( 'Papyrus' , 'script', 0, 2, '03070502060502030205' ) ) StandardFonts.append( Font( 'Sylfaen' , 'roman' , 0, 2, '010a0502050306030303' ) ) StandardFonts.append( Font( 'Symbol' , 'roman' , 2, 2, '05050102010706020507' ) ) StandardFonts.append( Font( 'Tahoma' , 'swiss' , 0, 2, '020b0604030504040204' ) ) StandardFonts.append( Font( 'Times New Roman' , 'roman' , 0, 2, '02020603050405020304' ) ) StandardFonts.append( Font( 'Trebuchet MS' , 'swiss' , 0, 2, '020b0603020202020204' ) ) StandardFonts.append( Font( 'Verdana' , 'swiss' , 0, 2, '020b0604030504040204' ) ) StandardFonts.Castellar.SetAlternate( StandardFonts.Georgia ) """ Found the following definition at http://www.pbdr.com/vbtips/gen/convtwip.htm Twips are screen-independent units used to ensure that the placement and proportion of screen elements in your screen application are the same on all display systems. A twip is a unit of screen measurement equal to 1/20 of a printer's point. The conversion between twips and inches/centimeters/millimeters is as follows: There are approximately 1440 twips to a inch (the length of a screen item measuring one inch when printed). As there are 2.54 centimeters to 1 inch, then there are approximately 567 twips to a centimeter (the length of a screen item measuring one centimeter when printed). Or in millimeters, as there are 25.4 millimeters to 1 inch, therefore there are approximately 56.7 twips to a millimeter (the length of a screen item measuring one millimeter when printed).""" # Width default is 12240, Height default is 15840 StandardPaper = Papers() StandardPaper.append( Paper( 'LETTER' , 1, 'Letter 8 1/2 x 11 in' , 12240, 15840 ) ) StandardPaper.append( Paper( 'LETTERSMALL' , 2, 'Letter Small 8 1/2 x 11 in' , 12240, 15840 ) ) StandardPaper.append( Paper( 'TABLOID' , 3, 'Tabloid 11 x 17 in' , 15840, 24480 ) ) StandardPaper.append( Paper( 'LEDGER' , 4, 'Ledger 17 x 11 in' , 24480, 15840 ) ) StandardPaper.append( Paper( 'LEGAL' , 5, 'Legal 8 1/2 x 14 in' , 12240, 20160 ) ) StandardPaper.append( Paper( 'STATEMENT' , 6, 'Statement 5 1/2 x 8 1/2 in' , 7920, 12240 ) ) StandardPaper.append( Paper( 'EXECUTIVE' , 7, 'Executive 7 1/4 x 10 1/2 in' , 10440, 15120 ) ) StandardPaper.append( Paper( 'A3' , 8, 'A3 297 x 420 mm' , 16838, 23811 ) ) StandardPaper.append( Paper( 'A4' , 9, 'A4 210 x 297 mm' , 11907, 16838 ) ) StandardPaper.append( Paper( 'A4SMALL' , 10, 'A4 Small 210 x 297 mm' , 11907, 16838 ) ) StandardPaper.append( Paper( 'A5' , 11, 'A5 148 x 210 mm' , 8391, 11907 ) ) StandardPaper.append( Paper( 'B4' , 12, 'B4 (JIS) 250 x 354' , 14175, 20072 ) ) StandardPaper.append( Paper( 'B5' , 13, 'B5 (JIS) 182 x 257 mm' , 10319, 14572 ) ) StandardPaper.append( Paper( 'FOLIO' , 14, 'Folio 8 1/2 x 13 in' , 12240, 18720 ) ) StandardPaper.append( Paper( 'QUARTO' , 15, 'Quarto 215 x 275 mm' , 12191, 15593 ) ) StandardPaper.append( Paper( '10X14' , 16, '10x14 in' , 14400, 20160 ) ) StandardPaper.append( Paper( '11X17' , 17, '11x17 in' , 15840, 24480 ) ) StandardPaper.append( Paper( 'NOTE' , 18, 'Note 8 1/2 x 11 in' , 12240, 15840 ) ) StandardPaper.append( Paper( 'ENV_9' , 19, 'Envelope #9 3 7/8 x 8 7/8' , 5580, 12780 ) ) StandardPaper.append( Paper( 'ENV_10' , 20, 'Envelope #10 4 1/8 x 9 1/2' , 5940, 13680 ) ) StandardPaper.append( Paper( 'ENV_11' , 21, 'Envelope #11 4 1/2 x 10 3/8' , 6480, 14940 ) ) StandardPaper.append( Paper( 'ENV_12' , 22, 'Envelope #12 4 3/4 x 11' , 6840, 15840 ) ) StandardPaper.append( Paper( 'ENV_14' , 23, 'Envelope #14 5 x 11 1/2' , 7200, 16560 ) ) StandardPaper.append( Paper( 'CSHEET' , 24, 'C size sheet 18 x 24 in' , 29520, 34560 ) ) StandardPaper.append( Paper( 'DSHEET' , 25, 'D size sheet 22 x 34 in' , 31680, 48960 ) ) StandardPaper.append( Paper( 'ESHEET' , 26, 'E size sheet 34 x 44 in' , 48960, 63360 ) ) StandardPaper.append( Paper( 'ENV_DL' , 27, 'Envelope DL 110 x 220mm' , 6237, 12474 ) ) StandardPaper.append( Paper( 'ENV_C5' , 28, 'Envelope C5 162 x 229 mm' , 9185, 12984 ) ) StandardPaper.append( Paper( 'ENV_C3' , 29, 'Envelope C3 324 x 458 mm' , 18371, 25969 ) ) StandardPaper.append( Paper( 'ENV_C4' , 30, 'Envelope C4 229 x 324 mm' , 12984, 18371 ) ) StandardPaper.append( Paper( 'ENV_C6' , 31, 'Envelope C6 114 x 162 mm' , 6464, 9185 ) ) StandardPaper.append( Paper( 'ENV_C65' , 32, 'Envelope C65 114 x 229 mm' , 6464, 12984 ) ) StandardPaper.append( Paper( 'ENV_B4' , 33, 'Envelope B4 250 x 353 mm' , 14175, 20015 ) ) StandardPaper.append( Paper( 'ENV_B5' , 34, 'Envelope B5 176 x 250 mm' , 9979, 14175 ) ) StandardPaper.append( Paper( 'ENV_B6' , 35, 'Envelope B6 176 x 125 mm' , 9979, 7088 ) ) StandardPaper.append( Paper( 'ENV_ITALY' , 36, 'Envelope 110 x 230 mm' , 6237, 13041 ) ) StandardPaper.append( Paper( 'ENV_MONARCH' , 37, 'Envelope Monarch 3.875 x 7.5 in' , 5580, 10800 ) ) StandardPaper.append( Paper( 'ENV_PERSONAL' , 38, '6 3/4 Envelope 3 5/8 x 6 1/2 in' , 5220, 9360 ) ) StandardPaper.append( Paper( 'FANFOLD_US' , 39, 'US Std Fanfold 14 7/8 x 11 in' , 21420, 15840 ) ) StandardPaper.append( Paper( 'FANFOLD_STD_GERMAN' , 40, 'German Std Fanfold 8 1/2 x 12 in' , 12240, 17280 ) ) StandardPaper.append( Paper( 'FANFOLD_LGL_GERMAN' , 41, 'German Legal Fanfold 8 1/2 x 13 in' , 12240, 18720 ) ) # # Finally a StyleSheet in which all of this stuff is put together # class StyleSheet : def __init__( self, colours=None, fonts=None ) : self.Colours = colours or deepcopy( StandardColours ) self.Fonts = fonts or deepcopy( StandardFonts ) self.TextStyles = AttributedList() self.ParagraphStyles = AttributedList() class Section( list ) : NONE = 1 COLUMN = 2 PAGE = 3 EVEN = 4 ODD = 5 BREAK_TYPES = [ NONE, COLUMN, PAGE, EVEN, ODD ] def __init__( self, paper=None, margins=None, break_type=None, headery=None, footery=None, landscape=None, first_page_number=None ) : super( Section, self ).__init__() self.Paper = paper or StandardPaper.A4 self.SetMargins( margins ) self.Header = [] self.Footer = [] self.FirstHeader = [] self.FirstFooter = [] self.SetBreakType( break_type or self.NONE ) self.SetHeaderY( headery ) self.SetFooterY( footery ) self.SetLandscape( landscape ) self.SetFirstPageNumber( first_page_number ) def TwipsToRightMargin( self ) : return self.Paper.Width - ( self.Margins.Left + self.Margins.Right ) def SetMargins( self, value ) : self.Margins = value or MarginsPropertySet( top=1000, left=1200, bottom=1000, right=1200 ) self.Width = self.Paper.Width - ( self.Margins.Left + self.Margins.Right ) def SetBreakType( self, value ) : assert value in self.BREAK_TYPES self.BreakType = value return self def SetHeaderY( self, value ) : self.HeaderY = value return self def SetFooterY( self, value ) : self.FooterY = value return self def SetLandscape( self, value ) : self.Landscape = False if value : self.Landscape = True return self def SetFirstPageNumber( self, value ) : self.FirstPageNumber = value return self def MakeDefaultStyleSheet( ) : result = StyleSheet() NormalText = TextStyle( TextPropertySet( result.Fonts.Arial, 22 ) ) ps = ParagraphStyle( 'Normal', NormalText.Copy(), ParagraphPropertySet( space_before = 60, space_after = 60 ) ) result.ParagraphStyles.append( ps ) ps = ParagraphStyle( 'Normal Short', NormalText.Copy() ) result.ParagraphStyles.append( ps ) NormalText.TextPropertySet.SetSize( 32 ) ps = ParagraphStyle( 'Heading 1', NormalText.Copy(), ParagraphPropertySet( space_before = 240, space_after = 60 ) ) result.ParagraphStyles.append( ps ) NormalText.TextPropertySet.SetSize( 24 ).SetBold( True ) ps = ParagraphStyle( 'Heading 2', NormalText.Copy(), ParagraphPropertySet( space_before = 240, space_after = 60 ) ) result.ParagraphStyles.append( ps ) # Add some more in that are based on the normal template but that # have some indenting set that makes them suitable for doing numbered normal_numbered = result.ParagraphStyles.Normal.Copy() normal_numbered.SetName( 'Normal Numbered' ) normal_numbered.ParagraphPropertySet.SetFirstLineIndent( TabPropertySet.DEFAULT_WIDTH * -1 ) normal_numbered.ParagraphPropertySet.SetLeftIndent ( TabPropertySet.DEFAULT_WIDTH ) result.ParagraphStyles.append( normal_numbered ) normal_numbered2 = result.ParagraphStyles.Normal.Copy() normal_numbered2.SetName( 'Normal Numbered 2' ) normal_numbered2.ParagraphPropertySet.SetFirstLineIndent( TabPropertySet.DEFAULT_WIDTH * -1 ) normal_numbered2.ParagraphPropertySet.SetLeftIndent ( TabPropertySet.DEFAULT_WIDTH * 2 ) result.ParagraphStyles.append( normal_numbered2 ) ## LIST STYLES for idx, indent in [ (1, TabPS.DEFAULT_WIDTH ), (2, TabPS.DEFAULT_WIDTH * 2), (3, TabPS.DEFAULT_WIDTH * 3) ] : indent = TabPropertySet.DEFAULT_WIDTH ps = ParagraphStyle( 'List %s' % idx, TextStyle( TextPropertySet( result.Fonts.Arial, 22 ) ), ParagraphPropertySet( space_before = 60, space_after = 60, first_line_indent = -indent, left_indent = indent) ) result.ParagraphStyles.append( ps ) return result class TAB : pass class LINE : pass class RawCode : def __init__( self, data ) : self.Data = data PAGE_NUMBER = RawCode( r'{\field{\fldinst page}}' ) TOTAL_PAGES = RawCode( r'{\field{\fldinst numpages}}' ) SECTION_PAGES = RawCode( r'{\field{\fldinst sectionpages}}' ) ARIAL_BULLET = RawCode( r'{\f2\'95}' ) def _get_jpg_dimensions( fin ): """ converted from: http://dev.w3.org/cvsweb/Amaya/libjpeg/rdjpgcom.c?rev=1.2 """ M_SOF0 = chr( 0xC0 ) # /* Start Of Frame N */ M_SOF1 = chr( 0xC1 ) # /* N indicates which compression process */ M_SOF2 = chr( 0xC2 ) # /* Only SOF0-SOF2 are now in common use */ M_SOF3 = chr( 0xC3 ) # M_SOF5 = chr( 0xC5 ) # /* NB: codes C4 and CC are NOT SOF markers */ M_SOF6 = chr( 0xC6 ) # M_SOF7 = chr( 0xC7 ) # M_SOF9 = chr( 0xC9 ) # M_SOF10 = chr( 0xCA ) # M_SOF11 = chr( 0xCB ) # M_SOF13 = chr( 0xCD ) # M_SOF14 = chr( 0xCE ) # M_SOF15 = chr( 0xCF ) # M_SOI = chr( 0xD8 ) # /* Start Of Image (beginning of datastream) */ M_EOI = chr( 0xD9 ) # /* End Of Image (end of datastream) */ M_FF = chr( 0xFF ) MARKERS = [ M_SOF0, M_SOF1, M_SOF2, M_SOF3, M_SOF5, M_SOF6, M_SOF7, M_SOF9, M_SOF10,M_SOF11, M_SOF13, M_SOF14, M_SOF15 ] def get_length() : b1 = fin.read( 1 ) b2 = fin.read( 1 ) return (ord(b1) << 8) + ord(b2) def next_marker() : # markers come straight after an 0xFF so skip everything # up to the first 0xFF that we find while fin.read(1) != M_FF : pass # there can be more than one 0xFF as they can be used # for padding so we are now looking for the first byte # that isn't an 0xFF, this will be the marker while True : result = fin.read(1) if result != M_FF : return result raise Exception( 'Invalid JPEG' ) # BODY OF THE FUNCTION if not ((fin.read(1) == M_FF) and (fin.read(1) == M_SOI)) : raise Exception( 'Invalid Jpeg' ) while True : marker = next_marker() # the marker is always followed by two bytes representing the length of the data field length = get_length () if length < 2 : raise Exception( "Erroneous JPEG marker length" ) # if it is a compression process marker then it will contain the dimension of the image if marker in MARKERS : # the next byte is the data precision, just skip it fin.read(1) # bingo image_height = get_length() image_width = get_length() return image_width, image_height # just skip whatever data it contains fin.read( length - 2 ) raise Exception( 'Invalid JPEG, end of stream reached' ) _PNG_HEADER = '\x89\x50\x4e' def _get_png_dimensions( data ) : if data[0:3] != _PNG_HEADER : raise Exception( 'Invalid PNG image' ) width = (ord(data[18]) * 256) + (ord(data[19])) height = (ord(data[22]) * 256) + (ord(data[23])) return width, height def _get_emf_dimensions( fin ): import struct def get_DWORD(): return struct.unpack("