Ir al contenido principal

Ralsina.Me — El sitio web de Roberto Alsina

Publicaciones sobre python (publicaciones antiguas, página 65)

PET: English Translation Issue 1 tiene fecha

La ver­sión en in­glés se lla­ma PE­T, que sig­ni­fi­ca "P­y­thon En­tre To­do­s: En­glish Trans­la­tio­n".

Va a te­ner los mis­mos con­te­ni­dos que el pri­mer nú­me­ro en cas­te­llano­... y va a ser la úl­ti­ma que ha­ga­mos así.

De ahí en má­s, las dos ver­sio­nes van a salir al mis­mo tiem­po, si po­de­mo­s.

Por lo tan­to, va a ha­ber un lap­so muy cor­to en­tre el pri­mer nú­me­ro en in­glés y el se­gun­do (o­ja­lá que me­nos de un me­s).

Así que , no cam­bien de ca­nal

Cosas que aprendí publicando una revista

¿En­ton­ce­s, que apren­dí? ¡Va­rias co­sas!

  • Lo úni­­co que se ne­­ce­­si­­ta pa­­ra pu­­bli­­car es tie­m­­po y co­n­­te­­ni­­do.

  • El tie­m­­po se pue­­de co­n­­ve­r­­tir en co­n­­te­­ni­­do, pe­­ro si es­­cri­­bís to­­­do so­­­lo es un blo­­­g, no una re­­vis­­ta. Por sue­r­­te PET atra­­jo bue­­­nos co­­­la­­bo­­­ra­­do­­­res.

  • Si que­­rés di­se­­ño uti­­li­­ta­­rio, rs­­t2­­pdf fun­­cio­­­na.

  • En al­­gu­­nos sen­­ti­­dos fun­­cio­­­na me­­jor que otras he­­rra­­mien­­ta­s.

    • Pue­­­do sa­­­car una ve­­r­­­sión co­­­­­rre­­­gi­­­da de los PDFs en 5 mi­­­nu­­­tos pa­­­ra to­­­­­dos los di­se­­­ño­­­s. ¿Cuán­­­to me lle­­­va­­­ria usan­­­do Scri­­­bus u otros DTP? En una re­­­vis­­­ta do­­n­­­de las co­­­sas de­­­ben ser co­­­­­rre­­c­­­tas eso es im­­­po­­­r­­­tan­­­te.

    • Las ta­­­blas de co­­n­­­te­­­ni­­­do (TO­­­­­C) son me­­­jo­­­­­res que la ma­­­yo­­­­­ría de las re­­­vis­­­tas en PDF ama­­­teu­­­r. La que es­­­tá en el tex­­­to es cli­­­ckea­­­ble, y la del PDF es pe­­r­­­fe­­c­­­ta.

    Los nú­­me­­ros de pá­­gi­­na en la TOC del PDF es­­tán bien (no, la ta­­pa no es la pá­­gi­­na 1)

    • Es­­­toy pro­­­­­du­­­cien­­­do 6 ve­­r­­­sio­­­­­nes en PDF: A4 (BN, co­­­­­lo­­­­­r), A5(­­­BN, co­­­­­lo­­­­­r) y li­­­bri­­­to­­­(­­­BN, co­­­­­lo­­­­­r) y po­­­­­dría agre­­­gar otra en mi­­­nu­­­to­­­s.

  • ¡A­­pren­­dí que es PDF Im­­po­­­si­­tio­­n!

Va­mos a ex­pli­car es­a:

Su­po­ne­te que que­res im­pri­mir un li­bri­to, y te­nés 32 pá­gi­nas de con­te­ni­do. ¿Co­mo lo ha­cé­s?

La for­ma más fá­cil es im­pri­mir­lo a dos pa­gi­nas por ca­ri­lla en pa­pel A4, así po­dés api­lar las ho­ja­s, do­blar­las por la mi­ta­d, abro­char­la­s, y te da un lin­do li­bri­to A5.

El pro­ble­ma es que el or­den de las pá­gi­nas es di­fí­ci­l. Por ejem­plo, pa­ra un li­bri­to de 4 pá­gi­na­s, hay que im­pri­mir una ho­ja A4 con las pá­gi­nas 4-1 de un la­do y las 2-3 del otro.

Pa­ra 8 pá­gi­na­s, es 8-1,2-7,3-6,4-5.

Por suer­te hay una for­ma de ha­cer­lo au­to­má­ti­ca­men­te:

1. Ins­ta­lá po­do­fo 3. Con­se­gui­te book­le­t-A4.­plan (ver aba­jo) 2. Co­rré es­to:

podofoimpose mis-paginas-A5.pdf mi-librito.pdf booklet-A4.plan lua

book­le­t-A4.­plan es es­to:

