3

I have a djvu scan of a book. Let's consider two cases:

  1. I'd like to number the pages 0, 1, 2, ... (usage case: the cover should get be page 0)

  2. I'd like to number some pages with Roman numbers and some with Arabic numbers, for example: i, ii, iii, ..., x, 1, 2, 3, ... (usage case: some introductory pages are numbered Roman in the book)

Is it possible to do it on Linux?

marmistrz
  • 2,732
  • 4
  • 23
  • 30
  • Whatever the platform, this will require a specific tool that works with lowlevel djvu specification. Just hope there is a `djvulibre` expert here. – orion Jun 17 '15 at 09:11

2 Answers2

2

It's possible, but if you have to ask it's unlikely to be very useful to you. You'll need a script that produces a sequence of set-page-title commands like this:

select 1; set-page-title "Cover"
select 2; set-page-title "i"
select 3; set-page-title "ii"
select 4; set-page-title "iii"
select 5; set-page-title "1"
select 6; set-page-title "2"
select 7; set-page-title "3"
select 8; set-page-title "4"
select 9; set-page-title "5"
select 10; set-page-title "6"
...

You have to pipe the output of the script to djvused to commit the changes to your DjVu file:

djvu_pagination | djvused -f - -s file.djvu

Beware however that you have only once chance at this, if you get the numbers wrong you won't be able to run the same command again, you'll have to reset logical page numbers by referencing the component names. That goes something like this:

select "all_24223_to_00243.cpc.djvu"; set-page-title "all_24223_to_00243.cpc.djvu"
select "all_24223_to_00243.cpc0002.djvu"; set-page-title "all_24223_to_00243.cpc0002.djvu"
select "all_24223_to_00243.cpc0003.djvu"; set-page-title "all_24223_to_00243.cpc0003.djvu"
select "all_24223_to_00243.cpc0004.djvu"; set-page-title "all_24223_to_00243.cpc0004.djvu"
select "all_24223_to_00243.cpc0005.djvu"; set-page-title "all_24223_to_00243.cpc0005.djvu"
...

You'd then pipe these commands to djvused as above:

djvu_reset_pagination | djvused -f - -s file.djvu

Once upon a time people used to have scripts to handle all that. Those days are now long gone.

