Scantailor images to PDF for POD services on Linux

Share your software workflow. Write up your tips and tricks on how to scan, digitize, OCR, and bind ebooks.

Moderator: peterZ

Post Reply
abmartin
Posts: 79
Joined: 15 Sep 2010, 15:33
Number of books owned: 2000
Country: USA
Location: Ohio

Scantailor images to PDF for POD services on Linux

Post by abmartin »

Print On Demand services require PDF files in specific page sizes. Scantailor, does not have the option of creating a specfic size. Here's how I add margins to Scantailor output and make PDFs to submit to Lulu or another POD service. A key to this process is to make the inner margins larger than the outer. It is necessary, because the loss of space in the gutter of a printed book. In this tutorial, I have used an extra half inch in the inner margin.

Software used: libtiff-tools and imagemagick (debian package names -- in other distros, it's just libtiff)

All commands are run from the directory in which the output files are located. My files are numbered. The image sizes listed in my commands are if the images are 600 DPI. Adjust as necessary. While it may look complicated, the commands can be run with a single command if placed in a shell script for each page size. Try doing that with Acrobat with a single command!(A more elegand solution would be to add input variables when running the script, but I've never taken the time to do it)

Steps 1 and 5 are optional. I prefer to do them, because I like to preserve the original scantailor output.

1. copy output to a temporary folder
$mkdir print && cp *.tif print && cd print

2. create even and odd folders and move images into them before processing
$mkdir evens odds && mv *[02468].tif evens && mv *[13579].tif odds

3. using imagemagick, add margins to even and odd images with a larger inner margin. (This example is a 6"x9" target size, with an extra half inch in the gutter. Adjust variables as necessary)
$cd odds && mogrify -verbose -gravity center -extent 3300x5400 -gravity east -extent 3600x5400 *.tif && mv *.tif .. && cd .. && cd evens && mogrify -verbose -gravity center -extent 3300x5400 -gravity west -extent 3600x5400 *.tif && mv *.tif .. && cd .. && rmdir evens odds

4. using libtif, make a pdf file of the now correctly-sized images
$tiffcp *.tif print.tif && tiff2pdf -o print.pdf print.tif

5. clean temporary files and move pdf to original directory
$rm *.tif && mv print.pdf .. && cd .. && rmdir print


Pocket 4.25"x6.875" (2550x4125)
mkdir print && cp *.tif print && cd print && mkdir evens odds && mv *[02468].tif evens && mv *[13579].tif odds && cd odds && mogrify -verbose -gravity center -extent 2250x4125 -gravity east -extent 2550x4125 *.tif && mv *.tif .. && cd .. && cd evens && mogrify -verbose -gravity center -extent 2250x4125 -gravity west -extent 2550x4125 *.tif && mv *.tif .. && cd .. && rmdir evens odds && tiffcp *.tif print.tif && tiff2pdf -o print.pdf print.tif && rm *.tif && mv print.pdf .. && cd .. && rmdir print

A5 5.833"x8.264" (3500x4958)
mkdir print && cp *.tif print && cd print && mkdir evens odds && mv *[02468].tif evens && mv *[13579].tif odds && cd odds && mogrify -verbose -gravity center -extent 3200x4958 -gravity east -extent 3500x4958 *.tif && mv *.tif .. && cd .. && cd evens && mogrify -verbose -gravity center -extent 3200x4958 -gravity west -extent 3500x4958 *.tif && mv *.tif .. && cd .. && rmdir evens odds && tiffcp *.tif print.tif && tiff2pdf -o print.pdf print.tif && rm *.tif && mv print.pdf .. && cd .. && rmdir print

Trade 6"x9" (3600x5400)
mkdir print && cp *.tif print && cd print && mkdir evens odds && mv *[02468].tif evens && mv *[13579].tif odds && cd odds && mogrify -verbose -gravity center -extent 3300x5400 -gravity east -extent 3600x5400 *.tif && mv *.tif .. && cd .. && cd evens && mogrify -verbose -gravity center -extent 3300x5400 -gravity west -extent 3600x5400 *.tif && mv *.tif .. && cd .. && rmdir evens odds && tiffcp *.tif print.tif && tiff2pdf -o print.pdf print.tif && rm *.tif && mv print.pdf .. && cd .. && rmdir print

Royal 6.139"x9.21" (3683x5526)
mkdir print && cp *.tif print && cd print && mkdir evens odds && mv *[02468].tif evens && mv *[13579].tif odds && cd odds && mogrify -verbose -gravity center -extent 3383x5526 -gravity east -extent 3683x5526 *.tif && mv *.tif .. && cd .. && cd evens && mogrify -verbose -gravity center -extent 3383x5526 -gravity west -extent 3683x5526 *.tif && mv *.tif .. && cd .. && rmdir evens odds && tiffcp *.tif print.tif && tiff2pdf -o print.pdf print.tif && rm *.tif && mv print.pdf .. && cd .. && rmdir print

Crown Quarto 7.444"x9.681" (4466x5809)
mkdir print && cp *.tif print && cd print && mkdir evens odds && mv *[02468].tif evens && mv *[13579].tif odds && cd odds && mogrify -verbose -gravity center -extent 4166x5809 -gravity east -extent 4466x5809 *.tif && mv *.tif .. && cd .. && cd evens && mogrify -verbose -gravity center -extent 4166x5809 -gravity west -extent 4466x5809 *.tif && mv *.tif .. && cd .. && rmdir evens odds && tiffcp *.tif print.tif && tiff2pdf -o print.pdf print.tif && rm *.tif && mv print.pdf .. && cd .. && rmdir print

Comic 6.625"x10.25" (3975x6150)
mkdir print && cp *.tif print && cd print && mkdir evens odds && mv *[02468].tif evens && mv *[13579].tif odds && cd odds && mogrify -verbose -gravity center -extent 3675x6150 -gravity east -extent 3975x6150 *.tif && mv *.tif .. && cd .. && cd evens && mogrify -verbose -gravity center -extent 3675x6150 -gravity west -extent 3975x6150 *.tif && mv *.tif .. && cd .. && rmdir evens odds && tiffcp *.tif print.tif && tiff2pdf -o print.pdf print.tif && rm *.tif && mv print.pdf .. && cd .. && rmdir print

Letter 8.5"x11" (5100x6600)
mkdir print && cp *.tif print && cd print && mkdir evens odds && mv *[02468].tif evens && mv *[13579].tif odds && cd odds && mogrify -verbose -gravity center -extent 4800x6600 -gravity east -extent 5100x6600 *.tif && mv *.tif .. && cd .. && cd evens && mogrify -verbose -gravity center -extent 4800x6600 -gravity west -extent 5100x6600 *.tif && mv *.tif .. && cd .. && rmdir evens odds && tiffcp *.tif print.tif && tiff2pdf -o print.pdf print.tif && rm *.tif && mv print.pdf .. && cd .. && rmdir print

A4 8.264"x11.694" (4958x7016)
mkdir print && cp *.tif print && cd print && mkdir evens odds && mv *[02468].tif evens && mv *[13579].tif odds && cd odds && mogrify -verbose -gravity center -extent 4658x7016 -gravity east -extent 4958x7016 *.tif && mv *.tif .. && cd .. && cd evens && mogrify -verbose -gravity center -extent 4658x7016 -gravity west -extent 4958x7016 *.tif && mv *.tif .. && cd .. && rmdir evens odds && tiffcp *.tif print.tif && tiff2pdf -o print.pdf print.tif && rm *.tif && mv print.pdf .. && cd .. && rmdir print
User avatar
daniel_reetz
Posts: 2812
Joined: 03 Jun 2009, 13:56
E-book readers owned: Used to have a PRS-500
Number of books owned: 600
Country: United States
Contact:

Re: Scantailor images to PDF for POD services on Linux

Post by daniel_reetz »

Wow, great tutorial. Thank you for taking the time to write this up.
abmartin
Posts: 79
Joined: 15 Sep 2010, 15:33
Number of books owned: 2000
Country: USA
Location: Ohio

Re: Scantailor images to PDF for POD services on Linux

Post by abmartin »

Since Scantailor-Experimental no longer works with DPI, a couple of changes are necessary for this. I just hacked out a little script that will do all of the work for you to get the images to print sizes. I've included two versions, one with a step for you to input the DPI and one for files with DPI already embedded if you haven't jumped over to experimental.

The first script will ask for the DPI, tell you the size of your image, ask for you to select a target print size from a list, and offer you a custom choice for extending the inner margin based on the available space. If you intend to print a book to have bound or hole punched, I'd make sure you have a half-inch of margin in the gutter so things don't get cut off. By scripting it, there is no longer any math required, which would have gotten old now that scantailor images will come out with different DPIs for different books. I used all page sizes that Lulu.com currently offers. Your original images are changed only by changing their DPI, the resized images are temporary and will be deleted upon completion of the final PDF. If you don't want the DPI info to be written into your original files, just move lines 189-191 to the beginning. (mkdir print, cp *.tif print, cd print)

Prereqs: Imagemagick and Libtiff (libtiff-tools in some distros)
The script is looking for images with number endings. Odd-numbered pages are the recto, evens the verso. There is a single configuration option for the name of the first image, which the script uses to determine size and, in the second version, DPI. The default is just 001.tif.

There are no errors messages, no logging, no nothing. If you ask it to do something that it can't do, like asking for a page size that's too small or an inner margin too big, it's not going to work. Standard no warranty disclaimer applies...

Script for Scantailor-Experimental

Code: Select all

#!/bin/bash

##Scantailor-Experimental to Sized POD pdf

##Configuration
FIRST_IMAGE=001.tif #Name of first image in directory with extension

##Print Sizes
POCKET_WIDTH=4.25
POCKET_HEIGHT=6.88

DIGEST_WIDTH=5.5
DIGEST_HEIGHT=8.5

A5_WIDTH=5.83
A5_HEIGHT=8.26

TRADE_WIDTH=6
TRADE_HEIGHT=9

ROYAL_WIDTH=6.14
ROYAL_HEIGHT=9.21

COMIC_WIDTH=6.63
COMIC_HEIGHT=10.25

CROWN_QUARTO_WIDTH=7.44
CROWN_QUARTO_HEIGHT=9.68

SMALL_SQUARE_WIDTH=7.5
SMALL_SQUARE_HEIGHT=7.5

LETTER_HARDCOVER_WIDTH=8.25
LETTER_HARDCOVER_HEIGHT=10.75

A4_WIDTH=8.26
A4_HEIGHT=11.69

SQUARE_WIDTH=8.5
SQUARE_HEIGHT=8.5

LETTER_WIDTH=8.5
LETTER_HEIGHT=11

LANDSCAPE_WIDTH=9
LANDSCAPE_HEIGHT=7

##Manually input DPI of processed images
echo -e "\nEnter DPI of Processed Images: "
read INPUT_DPI

##Apply INPUT_DPI to images using mogrify
echo -e "\nApplying $INPUT_DPI DPI to images..."
mogrify -density $INPUT_DPI -units PixelsPerInch *.tif
echo -e "Done"

##Use Imagemagick to determine image dimensions
PAGE_WIDTH=$(convert $FIRST_IMAGE -format %[fx:w] info:)
PAGE_HEIGHT=$(convert $FIRST_IMAGE -format %[fx:h] info:)

##Using Dimensions and DPI, calculate image size
PAGE_WIDTH_INCHES=$(echo "scale=3; $PAGE_WIDTH/$INPUT_DPI" | bc)
PAGE_HEIGHT_INCHES=$(echo "scale=3; $PAGE_HEIGHT/$INPUT_DPI" | bc)

echo -e "\nYour images are $PAGE_WIDTH_INCHES x $PAGE_HEIGHT_INCHES inches"

##Prompt for destination size

echo -e "\nChoose a target paper size larger than your image: "
options=("Pocket: 4.25x6.88" "Digest: 5.5x8.5" "A5: 5.83x8.26" "Trade: 6x9" "Royal: 6.14x9.21" "Comic: 6.63x10.25" "Crown Quarto: 7.44x9.68" "Small Sqaure: 7.5x7.5" "Letter Hardcover: 8.25x10.75" "A4: 8.26x11.69" "Square: 8.5x8.5" "Letter: 8.5x11" "Landscape: 9x7" "Quit")
select opt in "${options[@]}"
do
    case $opt in
        "Pocket: 4.25x6.88")
            echo "You chose Pocket"
            WIDTH=$POCKET_WIDTH
            HEIGHT=$POCKET_HEIGHT
            SIZE=Pocket
            break
            ;;
        "Digest: 5.5x8.5")
            echo "You chose Digest"
            WIDTH=$DIGEST_WIDTH
            HEIGHT=$DIGEST_HEIGHT
            SIZE=Digest
            break         
            ;;
        "A5: 5.83x8.26")
            echo "You chose A5"
            WIDTH=$A5_WIDTH
            HEIGHT=$A5_HEIGHT
            SIZE=A5
            break
            ;;
        "Trade: 6x9")
            echo "You chose Trade"   
            WIDTH=$TRADE_WIDTH
            HEIGHT=$TRADE_HEIGHT     
            SIZE=Trade
            break
            ;;            
        "Royal: 6.14x9.21")
            echo "You chose Royal"
            WIDTH=$ROYAL_WIDTH
            HEIGHT=$ROYAL_HEIGHT
            SIZE=Royal
            break
            ;;
        "Comic: 6.63x10.25")
            echo "You chose Comic"
            WIDTH=$COMIC_WIDTH
            HEIGHT=$COMIC_HEIGHT
            SIZE=Comic
            break
            ;;
        "Crown Quarto: 7.44x9.68")
            echo "You chose Crown Quarto"
            WIDTH=$CROWN_QUARTO_WIDTH
            HEIGHT=$CROWN_QUARTO_HEIGHT
            SIZE=CrownQuarto
            break
            ;;
        "Small Sqaure: 7.5x7.5")
            echo "You chose Small Square"
            WIDTH=$SMALL_SQUARE_WIDTH
            HEIGHT=$SMALL_SQUARE_HEIGHT
            SIZE=SmallSquare
            break
            ;;
        "Letter Hardcover: 8.25x10.75")
            echo "You chose Letter Hardcover"
            WIDTH=$LETTER_HARDCOVER_WIDTH
            HEIGHT=$LETTER_HARDCOVER_HEIGHT
            SIZE=LetterHardcover
            break
            ;;
        "A4: 8.26x11.69")
            echo "You chose A4"
            WIDTH=$A4_WIDTH
            HEIGHT=$A4_HEIGHT
            SIZE=A4
            break
            ;;
        "Square: 8.5x8.5")
            echo "You chose Square"
            WIDTH=$SQUARE_WIDTH
            HEIGHT=$SQUARE_HEIGHT
            SIZE=Square
            break
            ;;
        "Letter: 8.5x11")
            echo "You chose Letter"
            WIDTH=$LETTER_WIDTH
            HEIGHT=$LETTER_HEIGHT
            SIZE=Letter
            break
            ;;
        "Landscape: 9x7")
            echo "You chose Landscape"
            WIDTH=$LANDSCAPE_WIDTH
            HEIGHT=$LANDSCAPE_HEIGHT
            SIZE=Landscape
            break
            ;;
        "Quit")
            break
            ;;
        *) echo invalid option;;
    esac