---Generic Booklet (A4)
---
---It is said generic as it will try to determine
---automatically how to fit the booklet onto A4
---paper sheets, scaling pages if necessary.
---it is well suited for office documents for
---which you do not care too much about resulting
---imposition artefacts since it manages to save
---paper!
---
-- print("Booklet")
-- We output an A4 booklet
PageWidth = 595.27559
PageHeight = 841.88976

print("PageCount",PageCount)

-- We assume that H > W
-- Argh, we now can do better since we have "if" ;-)
-- Scale = PageHeight / (2*SourceWidth)
if(SourceWidth <= SourceHeight)
then
--  If you A5 pages are not really A5, uncomment the next line
--  Scale = PageHeight / (2*SourceWidth)
    Scale = 1
    rot = 90
        xof = SourceHeight
        yofRA = 0
        yofRB = SourceWidth
        yofVA = 0
        yofVB = SourceWidth
else
--  If you A5 pages are not really A5, uncomment the next line
--  Scale = PageHeight / (2*SourceHeight)
    Scale = 1
    rot = 0
        xof = 0;
        yofRA = 0
        yofRB = SourceHeight
        yofVA = SourceHeight
        yofVB = 0
end

do
    rest = PageCount % 4
    totp = PageCount
    if rest ~= 0
        then
        totp = totp + ( 4 - rest)
        end
    inc = 0
    count = 0
    imax = totp/4
    while count < imax
        do
--          We assume that podofoimpose will discard invalid records
--          such as those with source page greater than PageCount
--          print(totp, inc, rot, xof,yofRA, yofRA, yofVA, yofVB)
-- Recto
        PushRecord(totp - inc , inc + 1 , rot, xof , yofRA)
        PushRecord(inc + 1 , inc + 1 , rot, xof , yofRB)
-- Verso
        PushRecord(inc + 2 , inc + 2 , rot, xof , yofVA)
        PushRecord(totp-(inc + 1) , inc + 2 , rot, xof, yofVB)

        count = count + 1
        inc = inc + 2
        end
end

El có­di­go es­tá to­ma­do de acá: http://www.oe­p-h.­co­m/im­po­se/

Y lis­to, te­nés un PDF to­do re­vuel­to con las pá­gi­nas en exac­ta­men­te el or­den co­rrec­to (y pá­gi­nas en blan­co agre­ga­das en el lu­gar ne­ce­sa­rio­).

¡Vengan a verme a Bahía Blanca este fin de semana!

Pa­ra va­ria­r, no voy a dar una de mis char­las vie­ja­s, sino una com­ple­ta­men­te nue­va, es­treno nun­ca ta­xi, que se lla­ma "El Ama­teu­r", y pro­ba­ble­men­te una li­gh­tning ta­lk o al­go así.

La ofer­ta ha­bi­tual de cer­ve­za gra­tis no va a ser po­si­ble es­ta ve­z, asi que: si men­cio­nás es­te blog en la se­sión de pre­gun­tas y res­pues­tas te ga­na­s... ca­ra­me­los gra­tis!

Des­pués de eso, voy a es­tar en FM La Tri­bu el sá­ba­do 21 de agos­to en las Char­las Abier­tas 2010 ha­blan­do de co­sas co­mo vir­tua­len­v, to­x, no­se y otros te­mas re­la­cio­na­dos a tes­tin­g.

Sale o sale: PET - Python Entre Todos

Sa­qué la cuen­ta re­gre­si­va por­que es­ta­ba equi­vo­ca­da (pro­ble­ma de ti­me­zo­ne). Pa­ra una que fun­cio­na, vean http://­re­vis­ta.­p­y­tho­n.or­g.ar

Me han me­ti­do en OPM (O­tro Pro­yec­to Má­s) y es­te es el pri­mer nú­me­ro en la his­to­ria de PET - Py­thon En­tre To­dos una re­vis­ta on­li­ne de py­tho­n.

Es­to es un emer­gen­te de PyAr la co­mu­ni­dad de Py­thon Ar­gen­ti­na, y tal vez nun­ca ten­ga un se­gun­do nú­me­ro así que aten­tos al pri­me­ro ;-)

Ven­go ha­cien­do de we­bmas­te­r, edi­ción y pro­duc­ción del PDF jun­to con Emi­liano Da­lla Ver­de Mar­co­z­zi que ayu­da por to­das par­tes y con­si­guió los ar­tícu­lo­s.

El pri­mer nú­me­ro son unas 45 pá­gi­nas A5 (o 23 A4) en le­tra chi­ca así que no es exac­ta­men­te enor­me, pe­ro tie­ne me­dia do­ce­na de ar­tícu­los apun­ta­dos a dis­tin­tos ni­ve­les de pro­gra­ma­dor py­tho­n.

