Abiword

index

Here we presents the integration of [The Birds Lake] into the abiword wordprocessor.

Abiword is a free, multiplatform wordprocessor. A complete integration of the birds lake into abiword will enable it in the future to have access to million of importation/exportation/isomorph filters !!! And be multiplatform the same time !!!

How do we do that ? In fact the code of the filters are not on the same machine than the wordprocessor. Abiword scan the internet like peer2peer apps for so called "Filters server", (This can be done on a dedicated thread, the server can be on the same machine). Once it got some servers it will contact them to get some informations about the server like its name, a logo, its filters trees. All the filters tree will be merged together...

Now we come back to abiword. Let's suppose that we had created highly semantic styles : TblTitle, TblChapter, TblSection and TblSubSection like in LaTeX. The following picture shows the Abiword manual structured with this styles. Click here to get this document. We have put a yellow background in the style to see them better, but what's really important is there name.



And now lets export it using the TheBirdsLake export plugin.


Once you've clicked ...

You have got a complex dialog, you select the filter on your left in the filters tree. And you will get a description of the filter on your right. Abiword communicates with the server using CORBA and by receiving xml files which describes authors, filters, server and so on ... We 've got a just in time strategy, for example we don't get a preview of filter until the user has clicked on it. We have also a cache system ...

Here we have only one filters server : Lioubovnik Python test, but you can have lot (but less than 32000 in the current implementation :-) ) You click on OK !! The server will launch a function to answer the filter what forms (called interface) he needs to be filled. The client will get them and will show them, here we have only one interface : SunBeach (tab).



The interfaces are also written in xml, the current example :

<?xml version="1.0"?>
<IGenInterface name="HTML_SunBeach" label="Sunbeach">
        <IGenFrame name="colors" label="Colors">
                <IGenInput name="titlesForegroundColor" label="Titles foreground" 
                        info="Choose the color that will be used for TblTitle, and TblSubSection and also 
                        for the menu section list bullet"
                        type="color" 
                        >ffff00</IGenInput>
                <IGenInput name="titlesBackgroundColor" 
                        label="Titles background" 
                        info="Choose the background color that will be used for TblTitle, and TblSubSection and also 
                        for the menu section list bullet"
                        type="color" 
                        >006565</IGenInput>
                <IGenInput name="menuBackgroundColor" 
                        label="Menu background" 
                        info="Choose the background color that will be used for the menu on the left"
                        type="color">ffffff</IGenInput>
        </IGenFrame>
        <IGenFrame name="chaptersSurfboards" 
                label="Chapters surfboard">
                <IGenInput name="display" 
                        type="boolean" label="Display ?"
                        info="Do you want to have a surfboard with the current chapter written on it"
                        >yes</IGenInput>
                <IGenInput name="ttfFont" type="selection" 
                        label="Which font ?"
                        info="Choose a font from those which are proposed"
                        items="TSCu_Comic;babelfish;ganymede;independ;electroh;betadance;edgewater;actionis"
                        >electroh</IGenInput>
                <IGenInput name="shading" 
                        type="boolean" label="Shading ?"
                        info="Do you want the text to be shaded ?"
                        >yes</IGenInput>
        </IGenFrame>
</IGenInterface>

Easy no ? We use LibIGen to render this interfaces. It supports GTK2 for now, but other toolkits could be used (I have started to work on a QT3 front-end). -> MULTIPLATFORM

The options you have chosen will be sent back to the server and used to apply the filter.