lcd047
  • 7,160
  • 1
  • 22
  • 33
  • I have had no problems reusing the same type of commands again, but the instructions for resetting logical page numbers don't hurt anyway. – hife Apr 04 '20 at 12:59
  • Note: ``echo "select "$iTOTAL"; set-page-title \""$iROMAN"\""`` is bad syntax. You are quoting the literal strings (which don’t *need* to be quoted) and leaving the shell variables (which should always be quoted) unquoted. – G-Man Says 'Reinstate Monica' Apr 04 '20 at 20:36
  • @lcd047 "Once upon a time people used to have scripts to handle all that. Those days are now long gone." I am intrigued by this statement; who were these DJVU adepts? Why are those days long gone? Is there a history recorded somewhere? – Nathaniel M. Beaver May 17 '21 at 12:24
  • 1
    @NathanielM.Beaver _who were these DJVU adepts?_ - Mostly [pirates](https://en.wikipedia.org/wiki/Library.nu) (allegedly). _Why are those days long gone?_ - Because people chose PDF instead, which had professionally-written editing tools, and the backing of the industry, while DjVu had been abandoned by its creators. – lcd047 May 17 '21 at 13:12
0

Update March 2021: Updated script + skipping pages

(adapted from lcd047's answer)

Create a backup copy of your .djvu file in case something goes wrong.

Install the numconv package from here.

Save the following as a text file e.g. generate_page_list.sh:

#!/bin/bash

## Set these parameters:
# Name first/last page $CNAME/$BCNAME? (Yes/No=0/1)
COVER=1
BCOVER=0
CNAME="C"
BCNAME="BC"
# Lowest roman page number 
MINROMAN=3
# Highest roman page number
MAXROMAN=6
# Lowest arabic page number
MINARABIC=1
# Highest arabic page number
MAXARABIC=10

# Create/Empty new_page_list
> new_page_list
# Initialise total page number iTOTAL
iTOTAL=1
# Generate list of set-page-title commands
if [[ "$COVER" == 1 ]]; then
    echo "select $iTOTAL; set-page-title \"$CNAME\"" >> new_page_list
    ((iTOTAL++))
fi

for (( i=$MINROMAN; i<=$MAXROMAN; i++)); do
    iROMAN=`echo $i | numconv -f Western -t Roman_Lower`
    echo "select $iTOTAL; set-page-title \"$iROMAN\"" >> new_page_list
    ((iTOTAL++))
done

for (( i=$MINARABIC; i<=$MAXARABIC; i++)); do
    echo "select $iTOTAL; set-page-title \"$i\"" >> new_page_list
    ((iTOTAL++))
done

if [[ "$BCOVER" == 1 ]]; then
    echo "select $iTOTAL; set-page-title \"$BCNAME\"" >> new_page_list
    ((iTOTAL++))
fi

Make generate_page_list.sh executable via

chmod +x generate_page_list.sh

Run the script via

./generate_page_list.sh

This produces a file new_page_list. Open this file in a text editor to check it contains a sequence of set-page-title commands like this:

select 1; set-page-title "Cover"
select 2; set-page-title "i"
select 3; set-page-title "ii"
select 4; set-page-title "iii"
select 5; set-page-title "1"
select 6; set-page-title "2"
select 7; set-page-title "3"
select 8; set-page-title "4"
select 9; set-page-title "5"
select 10; set-page-title "6"
...

Pass this list to djvused to commit the changes to your DjVu file:

djvused -f new_page_list -s file.djvu

Script with skipped pages

If your .djvu files has missing pages (e.g. empty pages left out when skanning), you can use the following extension of the above skript:

#!/bin/bash

## Set these parameters:
# Name first/last page $CNAME/$BCNAME? (Yes/No=0/1)
COVER=1
BCOVER=0
CNAME="C"
BCNAME="BC"
# Lowest roman page number 
MINROMAN=3
# Highest roman page number
MAXROMAN=6
# Skipped roman page numbers 
SKIPROMAN=""
# Lowest arabic page number
MINARABIC=1
# Highest arabic page number
MAXARABIC=10
# Skipped arabic page numbers
SKIPARABIC="3 5"

# Create/Empty new_page_list
> new_page_list
# Initialise total page number iTOTAL
iTOTAL=1
# Generate list of set-page-title commands
if [[ "$COVER" == 1 ]]; then
    echo "select $iTOTAL; set-page-title \"$CNAME\"" >> new_page_list
    ((iTOTAL++))
fi

for (( i=$MINROMAN; i<=$MAXROMAN; i++)); do
    if [[ ! " $SKIPROMAN " =~ " $i " ]]; then
        iROMAN=`echo $i | numconv -f Western -t Roman_Lower`
        echo "select $iTOTAL; set-page-title \"$iROMAN\"" >> new_page_list
        ((iTOTAL++))
    fi
done

for (( i=$MINARABIC; i<=$MAXARABIC; i++)); do
    if [[ ! " $SKIPARABIC " =~ " $i " ]]; then
        echo "select $iTOTAL; set-page-title \"$i\"" >> new_page_list
        ((iTOTAL++))
    fi
done

if [[ "$BCOVER" == 1 ]]; then
    echo "select $iTOTAL; set-page-title \"$BCNAME\"" >> new_page_list
    ((iTOTAL++))
fi

SKIPARABIC (resp. SKIPROMAN) is a string containing a list of page numbers to be skipped, separated by spaces. You can, for example, enter numbers individually:

SKIPARABIC="3 4"

or as a range

SKIPARABIC="{3..5}"

or a combination of one or more numbers and ranges (again separated by spaces

SKIPARABIC="{3..5} 7 {9..15}"

I am using string comparison (according to this stackoverflow answer), which may not be the most efficient, but it was the easiest and most readable solution I could find for skipping iterations in a loop according to a list.

hife
  • 103
  • 3