¡Es­tá sien­do di­ver­ti­da de ha­ce­r, oja­lá sea bien re­ci­bi­da!

Extensiones para rst2pdf: Fácil y poderoso

Es po­pu­la­r, por le­jos mi pro­gra­ma más usa­do, pe­ro po­cos sa­ben que es tam­bién fá­cil de ex­ten­der (¡s­alu­dos a Pa­tri­ck Mau­pi­n, que es­cri­bió esa par­te!). Y no só­lo eso, sino que se pue­de ha­cer que ha­ga co­sas bas­tan­te asom­bro­sas con un po­co de es­fuer­zo.

Pa­ra de­mos­trar­lo, cree­mos los tí­tu­los de sec­ción más im­pre­sio­nan­tes del mun­do y sus al­re­de­do­res (a ver co­mo ha­cen es­to con La­TeX ;-)

Pri­me­ro: de­fi­na­mos el pro­ble­ma

Los tí­tu­los que pue­de pro­du­cir rs­t2­pdf son abu­rri­do­s. Si apre­tás to­dos los bo­to­nes y ti­rás de to­das las pa­lan­ca­s, po­dés lle­gar a pro­du­cir un tí­tu­lo en Co­mic San­s, ali­nea­do de­re­cha en le­tras ro­sas con fon­do pal­ta y bor­de ro­jo.

Y has­ta ahí lle­ga la per­so­na­li­za­ción que po­dés ha­cer usan­do sty­les­hee­ts. Nor­mal­men­te eso es su­fi­cien­te por­que rs­t2­pdf no es­tá pen­sa­do pa­ra fo­lle­te­ría (aun­que al­gu­na se ha he­cho).

El pro­ble­ma real es que si te po­nés en di­se­ña­dor grá­fi­co con rs­t2­pdf, per­dés la es­truc­tu­ra del do­cu­men­to por­que no es­tás sien­do se­mánti­co.

Se­gun­do: de­fi­nir la me­ta

Uie­ro ha­cer en­ca­be­za­dos co­mo es­te:

fancytitles1

La ima­gen es­tá saca­da de la bi­blio­te­ca del con­gre­so de EEUU con un po­co de (ma­l) tra­ba­jo de gimp pa­ra de­jar el es­pa­cio li­bre a la iz­quier­da, y el tí­tu­lo se agre­gó con Inks­ca­pe.

¿Se pue­de ha­cer eso con rs­t2­pdf? No, ni cer­ca. No sin pro­gra­ma­r. ¡A­sí que pro­gra­me­mos una ex­ten­sión que te per­mi­ta crear cual­quier en­ca­be­za­do que vos quie­ras den­tro de los lí­mi­tes de Inks­ca­pe!

Pri­me­ro crea­mos un tem­pla­te SVG pa­ra los en­ca­be­za­dos (Es un po­co gran­de por­que tie­ne la ima­gen aden­tro­).

Ter­ce­ro: el flo­wa­ble en­ca­be­za­do­-i­ma­gen

Suponete que tenés una imagen del encabezado exactamente como esa de arriba. ¿Como lo dibujás en un PDF? En reportlab se hace usando flowables que son elementos que componen la historia que es tu documento. Esos flowables se acomodan en páginas, y eso es tu PDF.

Si es­tás ha­cien­do un tí­tu­lo, hay una co­sa má­s, ne­ce­si­tás crear un book­ma­rk pa­ra que apa­rez­ca en la ta­bla de con­te­ni­dos del PDF.

Este es un flowable que hace eso. Está hecho pegando pedazos de cosas de rst2pdf y es una cruza maligna entre Heading y MyImage:

class FancyHeading(MyImage):
  '''This is a cross between the Heading flowable, that adds outline
  entries so you have a PDF TOC, and MyImage, that draws images'''

  def __init__(self, *args, **kwargs):
      # The inicialization is taken from rst2pdf.flowables.Heading
      self.stext = kwargs.pop('text')
      # Cleanup title text
      self.stext = re.sub(r'<[^>]*?>', '', unescape(self.stext))
      self.stext = self.stext.strip()

      # Stuff needed for the outline entry
      self.snum = kwargs.pop('snum')
      self.level = kwargs.pop('level')
      self.parent_id= kwargs.pop('parent_id')


      MyImage.__init__(self, *args, **kwargs)

  def drawOn(self,canv,x,y,_sW):

      ## These two lines are magic.
      #if isinstance(self.parent_id, tuple):
          #self.parent_id=self.parent_id[0]

      # Add outline entry. This is copied from rst2pdf.flowables.heading
      canv.bookmarkHorizontal(self.parent_id,0,0+self.image.height)

      if canv.firstSect:
          canv.sectName = self.stext
          canv.firstSect=False
          if self.snum is not None:
              canv.sectNum = self.snum
          else:
              canv.sectNum = ""

      canv.addOutlineEntry(self.stext.encode('utf-8','replace'),
                                self.parent_id.encode('utf-8','replace'),
                                int(self.level), False)

      # And let MyImage do all the drawing
      MyImage.drawOn(self,canv,x,y,_sW)

