github.com/MontFerret/ferret@v0.18.0/pkg/stdlib/html/pdf.go (about)

     1  package html
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"regexp"
     7  
     8  	"github.com/MontFerret/ferret/pkg/drivers"
     9  	"github.com/MontFerret/ferret/pkg/runtime/core"
    10  	"github.com/MontFerret/ferret/pkg/runtime/values"
    11  	"github.com/MontFerret/ferret/pkg/runtime/values/types"
    12  )
    13  
    14  func ValidatePageRanges(pageRanges string) (bool, error) {
    15  	match, err := regexp.Match(`^(([1-9][0-9]*|[1-9][0-9]*)(\s*-\s*|\s*,\s*|))*$`, []byte(pageRanges))
    16  
    17  	if err != nil {
    18  		return false, err
    19  	}
    20  
    21  	return match, nil
    22  }
    23  
    24  // PDF prints a PDF of the current page.
    25  // @param {HTMLPage | String}target - Target page or url.
    26  // @param {Object} [params] - An object containing the following properties:
    27  // @param {Bool} [params.landscape=False] - Paper orientation.
    28  // @param {Bool} [params.displayHeaderFooter=False] - Display header and footer.
    29  // @param {Bool} [params.printBackground=False] - Print background graphics.
    30  // @param {Float} [params.scale=1] - Scale of the webpage rendering.
    31  // @param {Float} [params.paperWidth=22] - Paper width in inches.
    32  // @param {Float} [params.paperHeight=28] - Paper height in inches.
    33  // @param {Float} [params.marginTo=1] - Top margin in inches.
    34  // @param {Float} [params.marginBottom=1] - Bottom margin in inches.
    35  // @param {Float} [params.marginLeft=1] - Left margin in inches.
    36  // @param {Float} [params.marginRight=1] - Right margin in inches.
    37  // @param {String} [params.pageRanges] - Paper ranges to print, e.g., '1-5, 8, 11-13'.
    38  // @param {String} [params.headerTemplate] - HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them: - `date`: formatted print date - `title`: document title - `url`: document location - `pageNumber`: current page number - `totalPages`: total pages in the document For example, `<span class=title></span>` would generate span containing the title.
    39  // @param {String} [params.footerTemplate] - HTML template for the print footer. Should use the same format as the `headerTemplate`.
    40  // @param {Bool} [params.preferCSSPageSize=False] - Whether or not to prefer page size as defined by css. Defaults to false, in which case the content will be scaled to fit the paper size. *
    41  // @return {Binary} - PDF document in binary format.
    42  func PDF(ctx context.Context, args ...core.Value) (core.Value, error) {
    43  	err := core.ValidateArgs(args, 1, 2)
    44  
    45  	if err != nil {
    46  		return values.None, err
    47  	}
    48  
    49  	arg1 := args[0]
    50  	page, closeAfter, err := OpenOrCastPage(ctx, arg1)
    51  
    52  	if err != nil {
    53  		return values.None, err
    54  	}
    55  
    56  	defer func() {
    57  		if closeAfter {
    58  			page.Close()
    59  		}
    60  	}()
    61  
    62  	pdfParams := drivers.PDFParams{}
    63  
    64  	if len(args) == 2 {
    65  		arg2 := args[1]
    66  		err = core.ValidateType(arg2, types.Object)
    67  
    68  		if err != nil {
    69  			return values.None, err
    70  		}
    71  
    72  		params, ok := arg2.(*values.Object)
    73  
    74  		if !ok {
    75  			return values.None, core.Error(core.ErrInvalidType, "expected object")
    76  		}
    77  
    78  		landscape, found := params.Get("landscape")
    79  
    80  		if found {
    81  			err = core.ValidateType(landscape, types.Boolean)
    82  
    83  			if err != nil {
    84  				return values.None, err
    85  			}
    86  
    87  			pdfParams.Landscape = landscape.(values.Boolean)
    88  		}
    89  
    90  		displayHeaderFooter, found := params.Get("displayHeaderFooter")
    91  
    92  		if found {
    93  			err = core.ValidateType(displayHeaderFooter, types.Boolean)
    94  
    95  			if err != nil {
    96  				return values.None, err
    97  			}
    98  
    99  			pdfParams.DisplayHeaderFooter = displayHeaderFooter.(values.Boolean)
   100  		}
   101  
   102  		printBackground, found := params.Get("printBackground")
   103  
   104  		if found {
   105  			err = core.ValidateType(printBackground, types.Boolean)
   106  
   107  			if err != nil {
   108  				return values.None, err
   109  			}
   110  
   111  			pdfParams.PrintBackground = printBackground.(values.Boolean)
   112  		}
   113  
   114  		scale, found := params.Get("scale")
   115  
   116  		if found {
   117  			err = core.ValidateType(scale, types.Float, types.Int)
   118  
   119  			if err != nil {
   120  				return values.None, err
   121  			}
   122  
   123  			if scale.Type() == types.Int {
   124  				pdfParams.Scale = values.Float(scale.(values.Int))
   125  			} else {
   126  				pdfParams.Scale = scale.(values.Float)
   127  			}
   128  		}
   129  
   130  		paperWidth, found := params.Get("paperWidth")
   131  
   132  		if found {
   133  			err = core.ValidateType(paperWidth, types.Float, types.Int)
   134  
   135  			if err != nil {
   136  				return values.None, err
   137  			}
   138  
   139  			if paperWidth.Type() == types.Int {
   140  				pdfParams.PaperWidth = values.Float(paperWidth.(values.Int))
   141  			} else {
   142  				pdfParams.PaperWidth = paperWidth.(values.Float)
   143  			}
   144  		}
   145  
   146  		paperHeight, found := params.Get("paperHeight")
   147  
   148  		if found {
   149  			err = core.ValidateType(paperHeight, types.Float, types.Int)
   150  
   151  			if err != nil {
   152  				return values.None, err
   153  			}
   154  
   155  			if paperHeight.Type() == types.Int {
   156  				pdfParams.PaperHeight = values.Float(paperHeight.(values.Int))
   157  			} else {
   158  				pdfParams.PaperHeight = paperHeight.(values.Float)
   159  			}
   160  		}
   161  
   162  		marginTop, found := params.Get("marginTop")
   163  
   164  		if found {
   165  			err = core.ValidateType(marginTop, types.Float, types.Int)
   166  
   167  			if err != nil {
   168  				return values.None, err
   169  			}
   170  
   171  			if marginTop.Type() == types.Int {
   172  				pdfParams.MarginTop = values.Float(marginTop.(values.Int))
   173  			} else {
   174  				pdfParams.MarginTop = marginTop.(values.Float)
   175  			}
   176  		}
   177  
   178  		marginBottom, found := params.Get("marginBottom")
   179  
   180  		if found {
   181  			err = core.ValidateType(marginBottom, types.Float, types.Int)
   182  
   183  			if err != nil {
   184  				return values.None, err
   185  			}
   186  
   187  			if marginBottom.Type() == types.Int {
   188  				pdfParams.MarginBottom = values.Float(marginBottom.(values.Int))
   189  			} else {
   190  				pdfParams.MarginBottom = marginBottom.(values.Float)
   191  			}
   192  		}
   193  
   194  		marginLeft, found := params.Get("marginLeft")
   195  
   196  		if found {
   197  			err = core.ValidateType(marginLeft, types.Float, types.Int)
   198  
   199  			if err != nil {
   200  				return values.None, err
   201  			}
   202  
   203  			if marginLeft.Type() == types.Int {
   204  				pdfParams.MarginLeft = values.Float(marginLeft.(values.Int))
   205  			} else {
   206  				pdfParams.MarginLeft = marginLeft.(values.Float)
   207  			}
   208  		}
   209  
   210  		marginRight, found := params.Get("marginRight")
   211  
   212  		if found {
   213  			err = core.ValidateType(marginRight, types.Float, types.Int)
   214  
   215  			if err != nil {
   216  				return values.None, err
   217  			}
   218  
   219  			if marginRight.Type() == types.Int {
   220  				pdfParams.MarginRight = values.Float(marginRight.(values.Int))
   221  			} else {
   222  				pdfParams.MarginRight = marginRight.(values.Float)
   223  			}
   224  		}
   225  
   226  		pageRanges, found := params.Get("pageRanges")
   227  
   228  		if found {
   229  			err = core.ValidateType(pageRanges, types.String)
   230  
   231  			if err != nil {
   232  				return values.None, err
   233  			}
   234  
   235  			validate, err := ValidatePageRanges(pageRanges.String())
   236  
   237  			if err != nil {
   238  				return values.None, err
   239  			}
   240  
   241  			if !validate {
   242  				return values.None, core.Error(core.ErrInvalidArgument, fmt.Sprintf(`page ranges "%s", not valid`, pageRanges.String()))
   243  			}
   244  
   245  			pdfParams.PageRanges = pageRanges.(values.String)
   246  		}
   247  
   248  		headerTemplate, found := params.Get("headerTemplate")
   249  
   250  		if found {
   251  			err = core.ValidateType(headerTemplate, types.String)
   252  
   253  			if err != nil {
   254  				return values.None, err
   255  			}
   256  
   257  			pdfParams.HeaderTemplate = headerTemplate.(values.String)
   258  		}
   259  
   260  		footerTemplate, found := params.Get("footerTemplate")
   261  
   262  		if found {
   263  			err = core.ValidateType(footerTemplate, types.String)
   264  
   265  			if err != nil {
   266  				return values.None, err
   267  			}
   268  
   269  			pdfParams.FooterTemplate = footerTemplate.(values.String)
   270  		}
   271  
   272  		preferCSSPageSize, found := params.Get("preferCSSPageSize")
   273  
   274  		if found {
   275  			err = core.ValidateType(preferCSSPageSize, types.Boolean)
   276  
   277  			if err != nil {
   278  				return values.None, err
   279  			}
   280  
   281  			pdfParams.PreferCSSPageSize = preferCSSPageSize.(values.Boolean)
   282  		}
   283  	}
   284  
   285  	pdf, err := page.PrintToPDF(ctx, pdfParams)
   286  
   287  	if err != nil {
   288  		return values.None, err
   289  	}
   290  
   291  	return pdf, nil
   292  }