JPEGTRAN is great tool, but need script for batch processing

Using applications, configuring, problems
Post Reply
Message
Author
Mysp
Posts: 47
Joined: Mon 08 Jun 2009, 10:39
Location: Czech Republic

JPEGTRAN is great tool, but need script for batch processing

#1 Post by Mysp »

After quite long time of searching for different programs for the task, I have found that jpegtran is the perfect tool for my purpose, because it can do loseless JPEG rotate (and crop/other transformations, too -- but rotate is my primary concern). Besides, it is "built-in" in Puppy (or Quirky in my case) - I did not know that before. But, to my surprise, in does NOT accept wildcards for filenames. The basic command for me is like following:

Code: Select all

jpegtran -copy all -rotate 90 -optimize SomePhoto.JPG > rotated/SomePhoto.JPG
OR

Code: Select all

jpegtran -copy all -rotate 270 -optimize SomePhoto.JPG > rotated/SomePhoto.JPG
I have basic knowledge of using rxvt (urxvt) and few linux commands (including the touch command for changing filestamp), but I am not able to write scripts. Can therefore somebody write for me following script? (I hope it is quite simply for people with some programming practice.)

1) In loop take every single file in current directory and pass it to jpegtran with above switches (switches can be "hardcoded" in script for simplicity).
2) Change filestamp of newly created rotated JPEG file according to original file. This step 2 is not necessary, but I would greatly appreciate it.

Thank you very much in advance for your help.

amigo
Posts: 2629
Joined: Mon 02 Apr 2007, 06:52

#2 Post by amigo »

Code: Select all

#!/bin/sh

mkdir -p rotated
for JPEG in *.jpg ; do
    jpegtran -copy all -rotate 90 -optimize $JPEG > rotated/$JPEG
done

Mysp
Posts: 47
Joined: Mon 08 Jun 2009, 10:39
Location: Czech Republic

Your script OK (after solving small problem), thanks amigo

#3 Post by Mysp »

Thank amigo, your script works fine.
It is quite simple. I have thought it would be much complicated. I do not know all the details of proper syntax (like where need to be semicolon, "do" keyword etc.) but the main idea of the script is now quite understandable even for me, with absolutly no prior experience of bash scripts.

First, I have had small problems with the script. It ended with error message

Code: Select all

