Permalink
Browse files

- width of border edges can now be set individually

- let dzil do git stuff for release.
- added more docs.
- build pdf->gfx object before text object so text shows over graphics.
- enable multi-page documents to be specified in markup.
  • Loading branch information...
1 parent e3b8d5e commit f232e75b77bcdef98d2e7814fc5b1d187a626a75 @lecstor committed Nov 9, 2011
Showing with 183 additions and 41 deletions.
  1. +1 −6 .gitignore
  2. +6 −0 Changes
  3. +1 −1 dist.ini
  4. +106 −11 lib/PDF/Boxer.pm
  5. +45 −11 lib/PDF/Boxer/Content/Box.pm
  6. +8 −10 lib/PDF/Boxer/Content/Image.pm
  7. +11 −2 lib/PDF/Boxer/Doc.pm
  8. +5 −0 lib/PDF/Boxer/SpecParser.pm
View
@@ -1,8 +1,3 @@
-test.pdf
-test_boxer.pdf
-test_invoice.pdf
+*.pdf
/PDF-Boxer-*
.build
-t/full_tests/invoice.pdf
-synopsis_output.pdf
-full_test_invoice.pdf
View
@@ -1,5 +1,11 @@
Revision history for PDF-Boxer
+ - width of border edges can now be set individually
+ - let dzil do git stuff for release.
+ - added more docs.
+ - build pdf->gfx object before text object so text shows over graphics.
+ - enable multi-page documents to be specified in markup.
+
0.01 04/11/11
First version, released on an unsuspecting world.
View
@@ -2,7 +2,7 @@ name = PDF-Boxer
author = Jason Galea <lecstor@cpan.org>
license = Perl_5
copyright_holder = Jason Galea
-version = 0.001
+version = 0.002
[NextRelease]
[@Git]
View
@@ -71,14 +71,20 @@ PDF::Boxer
=head1 DESCRIPTION
-Use my version of a "box model" layout to create PDFs.
-Use PDF::Boxer::SpecParser to parse a template written in the not so patented PDFML.
+PDF::Boxer enables the creation of pdf documents using rows, columns, and grids
+for layout. An xml styled document is used to specify the contents of the
+document and is parsed into a block of data by PDF::Boxer::SpecParser and
+passed to PDF::Boxer
+
Suggestion: Use L<Template> to dynamically create your PDFML template.
=head1 MARKUP
-There should always be a single parent element which would commonly be a column
-allowing other elements to be stacked vertically on the page.
+For a single page document the parent element may be a row, column, or grid.
+Multiple pages can be generated by wrapping more than one of these elements
+with a doc element.
+
+=head2 ELEMENTS
=item column
@@ -107,6 +113,52 @@ container if necessary.
the image element places an image in the PDF.. whoda thunkit, eh?
the image can be scaled to a percentage of it's original size.
+=head2 ATTRIBUTES
+
+=over
+
+=item align
+
+ align="right"
+
+align right or center instead of the default left.
+
+=item background
+
+ background="#FF0000"
+
+background is set as a hexadecimal color.
+
+=item border
+
+border width set in pixels
+
+=item border_color
+
+=item font
+
+=item grow
+
+when set to true, the element will expand to take up any available space.
+
+=item margin, padding, border
+
+size set in pixels as a string for top, right, bottom, left.
+eg:
+ margin="5 10 15 20"; top = 5, right = 10, bottom = 15, left = 20.
+ margin="5 10"; top = 5, right = 10, bottom = 5, left = 10.
+
+margin is space outside the border.
+padding is space inside the border.
+border IS the border..
+
+=item name
+
+I use this for debugging mostly.
+It can be used to get an element object via the box_lookup method.
+
+=back
+
=method add_to_pdf
$boxer->add_to_pdf($spec);
@@ -117,6 +169,34 @@ Coverts markup to PDF.
Writes the generated PDF to the file specified in the call to new.
+=method register_box
+
+each named element is added to an internal register upon creation.
+
+=method box_lookup
+
+ $boxer->box_lookup('elementName');
+
+get an element from the register.
+
+=head1 BUGS
+
+positioning of elements not pixel perfect. eg. in a column the bottom of one
+child overlaps the top of the next by 1 pixel.
+
+=head1 TODO
+
+=over
+
+=item paging
+
+- enable a single element to be nominated for paging so if it's content is too
+large to fit on a page it is continued on the next page.
+
+- enable elements to be marked as first or last page only.
+
+=back
+
=head1 SEE ALSO
=for :list
@@ -175,13 +255,28 @@ sub add_to_pdf{
$spec->{boxer} = $weak_me;
$spec->{debug} = $self->debug;
- my $class = 'PDF::Boxer::Content::'.$spec->{type};
- my $node = $class->new($spec);
- $self->register_box($node);
- $node->initialize;
-# $node->ruler_h;
- $node->render;
- return $node;
+ if ($spec->{type} eq 'Doc'){
+ foreach my $page (@{$spec->{children}}){
+ $page->{boxer} = $weak_me;
+ $page->{debug} = $self->debug;
+
+ my $class = 'PDF::Boxer::Content::'.$page->{type};
+ my $node = $class->new($page);
+ $self->register_box($node);
+ $node->initialize;
+ $node->render;
+ $self->doc->new_page;
+ }
+ } else {
+ my $class = 'PDF::Boxer::Content::'.$spec->{type};
+ my $node = $class->new($spec);
+ $self->register_box($node);
+ $node->initialize;
+ $node->render;
+ }
+
+ return 1;
+ #return $node;
}
sub finish{
@@ -20,6 +20,7 @@ has 'background' => ( isa => 'Str', is => 'ro' );
has 'border_color' => ( isa => 'Str', is => 'ro' );
has 'font' => ( isa => 'Str', is => 'ro', default => 'Helvetica' );
has 'align' => ( isa => 'Str', is => 'ro', default => '' );
+has 'valign' => ( isa => 'Str', is => 'ro', default => '' );
=attr debug
@@ -77,6 +78,11 @@ Non-text boxes will pass this to their children.
The alignment of this box (text string; right or center)
No align means left.
+=attr valign
+
+The vertical alignment of this box (text string; bottom or center)
+No align means top.
+
=cut
sub BUILDARGS{
@@ -247,20 +253,48 @@ sub render{
$gfx->fill;
}
- # === Need to change to respect all border sides sizes ===
- # increasing linewidth thickens the border "around" the lines of the rectangle.
- # we want to thinken "inside" the rectangle..
- if (my $width = $self->border->[0]){
- $gfx->linewidth(1);
+ if ($self->border){
+
+ my $left = $self->border_left;
+ my $top = $self->border_top;
+ my $right = $left + $self->border_width;
+ my $bottom = $top - $self->border_height;
+
$gfx->strokecolor($self->border_color || 'black');
- my ($bl,$bt,$bw,$bh) = ($self->border_left, $self->border_top, $self->border_width, $self->border_height);
- foreach(1..$width){
- $gfx->rect($bl,$bt,$bw,-$bh);
+
+ if ($self->border->[0]){
+ $gfx->linewidth($self->border->[0]);
+ $gfx->move($left, $top);
+ $gfx->line($right, $top);
+ $gfx->stroke;
+ }
+
+ if ($self->border->[1]){
+ $gfx->linewidth($self->border->[1]);
+ $gfx->move($right, $top);
+ $gfx->line($right, $bottom);
$gfx->stroke;
- $bl++; $bt--;
- $bw -= 2;
- $bh -= 2;
}
+
+ if ($self->border->[2]){
+ $gfx->linewidth($self->border->[2]);
+ $gfx->move($right, $bottom);
+ $gfx->line($left, $bottom);
+ $gfx->stroke;
+ }
+
+ if ($self->border->[3]){
+ $gfx->linewidth($self->border->[3]);
+ $gfx->move($left, $bottom);
+ $gfx->line($left, $top);
+ $gfx->stroke;
+ }
+ }
+
+ if ($self->name eq 'Head' || $self->name eq 'Header' || $self->name eq 'Details' || $self->name eq 'ContentGrid'){
+ warn "Name: ".$self->name."\n";
+ warn sprintf "Top: %s\tRight: %s\tBottom: %s\tLeft: %s\n",
+ $self->margin_top, $self->margin_right, $self->margin_bottom, $self->margin_left;
}
foreach(@{$self->children}){
@@ -73,24 +73,22 @@ around 'render' => sub{
my @args = $self->scale ? ($self->scale/100) : ($self->image->width, $self->image->height);
- if (my $al = $self->valign){
- if ($al eq 'top'){
- $y = $self->content_top - $self->image_height;
- } elsif ($al eq 'center'){
+ foreach($self->valign || ()){
+ /^top/ && do { $y = $self->content_top - $self->image_height };
+ /^cen/ && do {
my $bc = $self->content_top - ($self->content_height / 2);
my $ic = $self->image_height / 2;
$y = $bc - $ic;
- }
+ };
}
- if (my $al = $self->align){
- if ($al eq 'right'){
- $x = $self->content_right - $self->image_width;
- } elsif ($al eq 'center'){
+ foreach($self->align || ()){
+ /^rig/ && do { $x = $self->content_right - $self->image_width };
+ /^cen/ && do {
my $bc = $self->content_left + ($self->content_width / 2);
my $ic = $self->image_width / 2;
$x = $bc - $ic;
- }
+ };
}
$gfx->image($img, $x, $y, @args);
View
@@ -18,7 +18,7 @@ sub _build_page{
my ($self) = @_;
my $page = $self->pdf->page;
$page->mediabox(0,0,$self->page_width, $self->page_height);
-# $page->cropbox($self->page_width-10, $self->page_height);
+ #$page->cropbox($self->page_width-10, $self->page_height);
return $page;
}
@@ -33,7 +33,9 @@ sub _build_gfx{ shift->page->gfx }
has 'text' => ( isa => 'Object', is => 'rw', lazy_build => 1 );
sub _build_text{
- my $txt = shift->page->text;
+ my ($self) = @_;
+ $self->gfx;
+ my $txt = $self->page->text;
$txt->compressFlate;
return $txt;
}
@@ -50,6 +52,13 @@ sub _build_fonts{
}
}
+sub new_page{
+ my ($self) = @_;
+ $self->clear_page;
+ $self->clear_text;
+ $self->clear_gfx;
+}
+
sub font{
my ($self, $name) = @_;
my $font = $self->fonts->{$name};
@@ -58,6 +58,10 @@ sub mangle_spec{
$element->[0]{type} = 'Grid';
push(@{$spec->{children}}, shift @$element);
$self->mangle_spec($spec->{children}->[-1], $element);
+ } elsif (lc($tag) eq 'doc'){
+ $element->[0]{type} = 'Doc';
+ push(@{$spec->{children}}, shift @$element);
+ $self->mangle_spec($spec->{children}->[-1], $element);
} else {
$element->[0]{type} = 'Box';
push(@{$spec->{children}}, shift @$element);
@@ -68,6 +72,7 @@ sub mangle_spec{
sub clean_text{
my ($self, $element) = @_;
+ return unless $element;
return if $element =~ /^[\s\n\r]*$/;
if ($self->clean_whitespace){
$element =~ s/^[\s\n\r]+//;

0 comments on commit f232e75

Please sign in to comment.