PyBlassReports - Report framework

About: A multiplatform framework for report creation, printing, export in PDF, export in SLK, export in XLS, export in XLSX, export RTF, export in HTM and other file formats, print preview for the report, and direct export without visualisation of the report. Is writen in Python. It uses: python 2.6, GTK+ Runtime, pygtk, cairo, pango, pangocairo, pyexcelerator (only for versions: 0.1, 0.2, 0.3 and 0.4) and PIL (only for version 0.9), and now has support for Tkinter interface.
For the SVG printing (from Firefox) it uses the JSPrintSetup addon ( available at
No installation needed.
Tested on Linux x86/x64 and Windows 2000/XP/Vista.
Version 1.6 released:
- ################# - Tkinter:
- DONE: Modified the report plot axis label position;
- DONE: Added support for window reparenting and a tabbed frame (like the GTK sNotebook widget);
- DONE: Export report in EPS file format with multipage, done adding a flag in Tk_ReportPreview class, multiple, and if it's true it draws all pages on one canvas;
- ################# - OverAll:
- DONE: Added the use of environment variable LOGNAME for newer linux systems;
- DONE: Modified exception handling;
- DONE: Fixed some report bugs;
- DONE: Modified the class RepObject;
- DONE: Modified the report example help __helpGtkTk__;

Version 1.5 released:
- ################# - PyGTK:
- DONE: Modified the PyBlassReports icon;
- DONE: Created and implemented the RTF color conversion function;
- DONE: Renamed all classes for PyGTK with gtk prefix;
- ################# - Tkinter:
- DONE: Constrants: %printpage%, %printpagefrom%, %printdate%, %printdatetime%;
- DONE: Image resize with PIL Image.resize;
- DONE: Export to PostScript multipage file that can be printed;
- DONE: Calculate date and time in XLSX;
- DONE: Export to other file formats;
- DONE: Wrapping text on vertical with calculation for rows height and rows on page
- DONE: Implement export to rtf;
- DONE: Calculate 16Bits color number for RTF;
- DONE: Print to printer - bug in the Tkinter Canvas postscript function - on evince can see the drawing but on the printer prints outside the margins -> no paper printed: Resolved: pageanchor = "sw", pagex = 0, pagey = 0 -> Not a BUG;
- DONE: Send EPS to printer under WIN32, need to install Ghostscript gswin32c.exe, and add it to PATH;
- DONE: Removed PIL requirement (restrict to only GIF image support, and write GIF resize module from scatch);
- DONE: Renamed all classes with tk prefix;
- DONE: Added plot class tkReportPlot to Tkinter report (only preview, print and postscript);
- DONE: Added barcode classes tkBarcodeEAN13 and tkBarcodeCODEBAR128 to Tkinter report (only preview, print and postscript);
- DONE: Small modifications on tkReportPlot and on xlsx export;
- DONE: Bound the mouse wheel to the yview_scroll action for the Tkinter Canvas;
- DONE: Recursive rows error on large data in cell (example: len(str)>=200);
- ################# - OverAll:
- DONE: Made some classes only once: Excel_Time, ExcelX_Files, ExcelX_CELL, RichTF_BOF, RichTF_EOF, RichTF_PAGE;
- DONE: Modified pygtk and tkinter version to use same report model and messure, differs in initialization;
- DONE: Recursive rows rectangle is now obj.new_subreport_dimension(startx, starty, widht, height);
- DONE: Make same model for the time, pages custom strings that are replaced by values;
- DONE: Made just one function to calculate the rows calculate_subreport_rows;
- DONE: Made just one function to create the SLK report data stream;
- DONE: Make tkinter version show only one page at the time;
- DONE: Make same classes/functions once (example RTF and XLSX);
- DONE: Export XHTML if "obj_imag" is undefined, results no image error in firefox;

Version 1.0 released:
- DONE: Modified the ReportPlot class (all);
- DONE: Added in the ReportPlot class label support for each lines, XY custom labels, grid lines, option to show or not to show the points coordinates;
- DONE: Added 3 classes to create a PNG image (drawPlotImage, drawCodeEan13, drawCodeBar128) and save it to the 'reports' folder;
- DONE: Integrated the 3 new classes (drawPlotImage, drawCodeEan13, drawCodeBar128) in the ReportPreview, ReportCell and SubreportRowCell class export_html and export_rtf functions to create the documents and after delete the PNG images;
- DONE: Added in the RTF and HTML export document the plot, ean13 and codebar128 images;
- DONE: Added export in Gnumeric xml spreadsheet format;
- DONE: Modified the Excel_CELL class and ReportPreview.export_xls function;
- DONE: Added support for PNG image width and height size;
- DONE: Added support for custom size paper: paper_name = "2480x3508", paper_orientation = "customxportrait";
- DONE: Implement export_xhtml, an xHTML + SVG + JS;
- DONE: Add to export_xhtml text left/center/right alingment;
- DONE: Modified the XLS style, and removed the images from the excelfor now;
- DONE: Added support for XHTML Printing with jsPrintSetup if it's installed in Firefox;
- DONE: Added class Fonts to create same fonts string name. Usage ex.: Fonts().arial();
- DONE: On Windows OS it opens the report in a new window, until the gtk_plug and gtk_socket is resolved on this platform;
- DONE: Changed Gnumeric gnm:Cols="16384" gnm:Rows="1048576";
- DONE: Added option to export in XLSX File Format;
- DONE: Modified class Fonts, added dicts for font names and styles;
- DONE: Modified imports and reports;
- DONE: Modified export in XLSX, image to PNG;
- DONE: Modified export in XLS/XLW, no image export;
- DONE: PIL is optional;

Version 0.9 released:
- DONE: Removed gtk.HRuler and gtk.VRuler;
- DONE: Modified the ReportPreview class into a gtk.VBox that is returned and contains all the data;
- DONE: Now you have to insert the ReportPreview = gtk.VBox into a container (example: gtk.Window, gtk.Notebook);
- DONE: Removed close_all, window, notebook from the ReportPreview needed varibles;
- DONE: Modified the painting algorithm, no more errors on having multiple report instances one over another;
- DONE: Added the cursor position on X, Y on a gtk.Label on top of the gtk.DrawingArea;
- DONE: Modified the example;
- DONE: Added ReportHeaderCell (it is ListaReportCell but renamed it);
- DONE: Removed ListaReportCell;
- DONE: ReportFooterCell (it calculates the possition on Y by setting the 0 origin on the Y end of the SubreportTblDim);
- DONE: Connected the gtk.VBox instance for the 'destroy' signal on the self.close_window function;
- DONE: Changed name for ListaPaperType into ReportPaperType;
- DONE: Changed name for ListaPaperOrientation into ReportPaperOrientation;
- DONE: Changed name for ListaReportLine into ReportLine;
- DONE: Changed name for ListaReportImages into ReportImage;
- DONE: Added the condensed font format;
- DONE: Modified the example;
- DONE: Changed in class ReportPreview the function self.close_window to self.destory_vbox, when the ReportPreview GtkVBox is destroyed the container (gtk.Container) that is not destroyed, you have to connect the ReportPreview GtkVBox on the 'destroy' signal and call that ReportPreview.destory_vbox() function;
- DONE: Added support for EAN13 and CodeBar128 barcodes in class and list with name 'ReportHeaderCell' and class 'SubreportTblRow', only on screen, printer and PDF, with types 'ean13' and 'codebar128';
- DONE: Changed the cursor position on a gtk.Tooltip on mouse click left / once;
- DONE: Changed drawing lines for bar code into filled rectangles of width 1;
- DONE: Added new _Image_Exe icon;
- DONE: Added new ComboBox for the action options;
- DONE: Added new Button to execute the action;
- DONE: Added another function for the combobox values on the execute button;
- DONE: Added new message when no option is selected;
- DONE: Removed the actions buttons;
- DONE: Added support for simple plot in class and list with name 'ReportHeaderCell' and class 'SubreportTblRow', only on screen, printer and PDF, with type 'plot', it is a dictionary with the keys:
- f_size - the font size (int);
- step - the axes step of values (int);
- plot - a dictionary with tuples of values for X and Y.
- DONE: Resolved some bugs in the bar codes fonts for the cairo.Context;
- DONE: Resolved partialy a bug in MyXlsTime, problem with the calculation of timediffer for the hour:minute:second format;
- DONE: Added new classes: ReportThread, ReportSocket and ShowReport;
- DONE: Implemented threading, sockets and plugs;
- DONE: Added a gtk.ProgressBar until the gtk.Plug is plugged in the gtk.Socket;
- DONE: Added a gtk.Button to cancel the ProgressBar and the thread;
- DONE: Bug resolved in the ReportPlot class on drawing negative values, origin on X calculated wrong;
- DONE: Bug resolved on RTF export '.0' decimal on cell dimension and origin;
- DONE: Implemented in export to RTF the text color, cell background color and border color;

Version 0.8 released:
- DONE: Added default export forder = Desktop;
- DONE: Modified MyXlsTime timeformat check, and the SymLK_CELL and Excel_CELL for date and time;
- DONE: Made the RepObject to import and create the empty lists;
- DONE: Changed class name WindowPreview to ReportPreview;
- DONE: Added and integrated an error_list and error message if error_list is not empty;
- DONE: Added foreground and background colors (html colors) in preview, print and pdf, htm;
- DONE: Added border color (html colors) in preview, print and pdf, htm;

Version 0.7 released:
- DONE: Made the .html export;
- DONE: Added new classes for a Report recursive row with autocalculation;
- DONE: Modified the draw, print and export functions;
- DONE: Removed: TblCellMultiple, TxtPgNumber;
- DONE: Removed from TblCellSimple: value for y (only used for export in .slk and .xls) = row number;
- DONE: Added to TblCellSimple: value for x (only used for export in .slk and .xls) = column number;
- DONE: Added to TblCellSimple: string variables:
- %date% - for date YYYY-mm-dd;
- %time% - for time HH:MM:SS;
- %datetime% - for datetime YYYY-mm-dd HH:MM:SS;
- %currentpage% - for current page number;
- %totalpages% - for total pages number;
- DONE: Added direct export in pdf, slk, xls, rtf and htm for applications without a screen output (requires gtk):
- "screen", "pdf", "slk", "xls", "rtf", "htm".

Version 0.6j released:
- TODO: Export to SLK, XLS, RTF (line color, font color and more styles);
- DONE: Make .xls export type datetime;
- DONE: Make more datetime formats support for MyXlsTime;
- DONE: Made .slk export type datetime;
- PROB: gtk.Button image is enabled or disabled by the global theme;

Version 0.6i released:
- TODO: Export to SLK, XLS, RTF (line color, font color and style);
- DONE: Focus on the new added tab;
- DONE: Export in RTF alignment in cell;
- DONE: gtk.Notebook autoscroll pages;
- DONE: Export in XLS, SLK type if isinstance(value, decimal.Decimal);
- DONE: Added Tab Title and Preview Window Title;
- DONE: Repaired a few bugs on RTF export;
- DONE: Added a 'Successfully finished saving the report.' MessageDialog;
- DONE: Changed the position/size calculation algorithm - more simple;
- DONE: Added more examples and changed the reporting template;
- DONE: Modified help_me() and inserted the help_me() function output into a gtk.Window;
- DONE: Added some shortcuts (Alt+P print, Alt+D export in pdf, Alt+K export in slk, Alt+X export in xls, Alt+R export in rtf, Alt+A about dialog);
- DONE: Removed TxtCellSimple and TxtCellMultiple;
- DONE: Added in TblCellSimple, TblCellMultiple and TxtPgNumber the variable for the border size (= 0 -> no border & > 0 -> with border of value 0.01 and bigger);
- DONE: Added gtk.VRuler and gtk.HRuler;
- DONE: Label with pointer position from the gtk.DrawingArea, on mouse left 1 click;
- DONE: Added a gtk.ProgressBar for report export operations;
- DONE: Changed the TblCellMultiple algorithm again (draw, print, export PDF, SLK and RTF);
- DONE: Added Pixbuf Icon Images and modified the HBox with buttons and selectors;
- DONE: Added Export in SLK (Symbolic Link - a type of spreadsheet)
- DONE: Added 4 standard fonts (Arial, Sans, Verdana and Helvetica)
- DONE: Remake the Export to XLS (Workbook v4.0)

Version 0.5 released:
- Removed export in .xls and the need of pyExcelerator;
- Added export in .xlw with no need for other modules;
- pyExcelerator is needed only for versions: 0.1, 0.2, 0.3 and 0.4.

Version 0.4 released:
- Resolved bug - png images not scaling on report zoom in / out;
- Changes in the drawing function.

Version 0.3 released:
- Suport for png images in preview, print, export pdf and export rtf, not for export in xls;
- Minor bugfixes.

Version 0.2 released:
- Support for emded in gtk.Notebook or in it's own window;
- Made some changes on the PreviewWindow class from the framework;
- Made a new example (please run the test file from the archive);
- Added a help_me function wich print's on the console the help or just read it from the README.txt;
- Made available the source code for the engine;
- Other minor changes.













Needed instalation packages:
GTK+ Runtime
Python 2.6
PyGobject for python2.6
PyCairo for python2.6
PyGtk for python2.6
PySqlite3 (for the sqlite test database example)
pyExcelerator (needed for the excel export only in versions: 0.1, 0.2, 0.3 and 0.4, in the other versions the library is my own).
PIL for version 0.9

Read license file.
Read copying file.
Read authors file.
#!/usr/bin/env python

# PyBlassReports Report Example File:
    import pyblassreports as rep
except Exception as e:

class ReportExample():
    """ Class example for a report """
    def __init__(self, guitype, data, imagsdir=""):
       #----------------------------------------------Begin creating title and lists-----------------------
        self.title = "TestingReport"
        self.guitype = guitype
        self.imagsdir = imagsdir
        # Create the lists = rep.RepObject() # this is actually pyblassreports.RepObject
        self.report_paper_size        =
        self.report_paper_type        =
        self.report_paper_orientation =
        self.report_line              =
        self.report_image             =
        self.report_header_cell       =
        self.report_footer_cell       =
        self.subreport_tbl_dim        =
        self.subreport_tbl_row        =
        #----------------------------------------------End creating title and lists-------------------------

        #----------------------------------------------Begin creating page formating------------------------
        # Set the Page Name and Orientation
        self.report_paper_size.extend([297, 210])
        #paper_size = gtk_calc_paper_size(("a4", "landscape") # only for pygtk guitype
        #print paper_size[0]/297.00, paper_size[1]/210.00
        #----------------------------------------------End creating page formating--------------------------

        #----------------------------------------------Begin creating fonts---------------------------------
        # Initialize class AllFonts
        self.fonts = rep.AllFonts()
        self.f = self.fonts.list(self.guitype)
        self.s =
        #----------------------------------------------End creating fonts----------------------------------- = None           # border style

        self.plotdata = None     # plot data

        self.rf = None           # font style
        self.rfl = None          # font style left
        self.rfc = None          # font style center
        self.rfr = None          # font style right

        self.rdata = eval(data)  # report data
        self.rd = None          # subreport dimensions

        return None

    def runrep(self):
        """ Transform string data to python types """
        #----------------------------------------------Begin inserting data---------------------------------
        # Insert an GIF/PNG image
        if self.guitype == "pygtk":
            self.report_image.append((self.imagsdir+"image.png", 5, 5, 10, 15))
            self.report_image.append((self.imagsdir+"image.gif", 5, 5, 10, 15))

        # Cell style: border & contents =, "#000000")
        self.rf =['sans'], 12, self.s['bold'], self.s['italic'], self.s['normal'],
                                        "#FFFFFF", "#FF55FF", "center")

        # Draw the Title
        self.report_header_cell.append(("REPORT EXAMPLE", 138, 10, 60, 5, 0, 0, self.rf,, "str"))

        # Draw Bar Codes
        self.rf =['sans'], 6, self.s['bold'], self.s['italic'], self.s['normal'],
                                   "#000000", "#FFFFFF", "center")
        self.report_header_cell.append(("9781550411980", 160, 20, 50, 25, 0, 0, self.rf,, "ean13"))
        self.report_header_cell.append(("PyBlassReports", 220, 35, 70, 25, 0, 0, self.rf,, "codebar128"))

        self.plotdata = {
            "title": "gtkPlot",
            "step": 100,
            "axes": ("Axa X" , "Axa Y"),
            "coords": "no",
            "plot": {
                    "red": [('red line', 1),
                            (12,  56), (20,  94), (33,  98), ( 45, 120),
                            (61, 180), (75, 160), (98, 223), (212, 256)
                    "blue": [('blue line', 1),
                            (50, 73), (297, 73), (197, 173)
                    "green": [('green line', 1),
                            (-50, -73), (297, 73)
                    "brown": [('brown line', 1),
                            (-55, -173), (-297, -73)
            } =, "black")
        self.rf =['verdana'], 7, self.s['normal'], self.s['normal'], self.s['normal'],
                                              "blue", "grey", "center")
        self. report_header_cell.append((self.plotdata, 30, 15, 70, 50, 0, 0, self.rf,, "plot")) =, "#000000")
        self.rfl =['sans'], 7, self.s['bold'], self.s['italic'], self.s['normal'],
                                              "#000000", "#669933", "left")
        self.rfc =['sans'], 7, self.s['bold'], self.s['italic'], self.s['normal'],
                                              "#000000", "#669933", "center")
        self.rfr =['sans'], 7, self.s['bold'], self.s['italic'], self.s['normal'],
                                              "#000000", "#669933", "right")

        for i in range(9):
            self.report_header_cell.append(("Column Name", 5+i*32, 70, 32, 7, 0, 0, self.rfl,, "str"))

        self.rd =, 77, 297-10, 210-77-15)
        self.rfl =['sans'], 7, self.s['normal'], self.s['normal'], self.s['normal'],
                                              "#000000", "#FFFFFF", "left")
        self.rfc =['sans'], 7, self.s['normal'], self.s['normal'], self.s['normal'],
                                              "#000000", "#FFFFFF", "center")
        self.rfr =['sans'], 7, self.s['normal'], self.s['normal'], self.s['normal'],
                                              "#000000", "#FFFFFF", "right")

        #bs1 = report.new_border_style(0.5, "#E32828")
        #report_header_cell.append((" ", 5, 77, 297-10, 210-77-15, 0, 0, rf, bs1, "str"))

        sumcol5 = 0
        sumcol6 = 0
        for i in range(300):
            sumcol5 += self.rdata["col5"]
            sumcol6 += self.rdata["col6"]
                        (self.rdata["col0"]+str(i),   32, 5, 0, 0, self.rfl,,   "str"),
                        (self.rdata["col1"],          32, 5, 0, 0, self.rfl,,   "str"),
                        (self.rdata["col2"],          32, 5, 0, 0, self.rfc,,   "str"),
                        (self.rdata["col3"],          32, 5, 0, 0, self.rfr,,   "str"),
                        (self.rdata["col4"],          32, 5, 0, 0, self.rfl,,   "str"),
                        (self.rdata["col5"],          32, 5, 0, 0, self.rfl,,   "int"),
                        ("%.4f" % self.rdata["col6"], 32, 5, 0, 0, self.rfc,,   "float"),
                        (self.rdata["col7"],          32, 5, 0, 0, self.rfr,,   "time"),
                        (self.rdata["col8"],          32, 5, 0, 0, self.rfc,,   "time")
        # Totals
        self.rfl =['sans'], 7, self.s['bold'], self.s['italic'], self.s['normal'],
                                              "#000000", "#FFFFFF", "left")
        self.rfc =['sans'], 7, self.s['bold'], self.s['italic'], self.s['normal'],
                                              "#000000", "#FFFFFF", "center")
        self.rfr =['sans'], 7, self.s['bold'], self.s['italic'], self.s['normal'],
                                              "#000000", "#FFFFFF", "right") =, "#FFFFFF")
                        ("Total: ",    32, 5, 0, 0, self.rfl,,   "str"),
                        (" ",          32, 5, 0, 0, self.rfl,,   "str"),
                        (" ",          32, 5, 0, 0, self.rfc,,   "str"),
                        (" ",          32, 5, 0, 0, self.rfr,,   "str"),
                        (" ",          32, 5, 0, 0, self.rfl,,   "str"),
                        (sumcol5,      32, 5, 0, 0, self.rfl,,   "int"),
                        ("%.4f" % sumcol6,      32, 5, 0, 0, self.rfc,,   "float"),
                        (" ",          32, 5, 0, 0, self.rfr,,   "str"),
                        (" ",          32, 5, 0, 0, self.rfl,,   "str"),
        #----------------------------------------------End inserting data-----------------------------------

        # Draw a line
        self.report_line.append((5, 195, 292, 195,

        # Cell border style =, "#FFFFFF")

        # Draw the datetime
        self.rf =['sans'], 7, self.s['bold'], self.s['italic'], self.s['underline'],
                                             "#000000", "#FFFFFF", "left")
        self.report_footer_cell.append(("%printdatetime%", 5, 5, 40, 5, 0, 0, self.rf,, "str"))

        # Draw page number
        self.rf =['sans'], 7, self.s['bold'], self.s['italic'], self.s['underline'],
                                             "#000000", "#FFFFFF", "right")
        self.report_footer_cell.append(("%printpagefrom%", 250, 5, 40, 5, 0, 0, self.rf ,, "str"))

        #----------------------------------------------Begin creating the report list-----------------------,
                            self.report_paper_size, self.report_paper_type, self.report_paper_orientation,
                            self.report_line, self.report_image,
                            self.report_header_cell, self.report_footer_cell,
                            self.subreport_tbl_dim, self.subreport_tbl_row)
        #----------------------------------------------End creating the report list-------------------------


# Print the pyblassreports error_list if any
if len(rep.ERROR_LIST)>0:


Message board: