View Single Post
Old 01-02-2010, 11:51 AM   #1
Jellby
frumious Bandersnatch
Jellby ought to be getting tired of karma fortunes by now.Jellby ought to be getting tired of karma fortunes by now.Jellby ought to be getting tired of karma fortunes by now.Jellby ought to be getting tired of karma fortunes by now.Jellby ought to be getting tired of karma fortunes by now.Jellby ought to be getting tired of karma fortunes by now.Jellby ought to be getting tired of karma fortunes by now.Jellby ought to be getting tired of karma fortunes by now.Jellby ought to be getting tired of karma fortunes by now.Jellby ought to be getting tired of karma fortunes by now.Jellby ought to be getting tired of karma fortunes by now.
 
Jellby's Avatar
 
Posts: 7,516
Karma: 18512745
Join Date: Jan 2008
Location: Spaniard in Sweden
Device: Cybook Orizon, Kobo Aura
Script to generate thumbnails

With the new 2.0 update, I noticed the format for the thumbnails has changed, they are not .t2b files anymore, but .thn. And since there are still some issues with margins and ePUB, I thought I would like to generate the thumbnails myself instead of letting the Cybook do it itself.

The thumbnail format is quite simple: just a "t4bp" header and then the pixel data with 4 bits per pixel (two pixels per byte). The thumbnail size is 96x144 pixels, as before.

I've created this Perl script (tested on Linux only, but should work anywhere with Perl and ImageMagick), that replaces the t2b.pl script I had before. Just use it with:

Code:
./thn.pl coverfile
where "coverfile" is a picture file with the cover, in any format supported by ImageMagick. It needs a palette file (I'll come to this in moment) called "palette.pgm", with 4 or 8 colours; it will create a "coverfile_6090.t2b" (old format) if it's 4 colours, and a "coverfile.thn" (new format) if it's 8 colours.

The palette file is just a simple "plain" PGM file with the grey levels to be used in the thumbnail. For best results, one should use the real brightness of the real grey levels of the Cybook, but I just used evenly distributed grey levels. examples:

Palette file for 4 grey levels (t2b thumbnails):
Code:
P2
1 4
255
32 96 160 224
Palette file for 8 grey levels (thn thumbnails, Cybook Gen3 Gold):
Code:
P2
1 8
255
16 48 80 112 144 176 208 240
Palette file for 4 grey levels but working like 8 (thn thumbnails, other Cybook models)
Code:
P2
1 8
255
32 96 96 160 160 160 224 224
(This last file should give better results for the Cybooks that can only display 4 grey levels. Note that they will read thumbnails with 8 grey levels (or even 16) without problem, but some details will be lost. By giving only 4 distinct colours in the palette ImageMagick will perform better dithering).

Just choose the palette file you want (or make your own), place it in the same directory as the thn.pl script, and you should be done. There is, of course, much room for improvement, it could read the cover image directly from .epub files, for instance... but that'll have to wait.

And this is the script:

thn.pl
Code:
#!/usr/bin/perl

use strict;

my $palette = $0;
my $width = 96;
my $height = 144;
my $size = $width."x".$height;
$palette =~ s/[^\/]+$/palette.pgm/;
my %pal;

# Read the palette file
open PALETTE, "<", $palette;
<PALETTE>;
my ($n, $m) = split / */, <PALETTE>;
my $colors = $n*$m;
<PALETTE>;
my $palstr = join( '', <PALETTE> );
$palstr =~ s/\s+/ /g;
$palstr =~ s/^\s+//;
close PALETTE;
my $i = 0;
# Build the table mapping input levels to output levels
foreach ( split / /, $palstr ) {
  $pal{$_}=$i++;
}

# Convert the file with ImageMagick
open PGM, "convert $ARGV[0] -resize $size -map \"${palette}\" -bordercolor white -border $size -gravity center -crop $size+0+0 -strip -compress none PGM:- |";
<PGM>;
<PGM>;
<PGM>;
my $pgmstr = join( '', <PGM> );
$pgmstr =~ s/\s+/ /g;
$pgmstr =~ s/^\s+//;
close PGM;
my @pgm = split / /, $pgmstr;
# Map input levels to output levels
for ( my $i=0; $i<=$#pgm; $i++ ) {
  $pgm[$i] = $pal{$pgm[$i]};
}

if ( $colors == 8 ) {
  open OUT, ">", "$ARGV[0].thn";
  print OUT "t4bp";
  my $k = 2; #pixels per byte
  for ( my $i=0; $i<=$#pgm; $i=$i+$k ) {
    my $px = 0;
    for ( my $j=0; $j<$k; $j++ ) {
      $px = 16*$px + int($pgm[$i+$j]*15/7+0.5);
    }
    print OUT chr($px);
  }
} elsif ( $colors == 4 ) {
  my $output = $ARGV[0];
  $output =~ s/\..+?$/_6090.t2b/;
  open OUT, ">", $output;
  my $k = 4; #pixels per byte
  for ( my $i=0; $i<=$#pgm; $i=$i+$k ) {
    my $px = 0;
    for ( my $j=0; $j<$k; $j++ ) {
      $px = 4*$px + $pgm[$i+$j];
    }
    print OUT chr($px);
  }
}
close OUT;

exit 0;

# Write a PGM file (debug)
#  comment the "exit 0" line above to get it
open OUT, ">", "$ARGV[0].pgm";
print OUT "P2\n$width $height\n";
print OUT $colors-1;
print OUT "\n";
foreach ( @pgm ) {
  print OUT "$_ ";
}
close OUT;
EDIT: I've changed the palette files, the level distribution gives better results now.

Last edited by Jellby; 01-06-2010 at 07:03 AM.
Jellby is offline   Reply With Quote