Open Event Server Ticket PDF: Where and Where-not to use static frame in xhtml2pdf

One among the very important features of Open Event Server project is the tickets sales feature, where a user can buy a number of different tickets for a number of people after which he is given a link to download the ticket pdf. However, an issue concerning our Open Event Server project was that if a buyer bought different tickets at a time with different individual ticket holders, all tickets contained the same name, type and QR-Code, which in no way was acceptable since tickets and holders were different.

We use the xhtml2pdf facility in order to convert an html to pdf. An xhtml2pdf facility helps us in converting HTML contents into PDF without the use of browser ‘print’ facility. In order to do this, we use the help of pages and frames, pages being the page of the PDF document, while a frame being that part of area within the page where the contents get stored.

What is a PDF and HTML?

The basic understanding of a PDF and an HTML is that, a PDF or Portable Document Format has layout such that it is measured in terms of specific width and height. However, for an HTML or Hyper Text Markup Language, we do no not have those specific widths and heights. Rather an HTML’s width depends on a person’s device of view and height can be infinitely long as desired.

In terms of xhtml2pdf relation with pages and frames layout, we can identify with this diagram:

+-page———————+
|                                    |
|  +-content_frame-+  |
|  |                          |    |
|  |                          |    |
|  |                          |    |
|  |                          |    |
|  +———————+   |
|                                    |
+—————————-+


The stated issue was due to static frame in xhtml2pdf.

What is that you ask?

Static frames vs Content frames
xhtml2pdf uses the concept of Static Frames to define content that remains the same across different pages (like headers and footers), and uses Content Frames to position the to-be-converted HTML content.

Static Frames are defined through use of the @frame property -pdf-frame-content. Regular HTML content will not flow through Static Frames.

Content Frames are @frame objects without this property defined. Regular HTML content will flow through Content Frames.(xhtml2pdf documentation)

So, the basic idea of the use of  -pdf-frame-content  was to make the contents of the pdf static i.e. without having to continuously change alignments of the page. It made the whole pdf stay static.

This actually caused the whole pdf content to stay constant, event while the loop was going over different name, QR-code and ticket-name values. That means the first loop content stayed over even with changes in values.

Just a simple fix of not making the frame static was the solution.

Here is a few insight of what we had before that was causing the issue:

 <style>
        @page {
            size: a4 portrait;
            background-image: url('{{ base_dir }}/static/data/ticket-trans-
                                  notext.png');
            margin: 0;

            @frame col1_frame {             /* Content frame 1 */
                left: 80pt;  top: 30pt;
                height: 250pt; width: 300pt;
                -pdf-frame-content: main_content;
            }

            @frame qrcode {
                left: 455pt;  top: 50pt;
                width: 100pt; height: 120pt;
                -pdf-frame-content: qr_code;
            }
            @frame number_frame {
                 left: 455pt;  top: 25pt;
                width: 100pt; height: 30pt;
                -pdf-frame-content: number_content;
            }


             @frame col2_frame {
                left: 440pt; top: 170pt;
                -pdf-frame-content: personal_content;
            }
        }


Here,
main_content, qrcode, personal_content and number_content? are simply the class you want to make static.
The following was done to fix it:

 <style>
        @page {
            size: a4 portrait;
            background-image: url('{{ base_dir }}/static/data/ticket-trans-
                                  notext.png');
            margin: 0;

            @frame col1_frame {             /* Content frame 1 */
                left: 80pt;  top: 30pt;
                height: 250pt; width: 300pt;
            }

            @frame qrcode {
                left: 455pt;  top: 50pt;
                width: 100pt; height: 120pt;
            }
            @frame number_frame {
                 left: 455pt;  top: 25pt;
                width: 100pt; height: 30pt;
                -pdf-frame-content: number_content;
            }


             @frame col2_frame {
                left: 440pt; top: 170pt;
            }
        }



But the main question was, ‘where and where-not to use static frame’.
So the simple answer to that is, when you want the contents to stay exactly the same over the different pages of the pdf (for example the company logo or the administrator signature, etc), then you can happily get on with -pdf-frame-content. i.e:

          -pdf-frame-content: <class_name>


If not, or you need to loop over different values, then use Content frames.

Also, for more detailed understanding of PDF and HTML pages and frames, we have this good documentation written about it here: https://github.com/xhtml2pdf/xhtml2pdf/blob/master/doc/source/format_html.rst#static-frames-vs-content-frames

Responsive Image Overlay

Image overlay is a very common concept in front-end development. It is easy to implement but difficult when we deal it with different screen sizes, where we need to cover the image with the overlay each time the screen size is changed. I have gone through various blog posts when I need to implement the same for Open-event webapp and researched a solution that works for all screen sizes without any media query.

1234

How to add an overlay to an image ?

If we need four images in a single row nearly 300*300px.  The code below shows the markup.

image-holder : The parent class to take the image and overlay inside it.

background-image: This class takes image source.

responsive-overlay: This is the key point to make it responsive. Responsive-overlay contains a class hover-state to add overlay absolutely and a class social-links.

social-links: It adds content to hover-state.

 

<div class="image-holder">
  <img class="background-image" alt="" src="">
   <div class="responsive-overlay">
     <div class="hover-state text-center preserve3d">
       <div class="social-links vertical-align">

       </div>
     </div>
   </div>
 </div>

The styling is written with SASS in .scss file as shown below.

//overlayimage and backgroundshade can be set in config.scss

 .image-holder {
   position: relative;
   overflow: hidden;
   margin-bottom: 12px;

   .background-image {
     height: 300px;
     width: 300px;
     display: block;
     margin: 0 auto;
     background-color: $background-shade;
    }
 
   .responsive-overlay {
     @include responsiveoverlay;

    .preserve3d {
       height: 300px;
      }

    .hover-state {
     @include hoverstate;
     height: 300px;
     width: 300px;
    }

  @mixin responsiveoverlay {
     height: 100%;
     position: absolute;
     top: 0;
     width: 100%;
}

   @mixin hoverstate {
     background: $overlayimage;
     display: block;
     height: 300px;
     left: 0;
     margin: 0 auto;
     opacity: 0;
     position: relative;
     top: 0;
     -moz-transition: all 0.3s ease-out;
     -webkit-transition: all 0.3s ease-out;
     transition: all 0.3s ease-out;
     width: 300px;
     z-index: 2;
   }

This code will work for responsiveness as well. The main catch here is the responsive-overlay class which is made 100% in width but set to position absolute. The images which are 300 * 300 px in size will take an overlay of the same size because of hover-state class. Instead, if we adjust sizes of images in small screens the above code will adjust overlay on the image automatically.

Like, on tablets we can have an overlay like this.

345

And on mobile screen output is like that :

23

Conclusion

Responsiveness is easy if we follow correct concepts. Here, the concepts of absolute and relative positioning in CSS have done the magic. Now we can play by adding different contents and effect on hover following the same basics.