done


##Calculate Target Sizes for Print Size

WIDTH_TARGET=$(awk "BEGIN {printf \"%.0f\n\", $WIDTH*$INPUT_DPI}")
HEIGHT_TARGET=$(awk "BEGIN {printf \"%.0f\n\", $HEIGHT*$INPUT_DPI}")

##Inner Margin Calculation
MAX_MARGIN=$(expr $WIDTH_TARGET - $PAGE_WIDTH)

##Prompt for Inner Margin Size
echo -e "\nEnter the number of pixels of inner margin you would like from 0-$MAX_MARGIN: "
read INNER_MARGIN

##Calculation for intermediate width
INTERMEDIATE_WIDTH_TARGET=$(expr $WIDTH_TARGET - $INNER_MARGIN)

##Make a temp folder; Copy images into temp folder; Copy Recto (odd #) and Verso (even #) images into seperate folders
mkdir print
cp *.tif print
cd print
mkdir evens odds
mv *[02468].tif evens
mv *[13579].tif odds

##Process Odd Images
echo -e "\nPreparing recto pages..."
cd odds
mogrify -gravity center -extent "$INTERMEDIATE_WIDTH_TARGET"x"$HEIGHT_TARGET" -gravity east -extent "$WIDTH_TARGET"x"$HEIGHT_TARGET" *.tif
mv *.tif ..
cd ..
echo -e "done"