line 5: rotated/*.jpg: Invalid argument
My wrong idea was that there is some syntax error in the script.
But after checking line number and its content, I realised that might be because of case sensitivity ("jpg" versus "JPG"), tried it and it works.
Of course, this is not your mistake, but mine. My camera simply create files with "JPG" extension and I am still not fully accustomed to Linux strict case sensitivity. Especially when Pfind file finder is not case sensitive by default (I use Pfind often and I am glad, that Pfind is not case sensitive).

Thank, amigo once more.
Can somebody add changing filestamp of new file according to original one? I do not know how much complicated it is, but I would really appreciaate that additional functionality. Looking at the script above, I think I would be able to call touch command in for loop properly, but I have no idea how to get filestamp from original file.

User avatar
Flash
Official Dog Handler
Posts: 13071
Joined: Wed 04 May 2005, 16:04
Location: Arizona USA

#4 Post by Flash »

By filestamp do you mean the exif metadata that the camera puts in the jpeg file?

User avatar
technosaurus
Posts: 4853
Joined: Mon 19 May 2008, 01:24
Location: Blue Springs, MO
Contact:

#5 Post by technosaurus »

here is the 1-liner version of amigo's script that should work with most typical jpeg extensions (*.jpg *.JPG *.jpeg *.JPEG) and silence the errors if one or more extension types is missing.

Code: Select all

mkdir -p rotated;for JPEG in *.jpg *.JPG *.jpeg *.JPEG ; do jpegtran -copy all -rotate 90 -optimize $JPEG > rotated/$JPEG;done 2>/dev/null
just paste it in a terminal and go
btw Rox has a nifty shortcut to open the terminal in the current directory ... just press "`" (upper left of the keyboard where the "~" tilda is) ... then just cut and paste with a middle mouse click (simulated on 2 button mice by pressing both at the same time)

... I think stat is the tool you are looking for to get time stamps
stat -c %z file.jpg

but OMG the formatting difference is a bear

Code: Select all

#!/bin/sh
mkdir -p rotated 2>/dev/null
for JPEG in *.jpg *.JPG *.jpeg *.JPEG; do
    jpegtran -copy all -rotate 90 -optimize $JPEG > rotated/$JPEG 2>/dev/null
    STAMP=`stat -c %z $JPEG 2>/dev/null`
	STAMP=${STAMP%%.*} #remove bits after the "."
	STAMP=${STAMP//-} #remove all "-"
	STAMP=${STAMP// } #remove all " "
	STAMP=${STAMP/:/} #remove first ":"
	STAMP=${STAMP/:/.} #replace ":" with "."
	touch -c -t $STAMP rotated/$JPEG 2>/dev/null
#touch -c is not supposed to create files but it did ... too lazy to file a bug report
	rm -f rotated/"*."*
done
Check out my [url=https://github.com/technosaurus]github repositories[/url]. I may eventually get around to updating my [url=http://bashismal.blogspot.com]blogspot[/url].

amigo
Posts: 2629
Joined: Mon 02 Apr 2007, 06:52

#6 Post by amigo »

Very good -glad you made it featureful enough so that you resist the temptation to make it a one-liner. LOL

User avatar
technosaurus
Posts: 4853
Joined: Mon 19 May 2008, 01:24
Location: Blue Springs, MO
Contact:

#7 Post by technosaurus »

apparently busybox touch in wary _does_ support -c and -r ... it just doesn't show up in the help text ... quite annoying yet all too commonplace

so that bunch of garbage becomes

touch -c -r $FILE rotated/$FILE
Check out my [url=https://github.com/technosaurus]github repositories[/url]. I may eventually get around to updating my [url=http://bashismal.blogspot.com]blogspot[/url].

Mysp
Posts: 47
Joined: Mon 08 Jun 2009, 10:39
Location: Czech Republic

(Almost) final version of the script

#8 Post by Mysp »

Thank you very much, technosauras and amigo for you quick response and help.
Sorry for not saying "thanks" for so long time. I tried your script soon after your post, but then I was so busy both at work and at home.
I further modified your script and have learned few other thinks. I will put few comments about that here as it can be useful for others and I still have some questions.

1. Version with "touch -c -r" (with some problems)
Version of "touch" command in Quirky also support both "-c" and "-r" switch. It even list them in help (I just did not use/noticed them before). (The version of touch in Quirky is 6.9.) Therefore I decided to base the script on "touch -c -r", as suggested in last post of technosaurus. I took line 1-4 from previous post and replaced all "STAMP" lines just with "touch -c -r $FILE rotated/$FILE". Basically, this script works, but I have found few problems:
1) The first one was just lack of my knowledge. I know basic redirection of std output to file, but did not understand all " 2>...". Only later I have learned that this is part of redirection, too - neccessary for redirecton of errors.
2) But even after that: the script works fine for single extension, but for multiple extension (*.jpg *.JPG *.jpeg *.JPEG) the script still makes error messages "Invalid argument" and I was not able to solve that. Even the original script of Technosaurus with "stat" command and all "STAMP" lines makes the same error. Just did not know why. And because meantime I have found that my sister's camera use JPEG extension, while mine use JPG, now I really want script for all 4 extensions.

2. Final (?) version with "touch -c -r" + improved error handling + rotation angle as input parameter
I came to decision that it would be nice to be able to choose between 90 and 270 angle = having single script instead of two almost identical scripts. Therefore I needed rotation angle as input parameter. I hope the script bellow is the final version (I did some testing, but not very extensive yet). There are still few thinks not very clear for me, see Comments and questions later.
1) After learning (a little) how to process input parameter, it was not so difficult to implement it (including default 90 angle if no input parameter is given). It is just 3 short lines of codes.
2) I also add basic error checking and information messages. (It is not foolprof checking for all possible errors.) Expression "in 90|180|270)" was most difficult for me and the syntax with no "(" but with ")" is still strange for me.
3) It is seems enough (after some tests) to write just "mkdir -p rotated" even if directory exists, therefore I ommit " 2>/dev/null" from technosaurus script.
4) After finding the correct syntax for testing existence of a file: if [[ -e $FILE ]]; then
it was quite easy to modify core lines of the script.
5) Surprisingly, the most difficult (or at least most time consumig) was to find some working syntax for counting number of files.

Code: Select all

#!/bin/sh 
#=== Loseless rotate of all photos in current dir, maintaing original filestamp ========#
#    Optional input parameter: rotate angle clockwise 90 or 180 or 270 (default = 90)   #
#    Rotated photos are created in subdir "rotated" of current directory                #
#=======================================================================================#


if [[ $# -gt 0 ]]; then ANGLE=$1
else ANGLE=90
fi

case $ANGLE in 90|180|270) 
       echo "Processing photos in dir:   $PWD"
       echo "Rotation angle (clockwise): $ANGLE";;
 	*) echo "Loseless rotate of all photos in current dir."
 	   echo "Rotate angle must be 90 (default) or 180 or 270 clockwise."
 	   exit 1;;
esac

mkdir -p rotated
i="0"

for FILE in *.JPG *.jpg *.JPEG *.jpeg; do
     if [[ -e $FILE ]]; then
        jpegtran -copy all -rotate $ANGLE -optimize $FILE > rotated/$FILE
        touch -c -r $FILE rotated/$FILE
        i=$(( $i + 1 ))
     fi
done
echo "Number of rotated photos:   $i"
Few additional comments and questions
1) "btw Rox has a nifty shortcut to open the terminal in the current directory...". (technosaurus' tip)
Yes, I know that. But anyway 95% of time I am working in two-panel file manager (now Tux Commander: it has only basic functions, but it resembles Total Commanders most, I have tried several others) and it is also easy to launch rxvt in specific directory from Tux.
2) "apparently busybox touch in wary _does_ support -c and -r ... it just doesn't show up in the help text ... quite annoying yet all too commonplace"
I am quite suprised that there is such discrepancy or inconsistency (or what is the proper English word) in parameters for basic Linux commands. So far I know just few commands, but I was convinced that GNU CoreUtils are VERY standardised for years. (I am aware that Puppy has BusyBux for many common commands (and these are missing some switches) and only some "full" versions.)
3) How "touch -c -r" is changing filestamp of rotated images?.
a) The only thing that really suprised me is that even on partition with FAT32 (I have photos on such partiton) there are still "Linux style" atime, mtime and ctime attributes.
b) Looking at these attributes after the script run might be a little confusing at first, but logical at second look. Mtime in this case is always the oldest. It equals to the time of creating photo in camera: that is exactly what I want! (I want to see at first glance, when I created the photo.) Ctime (not important in this case) for the photo BEFORE rotation (of course) equals to the date/time of transfer of photos to the PC and for the photo AFTER rotation to the run time of the script. Atime (not important at all) obviously depends on whether this attribute is updated for particular partition or not.
Question 1: Maybe I really badly mistundestood that part of documentation for BASH, therefore I would like to know:
a) When assigning "zero" to some variable, is there any difference between i="0" and i=0 ?
b) And is (for me horrible) syntax i=$(( $i + 1 )) the only one for increasing variable by one?
I was trying things like "i=i+1" or "i=$i+1" or "i++" or "$++" (see also Question 2).
Question 2: I am really confused when to reference variable with $ and when not. The only case which seems clear for me is passing variable to another program: like "jpegtran -copy all -rotate $ANGLE ...." or to echo command. Can this be formulated to some simply rules?
Question 3: I want to have one separate directory for all personal scripts. What is the right init script file for adding such directory to PATH?

I certainly do not want to take too much time of amigo or technosaurus (you already helped me a lot) or anyone else, but I would really appreciate to clarify remaining questions. It is my first script (not counting few very simple ones without any loop or conditional statements), therefore I think it is understandable thate some topics still confused me even after study of Bash documentation quite a lot.

Thank you very much in advance for your help.

Bruce B

#9 Post by Bruce B »

I use jpgtran to convert jpeg files to baseline format. It wants and infile and an outfile. Here is the script. The script doesn't do what you want, but it is a template that I think could do anything.

If questions, ask and I'll explain.

Code: Select all

#!/bin/bash

# lossless conversion to baseline format
# removes extraneious data from file

TMPDIR=tmpdir

mkdir $TMPDIR
for i in *.jpg ; do
	jpegtran -copy none -outfile $TMPDIR/$i $i
	mv -v $TMPDIR/$i .
done
rmdir $TMPDIR
~

User avatar
L18L
Posts: 3479
Joined: Sat 19 Jun 2010, 18:56
Location: www.eussenheim.de/

Re: (Almost) final version of the script

#10 Post by L18L »

Mysp wrote: Question 1: Maybe I really badly mistundestood that part of documentation for BASH, therefore I would like to know:
a) When assigning "zero" to some variable, is there any difference between i="0" and i=0 ?
b) And is (for me horrible) syntax i=$(( $i + 1 )) the only one for increasing variable by one?
I was trying things like "i=i+1" or "i=$i+1" or "i++" or "$++" (see also Question 2).
Question 2: I am really confused when to reference variable with $ and when not. The only case which seems clear for me is passing variable to another program: like "jpegtran -copy all -rotate $ANGLE ...." or to echo command. Can this be formulated to some simply rules?
Question 3: I want to have one separate directory for all personal scripts. What is the right init script file for adding such directory to PATH?
1a: "0" is a string while 0 is a number
2: Assigning a value to a variable without $, refering to it use $
3: /root/my-applications/bin is in PATH (echo $PATH to see it)
Hope that helps

Master_wrong
Posts: 452
Joined: Thu 20 Mar 2008, 01:48

#11 Post by Master_wrong »

1.b. try

let n="$n+1"
Cluster-Pup v.2-Puppy Beowulf Cluster
[url]http://www.murga-linux.com/puppy/viewtopic.php?p=499199#499199[/url]

User avatar
L18L
Posts: 3479
Joined: Sat 19 Jun 2010, 18:56
Location: www.eussenheim.de/

#12 Post by L18L »

Master_wrong wrote:1.b. try

let n="$n+1"
thank you Master right :D

amigo
Posts: 2629
Joined: Mon 02 Apr 2007, 06:52

#13 Post by amigo »

these all work with most shells:
i=$(( $i + 1 ))
let n="$n+1"
(( i++ ))

Mysp
Posts: 47
Joined: Mon 08 Jun 2009, 10:39
Location: Czech Republic

Thanks to all

#14 Post by Mysp »

This weekend I wiil be away, therefore only short message.
Thanks to all for help.
It seem that's everything is solved.
When I will be back, I will reedit this post, retest the script and then mark the whole topic as SOLVED.

Once more thanks to all.

Post Reply