After all that you have a well selected and well customized document (the result is a directory, if you have called on file selection dialog 'out.tbl' you will get a 'out.tbl.dir' folder which contains the html, graphics, css, etc files ...

Click here to see the result of this filter online.

Writting a filter is very easy, since these can be written in python using LioubovnikPython (you can use other langages, you have just to write the Lioubovnik, the job of communication with the client is done in Lioubliou, the code of LioubovnikPython is less than 400 lines of C code !!!)

It is easy also because you write the class which handles with the miscellanceous inner xml of the Abiword1 format once and then reuse the code indefinitly. You just writte some CSS code, generates some graphics dynamically, javascript, PHP, etc ...

For example, here is the code of the SunBeach filter which creates a clone of michel.strasser.free.fr web site :

import emb
import sys
import os
import os.path
from Base.AbwReadAndExecute import Input
from Base.AbwReadAndExecute import PageBase_CS
from Base.AbwReadAndExecute import AbwHtmlReadAndExecute
import tarfile
import Image, ImageDraw, ImageFont

filter={}

def interfaces(portsDir, workingDir):
        filter["Filter"]=Filter(workingDir)
        filter["PortsDir"]=portsDir
        return ["Interfaces/HTML/TblIf-HTML_SunBeach.ign"]

def main(portsDir, workingDir, ig):
        print "Hello, special greetings from main func, yeah !!!\n"
        print "workin'Dir is" + workingDir
        print "portsDir is" + portsDir
        filter["Filter"].run(ig)

class Filter:
        def __init__(self, dir):
                self.input=Input(dir)
                pB=PageBase_CS(self.input)
                self.ab=AbwHtmlReadAndExecute(self.input, pB)

        def printDocStyleForChapter(self, docStyleFd, chapterId):
                toWrite="""
                #TblChapterBis__""" + chapterId + """ {
                        background-image: url(""" + chapterId + """.png);
                        display: block;
                }
                """
                docStyleFd.write(toWrite)

        def createChaptersPics(self, display, font, shading):
                res=self.input.ctxt.xpathEval("/abiword/section/p[@style='TblChapter']")

                out=self.input.dir + os.sep + "out"
                theme=out + os.sep + "theme"
                im=Image.open(theme + os.sep + "sunBeach" + os.sep + "surfboard2.png")
                fontFile=filter["PortsDir"] + os.sep + "Ressources" + os.sep + "Fonts" + os.sep + font + ".ttf"
                if(not os.path.exists(fontFile)):
                        fontFile=filter["PortsDir"] + os.sep + "Ressources" + os.sep + "Fonts" + os.sep + "electroh.ttf"
                print "fontFile is " + fontFile
                font2=ImageFont.truetype(fontFile, 18, 0)

                docStyle=open(out + os.sep + "docStyle.css", "w")

                if(display):
                        for i in res:
                                id=i.prop("TblId")
                                print id
                                txt=i.content
                                if(len(txt)>12):
                                        txt=txt[:9] + "..."

                                im2=im.copy()
                                draw=ImageDraw.Draw(im2)

                                if(shading):
                                        draw.text((40, 16), txt, font=font2, fill=(89, 9, 10))
                                draw.text((38, 14), txt, font=font2, fill=(255, 255, 255))

                                del draw

                                file=self.input.dir + os.sep + "out" + os.sep + id + ".png"
                                im3=im2.rotate(90)
                                im3.save(file, "PNG")

                                self.printDocStyleForChapter(docStyle, id)
                else:
                        toWrite="""
                        .TblChapterBis {
                                display: none;
                        }
                        """
                        docStyle.write("toWrite")
                docStyle.close()

        def drawOutside(self, draw, xy1, xy2, color):
                (x1, y1)=xy1
                (x2, y2)=xy2
                dy=y2-y1
                r=dy/2
                draw.arc([x1, y1, x1 + dy, y2], 90, 270, color)
                draw.arc([x2 - dy, y1, x2, y2], 270, 90, color)
                draw.line([x1 + r, y1, x2 - r, y1], color)
                draw.line([x1 + r, y2, x2 - r, y2], color)

        def createHBackground2(self, colorS1, colorS2, file, size, coords):
                im=Image.new("RGBA", size)
                draw=ImageDraw.Draw(im)
                rX1=coords[0]
                rY1=coords[1]
                rX2=coords[2]
                rY2=coords[3]
                cR=(rY2-rY1)/2

                color=colorS2
                self.drawOutside(draw, (rX1 - cR - 8, rY1 - 8), (rX2 + cR + 8, rY2 + 8), color)
                self.drawOutside(draw, (rX1 - cR - 6, rY1 - 6), (rX2 + cR + 6, rY2 + 6), color)
                self.drawOutside(draw, (rX1 - cR - 4, rY1 - 4), (rX2 + cR + 4, rY2 + 4), color)
                self.drawOutside(draw, (rX1 - cR - 2, rY1 - 2), (rX2 + cR + 2, rY2 + 2), color)

                color=colorS1
                draw.setfill(1)
                draw.ellipse([rX1 - cR, rY1, rX1 + cR, rY2], fill=color)
                draw.ellipse([rX2 - cR, rY1, rX2 + cR, rY2], fill=color)
                draw.rectangle([rX1, rY1, rX2, rY2], fill=color)

                del draw

                im.save(file, "PNG")


        def createHBackgrounds(self, colorS1, colorS2):
                out=self.input.dir + os.sep + "out"
                theme=out + os.sep + "theme"
                sunBeach=theme + os.sep + "sunBeach"

                self.createHBackground2(colorS1, colorS2, sunBeach + os.sep + "backH1.png", (822, 130), [65, 27, 761, 103])
                self.createHBackground2(colorS1, colorS2, sunBeach + os.sep + "backH2Page.png", (630, 50), [40, 10, 590, 40])

        def createBul2(self, colorS1, colorS2, menuBackColor):
                out=self.input.dir + os.sep + "out"
                theme=out + os.sep + "theme"
                sunBeach=theme + os.sep + "sunBeach"
                im=Image.new("RGBA", [13, 13])
                draw=ImageDraw.Draw(im)
                draw.rectangle([0, 0, 12, 12], fill=menuBackColor)
                draw.rectangle([5, 5, 7, 7], fill=colorS1)
                for i in [[5, 1, 7, 3], [1, 5, 3, 7], [9, 5, 11, 7], [5, 9, 7, 11]]:
                        draw.rectangle(i, fill=colorS2)
                del draw
                im.save(sunBeach + os.sep + "bul2.gif", "GIF")


        def hPageEtc(self, color1, color2, menuBackgroundColor):
                self.createHBackgrounds(color1, color2)
                out=self.input.dir + os.sep + "out"
                docStyle=open(out + os.sep + "docStyle.css", "a")

                toWrite="""
                #TblTitle {
                        color: """ + color2 + """;
                }
                .TblSection {
                        color: """ + color2 + """;
                }
                .MenuGenerator a:hover
                {
                        color: """ + color2 + """;
                        background-color: """ + color1 + """;
                }
                .MenuGenerator li
                {
                        background-color: """ + menuBackgroundColor + """;
                }

                """
                docStyle.write(toWrite)

                docStyle.close()
                self.createBul2(color1, color2, menuBackgroundColor)


        def run(self, ig):
                cTitlesFg=emb.get(ig, "/HTML_SunBeach/colors/titlesForegroundColor")
                cTitlesBg=emb.get(ig, "/HTML_SunBeach/colors/titlesBackgroundColor")
                cMenuBg=emb.get(ig, "/HTML_SunBeach/colors/menuBackgroundColor")
                sbDisplay=emb.get(ig, "/HTML_SunBeach/chaptersSurfboards/display")
                sbFont=emb.get(ig, "/HTML_SunBeach/chaptersSurfboards/ttfFont")
                sbShading=emb.get(ig, "/HTML_SunBeach/chaptersSurfboards/shading")

                self.ab.run()
                portsDir=filter["PortsDir"]

                themeFile=portsDir + os.sep + "Export" + os.sep + "HTML" + os.sep + "SunBeach" + os.sep + "theme.tgz"
                tar = tarfile.open(themeFile, "r:gz")
                for i in tar.getmembers():
                        tar.extract(i, self.input.dir + os.sep + "out")
                tar.close()

                self.createChaptersPics((sbDisplay=="yes"), sbFont, (sbShading=="yes"))

                self.hPageEtc("#" + cTitlesBg, "#" + cTitlesFg, "#" + cMenuBg)

                del filter["Filter"]


And you can have much better since I am not a web designer or graphist. See what they do at csszengarden.com !