##Process Even Images
echo -e "\nPreparing verso pages..."
cd evens
mogrify -gravity center -extent "$INTERMEDIATE_WIDTH_TARGET"x"$HEIGHT_TARGET" -gravity west -extent "$WIDTH_TARGET"x"$HEIGHT_TARGET" *.tif
mv *.tif ..
cd ..
echo -e "done"

##Clean temp folders
rmdir evens odds

##Using Libtiff to make PDF
echo -e "\nMaking PDF..."
tiffcp *.tif print.tif 
tiff2pdf -z -o Print-$SIZE.pdf print.tif
echo -e "done"

#Cleanup
mv Print-$SIZE.pdf ..
rm *.tif
cd ..
rmdir print

exit


And here's one for images with the DPI already determined (Scantailor-classic)

Code: Select all

#!/bin/bash

##Scantailor-Experimental to Sized POD pdf

##Configuration
FIRST_IMAGE=001.tif #Name of first image in directory with extension

##Print Sizes
POCKET_WIDTH=4.25
POCKET_HEIGHT=6.88

DIGEST_WIDTH=5.5
DIGEST_HEIGHT=8.5

A5_WIDTH=5.83
A5_HEIGHT=8.26

TRADE_WIDTH=6
TRADE_HEIGHT=9

ROYAL_WIDTH=6.14
ROYAL_HEIGHT=9.21

