Permalink
Browse files

dramatic improvement -- more closely resembles madinah mushaf wrt pag…

…e height, line spacing and alignment
  • Loading branch information...
1 parent cfe0bca commit a9b677e064bd40af54b3509485c4996c45a994f2 @sharabash sharabash committed Dec 1, 2009
Showing with 80 additions and 78 deletions.
  1. +2 −0 .gitignore
  2. +78 −78 generate.quran.page.pl
View
@@ -2,4 +2,6 @@
*.swo
*.png
output/*
+test_output
*.db-journal
+.tmp
View
@@ -1,4 +1,4 @@
-#!/usr/bin/perl5.11.0
+#!/usr/bin/env perl
# بسم الله الرحمن الرحيم
# In the name of Allah, Most Gracious, Most Merciful
@@ -21,10 +21,13 @@
use GD;
use GD::Text;
use GD::Text::Align;
+#use GD::Text::Wrap;
use Getopt::Long;
use Pod::Usage;
use List::Util qw/min max/;
+# we're using Phi because the height/width and width/height ratios of text
+# from pages from a madani mushaf are approximately 1.61 and 0.61, respectively
use constant PHI => ((sqrt 5) + 1) / 2;
use constant phi => (((sqrt 5) + 1) / 2) - 1;
@@ -34,22 +37,22 @@
my $dbh = DBI->connect("dbi:SQLite2:dbname=./data/madani.sqlite2.db","","",
{ RaiseError => 1, AutoCommit => 0 });
-my ($page, $batch, $width, $em, $help) = (undef, undef, undef, 1.0, 0);
+my ($page, $batch, $width, $scale, $help) = (undef, undef, undef, 1.0, 0);
GetOptions(
'page=i' => \$page,
'batch' => \$batch,
'width:i' => \$width,
- 'em:f' => \$em,
+ 'scale:f' => \$scale,
'help|?' => \$help,
) or pod2usage(1);
pod2usage(1) if $help;
-$em = sprintf('%.1f',$em);
+$scale = sprintf('%.1f',$scale);
+my $height = $width * PHI;
-die "Minimal parameters are --width and --page for a single page, or \
-use --width and --batch to generate images for the entire Qur'an"
- unless ($width and ($batch or $page));
+die "Minimal parameters are --width and --page for a single page, or --width \
+ and --batch for the entire Qur'an" unless $width and ($batch or $page);
if ($batch) {
$self->generate_batch;
@@ -59,138 +62,135 @@
}
sub generate_batch {
- for (my $i=1; $i<=604; $i++){
- print "processing page $i...\n";
- $self->generate_page($i);
+ for (my $page = 1; $page <= 604; $page++) {
+ print "Generating page $page...\n";
+ $self->generate_page($page);
}
}
sub generate_page {
my ($self, $page) = @_;
- my %data = ();
+ my $hash = {};
my $longest_line = 0;
- my $longest_width = 0;
- my $page_v = sprintf('%03d', $page);
+ my $longest_line_width = 0;
+ my $page_str = sprintf('%03d', $page);
my $sth = $dbh->prepare(
"select line, ayah, text from madani_page_text where page=$page");
- $sth->execute();
- while (my $row = $sth->fetchrow_hashref){
- my @vals = ();
- push(@vals, $row->{ayah});
- push(@vals, $self->_reverse_text($row->{text}));
- $data{$row->{line}} = \@vals;
- my $ayah_w = $self->_get_line_width($vals[1], $page_v, 24);
- if ($ayah_w > $longest_width){
- $longest_width = $ayah_w;
- $longest_line = $row->{line};
+
+ $sth->execute;
+ while (my ($line, $ayah, $text) = $sth->fetchrow_array) {
+ $text = $self->_reverse_text($text);
+
+ $hash->{$line} = [$ayah, $text];
+ my $line_width = $self->_get_line_width($text, $page_str, 24);
+ # 24 is an arbitrary font size because we're simply testing to find the longest line
+
+ if ($line_width > $longest_line_width) {
+ $longest_line = $line;
+ $longest_line_width = $line_width;
}
}
- $sth->finish();
- my @ll = @{$data{$longest_line}};
- (my $font_size, $longest_width) =
- $self->_get_best_font_size($ll[1], $page_v, $longest_width);
-
- my $rows = keys(%data);
- my $sub_phi = 1 + (phi * phi * phi);
- my $line_spacing = $font_size * $sub_phi;
- my $padding = $font_size * phi + ($font_size * phi * phi * phi);
- my $inner_width = $width - 2 * $padding;
- my $height = $rows * $font_size + ($rows - 1) * $line_spacing + 2 * $padding;
-
- #print "longest_width: $longest_width, width: $width, height: $height\n";
- my $gd = GD::Image->new($width, $height);
+ $sth->finish;
+
+ my ($ayah, $text) = @{$hash->{$longest_line}};
+ (my $font_size, $longest_line_width) =
+ $self->_get_best_font_size($text, $page_str, $longest_line_width);
+
+ my $line_spacing = ($height - 15 * $font_size) / 15; # testing a hypothesis
+
+ my $gd = GD::Image->new($width, $height + $line_spacing / 2);
my $white = $gd->colorAllocateAlpha(255, 255, 255, 127);
my $black = $gd->colorAllocate(0, 0, 0);
+
$gd->transparent($white);
- $gd->interlaced('true');
+ $gd->interlaced('false'); # save some kB
my $_draw_line = sub {
my ($i, $ayah, $text) = @_;
my $align = GD::Text::Align->new(
- $gd, valign => 'top', halign => 'right', color => $black);
+ $gd, valign => 'center', halign => 'center', color => $black);
if ((!$ayah) || ($ayah == 0)){
- $align->set_font("./data/fonts/QCF_BSML.TTF", $font_size);
+ $align->set_font("./data/fonts/QCF_BSML.TTF", $font_size - 1);
}
else {
- $align->set_font("./data/fonts/QCF_P$page_v.TTF", $font_size);
+ $align->set_font("./data/fonts/QCF_P$page_str.TTF", $font_size - 1);
}
$align->set_text($text);
- my $coord_x = $inner_width + 2 * $padding;
- my $coord_y = $padding * phi + $i * ($font_size + $line_spacing);
- $coord_y = $i * ($font_size + $line_spacing);
+ my $coord_x = $width / 2;
+ my $coord_y = $i * ($font_size + $line_spacing) + $line_spacing;
my @box = $align->bounding_box($coord_x, $coord_y, 0);
- $coord_y += $padding / 2;
- my $min_2_4 = min($box[2], $box[4]);
- my $max_2_4 = max($box[2], $box[4]);# - 5;
- my $avg_2_4 = ($min_2_4 + $max_2_4) / 2;
- $coord_x += $width - $max_2_4 - ($padding / 7);
- if ($coord_x > $width) {
- my $diff = $coord_x - $width;
- $coord_x = $width - $diff;
- }
- my $align_get_width = $align->get('width');
- if ($align_get_width > $width - ($padding / 7)) {
- my $diff = $align_get_width - ($width - ($padding / 7));
- $coord_x += $diff;
- }
- #print "coord_x: $coord_x, coord_y: $coord_y, padding? $padding, width? ". $align->get('width') ."\n";
$align->draw($coord_x, $coord_y, 0);
};
- for my $key (sort { $a <=> $b } keys(%data)){
- my $ayah = @{$data{$key}}[0];
- my $line = @{$data{$key}}[1];
- $_draw_line->($key-1, $ayah, @{$data{$key}}[1]);
+ for my $line (sort { $a <=> $b } keys %{ $hash }) {
+ my $ayah = @{$hash->{$line}}[0];
+ my $text = @{$hash->{$line}}[1];
+ $_draw_line->($line - 1, $ayah, $text);
}
my $path = "./output/width_$width/";
eval { `mkdir -p $path` };
- open OUTPUT, ">$path/$page_v.png";
+ open OUTPUT, ">$path/$page_str.png";
binmode OUTPUT;
- print OUTPUT $gd->png(0); # 0 is highest quality
+ print OUTPUT $gd->png(9); # 0 is highest quality, 9 is highest compression level
} # sub generate_page
sub _get_best_font_size {
- my ($self, $text, $page, $longest_width) = @_;
+ my ($self, $text, $page, $longest_line_width) = @_;
- my $font_step = 1;
+ my $font_step = 2;
my $font_size = 24;
- my $line_width = $longest_width;
+ my $line_width = $longest_line_width;
- if ($longest_width > $width){
- $font_step = -1;
- while ($line_width > $width){
+ # line width is greater than desired width
+ if ($longest_line_width > $width) { # here the variable $width refers to the global--needs refactoring to be more clear
+ $font_step = -2;
+ while ($line_width > $width) {
$font_size += $font_step;
$line_width = $self->_get_line_width($text, $page, $font_size);
- }
+ } # keep going until line_width < width
return ($font_size, $line_width);
}
- else {
+ else { # line width is less than desired width
my $prev_line_width = 0;
while ($line_width < $width){
$font_size += $font_step;
$prev_line_width = $line_width;
$line_width = $self->_get_line_width($text, $page, $font_size);
- }
- return ($font_size-$font_step, $prev_line_width);
+ } # keep going until line_width > width
+ # and then return the line_width just before we stepped over width
+ return ($font_size - $font_step, $prev_line_width);
}
} # sub _get_best_font_size
sub _get_line_width {
my ($self, $text, $page, $font_size) = @_;
+
my $gd = GD::Text->new() or die GD::Text::error();
+
$gd->set_font("./data/fonts/QCF_P$page.TTF", $font_size) or die $gd->error;
$gd->set_text($text);
my $gdi = GD::Image->new($gd->get('width'), $gd->get('height'));
- my $align = GD::Text::Align->new($gdi, valign => 'top', halign => 'right');
+ my $align = GD::Text::Align->new($gdi, valign => 'center', halign => 'center');
$align->set_font("./data/fonts/QCF_P$page.TTF", $font_size);
$align->set_text($text);
my @box = $align->bounding_box(0, 0, 0);
+ # returns:
+ # 0 1 2 3 4 5 6 7
+ # x1, y1, x2, y2, x3, y3, x4, y4
+ # (x1,y1) lower left corner
+ # (x2,y2) lower right corner
+ # (x3,y3) upper right corner
+ # (x4,y4) upper left corner
+
- my $line_width = max($box[2], $box[4]) - max($box[0], $box[6]);
+ # max of lower right corner's x versus upper right corner's x
+ # minus
+ # min of lower left corner's x verses upper left corner's x
+ my $line_width = max($box[2], $box[4]) - min($box[0], $box[6]);
return $line_width;
} # sub _get_line_width
@@ -220,7 +220,7 @@ =head1 OPTIONS
-p --page page number to process
-b --batch process the entire Qur'an in one shot
-w --width width of image in pixels
- -e --em scale font size by given factor - overrides width
+ -s --scale scale font size by given factor - overrides width
-h --help print this help message and exit
e.g. './generate.quran.page.pl -p 23 --width=480' would output page 4

0 comments on commit a9b677e

Please sign in to comment.