¿Y cómo le decimos a rst2pdf que use eso en vez de un Heading común? Pisando la clase TitleHandler. Acá es donde entra la magia de las extensiones.

Si se de­fi­ne, en una ex­ten­sió­n, una cla­se co­mo es­ta:

class FancyTitleHandler(genelements.HandleParagraph, docutils.nodes.title):

Entonces esa clase va a ser responsable de todos los nodos de clase docutils.nodes.title. En este caso, tan solo copié rst2pdf.genelements.HandleTitle y cambié el resultado de los encabezados nivel 1 para que use un FancyHeading en vez de un Heading... y eso es todo.

class FancyTitleHandler(genelements.HandleParagraph, docutils.nodes.title):
  '''
  This class will handle title nodes.

  It takes a "titletemplate.svg", replaces TITLEGOESHERE with
  the actual title text, and draws that using the FancyHeading flowable
  (see below).

  Since this class is defined in an extension, it
  effectively replaces rst2pdf.genelements.HandleTitle.
  '''

  def gather_elements(self, client, node, style):
      # This method is copied from the HandleTitle class
      # in rst2pdf.genelements.

      # Special cases: (Not sure this is right ;-)
      if isinstance(node.parent, docutils.nodes.document):
          #node.elements = [Paragraph(client.gen_pdftext(node),
                                      #client.styles['title'])]
          # The visible output is now done by the cover template
          node.elements = []
          client.doc_title = node.rawsource
          client.doc_title_clean = node.astext().strip()
      elif isinstance(node.parent, docutils.nodes.topic):
          node.elements = [Paragraph(client.gen_pdftext(node),
                                      client.styles['topic-title'])]
      elif isinstance(node.parent, docutils.nodes.Admonition):
          node.elements = [Paragraph(client.gen_pdftext(node),
                                      client.styles['admonition-title'])]
      elif isinstance(node.parent, docutils.nodes.table):
          node.elements = [Paragraph(client.gen_pdftext(node),
                                      client.styles['table-title'])]
      elif isinstance(node.parent, docutils.nodes.sidebar):
          node.elements = [Paragraph(client.gen_pdftext(node),
                                      client.styles['sidebar-title'])]
      else:
          # Section/Subsection/etc.
          text = client.gen_pdftext(node)
          fch = node.children[0]
          if isinstance(fch, docutils.nodes.generated) and \
              fch['classes'] == ['sectnum']:
              snum = fch.astext()
          else:
              snum = None
          key = node.get('refid')
          maxdepth=4
          if reportlab.Version > '2.1':
              maxdepth=6

          # The parent ID is the refid + an ID to make it unique for Sphinx
          parent_id=(node.parent.get('ids', [None]) or [None])[0]+u'-'+unicode(id(node))
          if client.depth > 1:
              node.elements = [ Heading(text,
                      client.styles['heading%d'%min(client.depth, maxdepth)],
                      level=client.depth-1,
                      parent_id=parent_id,
                      node=node,
                      )]
          else: # This is an important title, do our magic ;-)
              # Hack the title template SVG
              tfile = open('titletemplate.svg')
              tdata = tfile.read()
              tfile.close()
              tfile = tempfile.NamedTemporaryFile(dir='.', delete=False, suffix='.svg')
              tfname = tfile.name
              tfile.write(tdata.replace('TITLEGOESHERE', text))
              tfile.close()

              # Now tfname contains a SVG with the right title.
              # Make rst2pdf delete it later.
              client.to_unlink.append(tfname)

              e = FancyHeading(tfname, width=700, height=100,
                  client=client, snum=snum, parent_id=parent_id,
                  text=text, level=client.depth-1)

              node.elements = [e]

          if client.depth <= client.breaklevel:
              node.elements.insert(0, MyPageBreak(breakTo=client.breakside))
      return node.elements

La ex­ten­sión es­tá en SVN y se pue­de pro­bar así:

[fancytitles]$ rst2pdf -e fancytitles -e inkscape demo.txt -b1

Hay que ha­bi­li­tar la ex­ten­sión Inks­ca­pe pa­ra que los SVG se vean lo me­jor po­si­ble. Y es­ta es la sali­da:

fancytitles2

Se pue­de cam­biar cual­quier ele­men­to de la sali­da. Eso es ser ex­ten­si­ble :-)


Contents © 2000-2023 Roberto Alsina