COMIC_WIDTH=6.63
COMIC_HEIGHT=10.25

CROWN_QUARTO_WIDTH=7.44
CROWN_QUARTO_HEIGHT=9.68

SMALL_SQUARE_WIDTH=7.5
SMALL_SQUARE_HEIGHT=7.5

LETTER_HARDCOVER_WIDTH=8.25
LETTER_HARDCOVER_HEIGHT=10.75

A4_WIDTH=8.26
A4_HEIGHT=11.69

SQUARE_WIDTH=8.5
SQUARE_HEIGHT=8.5

LETTER_WIDTH=8.5
LETTER_HEIGHT=11

LANDSCAPE_WIDTH=9
LANDSCAPE_HEIGHT=7

##Determine DPI from First Image
INPUT_DPI=$(identify -format "%x" $FIRST_IMAGE)
echo -e "\nThe DPI of your images is $INPUT_DPI"

##Use Imagemagick to determine image dimensions
PAGE_WIDTH=$(convert $FIRST_IMAGE -format %[fx:w] info:)
PAGE_HEIGHT=$(convert $FIRST_IMAGE -format %[fx:h] info:)

##Using Dimensions and DPI, calculate image size
PAGE_WIDTH_INCHES=$(echo "scale=3; $PAGE_WIDTH/$INPUT_DPI" | bc)
PAGE_HEIGHT_INCHES=$(echo "scale=3; $PAGE_HEIGHT/$INPUT_DPI" | bc)

echo -e "\nYour images are $PAGE_WIDTH_INCHES x $PAGE_HEIGHT_INCHES inches"

##Prompt for destination size

echo -e "\nChoose a target paper size larger than your image: "
options=("Pocket: 4.25x6.88" "Digest: 5.5x8.5" "A5: 5.83x8.26" "Trade: 6x9" "Royal: 6.14x9.21" "Comic: 6.63x10.25" "Crown Quarto: 7.44x9.68" "Small Sqaure: 7.5x7.5" "Letter Hardcover: 8.25x10.75" "A4: 8.26x11.69" "Square: 8.5x8.5" "Letter: 8.5x11" "Landscape: 9x7" "Quit")
select opt in "${options[@]}"
do
    case $opt in
        "Pocket: 4.25x6.88")
            echo "You chose Pocket"
            WIDTH=$POCKET_WIDTH
            HEIGHT=$POCKET_HEIGHT
            SIZE=Pocket
            break
            ;;
        "Digest: 5.5x8.5")
            echo "You chose Digest"
            WIDTH=$DIGEST_WIDTH
            HEIGHT=$DIGEST_HEIGHT
            SIZE=Digest
            break         
            ;;
        "A5: 5.83x8.26")
            echo "You chose A5"
            WIDTH=$A5_WIDTH
            HEIGHT=$A5_HEIGHT
            SIZE=A5
            break
            ;;
        "Trade: 6x9")
            echo "You chose Trade"   
            WIDTH=$TRADE_WIDTH
            HEIGHT=$TRADE_HEIGHT     
            SIZE=Trade
            break
            ;;            
        "Royal: 6.14x9.21")
            echo "You chose Royal"
            WIDTH=$ROYAL_WIDTH
            HEIGHT=$ROYAL_HEIGHT
            SIZE=Royal
            break
            ;;
        "Comic: 6.63x10.25")
            echo "You chose Comic"
            WIDTH=$COMIC_WIDTH
            HEIGHT=$COMIC_HEIGHT
            SIZE=Comic
            break
            ;;
        "Crown Quarto: 7.44x9.68")
            echo "You chose Crown Quarto"
            WIDTH=$CROWN_QUARTO_WIDTH
            HEIGHT=$CROWN_QUARTO_HEIGHT
            SIZE=CrownQuarto
            break
            ;;
        "Small Sqaure: 7.5x7.5")
            echo "You chose Small Square"
            WIDTH=$SMALL_SQUARE_WIDTH
            HEIGHT=$SMALL_SQUARE_HEIGHT
            SIZE=SmallSquare
            break
            ;;
        "Letter Hardcover: 8.25x10.75")
            echo "You chose Letter Hardcover"
            WIDTH=$LETTER_HARDCOVER_WIDTH
            HEIGHT=$LETTER_HARDCOVER_HEIGHT
            SIZE=LetterHardcover
            break
            ;;
        "A4: 8.26x11.69")
            echo "You chose A4"
            WIDTH=$A4_WIDTH
            HEIGHT=$A4_HEIGHT
            SIZE=A4
            break
            ;;
        "Square: 8.5x8.5")
            echo "You chose Square"
            WIDTH=$SQUARE_WIDTH
            HEIGHT=$SQUARE_HEIGHT
            SIZE=Square
            break
            ;;
        "Letter: 8.5x11")
            echo "You chose Letter"
            WIDTH=$LETTER_WIDTH
            HEIGHT=$LETTER_HEIGHT
            SIZE=Letter
            break
            ;;
        "Landscape: 9x7")
            echo "You chose Landscape"
            WIDTH=$LANDSCAPE_WIDTH
            HEIGHT=$LANDSCAPE_HEIGHT
            SIZE=Landscape
            break
            ;;
        "Quit")
            break
            ;;
        *) echo invalid option;;
    esac
done


##Calculate Target Sizes for Print Size

WIDTH_TARGET=$(awk "BEGIN {printf \"%.0f\n\", $WIDTH*$INPUT_DPI}")
HEIGHT_TARGET=$(awk "BEGIN {printf \"%.0f\n\", $HEIGHT*$INPUT_DPI}")

##Inner Margin Calculation
MAX_MARGIN=$(expr $WIDTH_TARGET - $PAGE_WIDTH)

##Prompt for Inner Margin Size
echo -e "\nEnter the number of pixels of inner margin you would like from 0-$MAX_MARGIN: "
read INNER_MARGIN

##Calculation for intermediate width
INTERMEDIATE_WIDTH_TARGET=$(expr $WIDTH_TARGET - $INNER_MARGIN)

##Make a temp folder; Copy images into temp folder; Copy Recto (odd #) and Verso (even #) images into seperate folders
mkdir print
cp *.tif print
cd print
mkdir evens odds
mv *[02468].tif evens
mv *[13579].tif odds

##Process Odd Images
echo -e "\nPreparing recto pages..."
cd odds
mogrify -gravity center -extent "$INTERMEDIATE_WIDTH_TARGET"x"$HEIGHT_TARGET" -gravity east -extent "$WIDTH_TARGET"x"$HEIGHT_TARGET" *.tif
mv *.tif ..
cd ..
echo -e "done"

##Process Even Images
echo -e "\nPreparing verso pages..."
cd evens
mogrify -gravity center -extent "$INTERMEDIATE_WIDTH_TARGET"x"$HEIGHT_TARGET" -gravity west -extent "$WIDTH_TARGET"x"$HEIGHT_TARGET" *.tif
mv *.tif ..
cd ..
echo -e "done"

##Clean temp folders
rmdir evens odds

##Using Libtiff to make PDF
echo -e "\nMaking PDF..."
tiffcp *.tif print.tif 
tiff2pdf -z -o Print-$SIZE.pdf print.tif
echo -e "done"

#Cleanup
mv Print-$SIZE.pdf ..
rm *.tif
cd ..
rmdir print

exit
Post Reply