#! /usr/bin/python3 -sP
# -*- coding: utf-8 -*-

#
# wavextract - program for extracting embedded audio data from JPEG images
# Copyright (C) 2006 Michal Krenek
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# You can dowload a copy of the GNU General Public License here:
# http://www.gnu.org/licenses/gpl.txt
#
# Author: Michal Krenek (Mikos)
# Email:  mikos@sg1.cz
# Jabber: mikos@njs.netlab.cz
#

import sys
import os

# Python Imaging Library (PIL) must be installed!
from PIL import Image

class Error(Exception):
    """Standard errors (printed without program termination)"""
    pass

class CriticalError(Error):
    """Critical errors (program is terminated after critical error)"""
    pass

def wavextract(imagefile):
    """Extracts audio data from JPEG file"""

    try:
        img = Image.open(imagefile)
    except IOError:
        raise Error("File '%s' doesn't exist or isn't regular image." % imagefile)

    if img.format != "JPEG":
        raise Error("File '%s' isn't regular JPEG image!" % imagefile)

    wave_list = []
    riff_header = False

    # Get FlashPix data streams from JPEG file
    fpxr = (i[1] for i in img.applist if i[0] == "APP2" and i[1][:5] == "FPXR\0")

    # Parse FlashPix data streams to get RIFF audio data
    for i, item in enumerate(fpxr):
        if not riff_header and i >= 3 and item[41:].startswith("RIFF"):
            wave_list.append(item[41:])
            riff_header = True
        elif riff_header and i >= 4:
            wave_list.append(item[13:])

    if not riff_header:
        raise Error("File '%s' doesn't contain audio data." % imagefile)

    return "".join(wave_list)

def savefile(wavfile, data):
    """Write RIFF audio data to file"""

    if os.path.isfile(wavfile):
        raise Error("File '%s' already exists." % wavfile)

    try:
        f = file(wavfile, "w")
    except IOError:
        raise Error("Can't write to file '%s'." % wavfile)
    else:
        f.write(data)
        f.close()


def extreplace(filename, newext):
    """Replace file extension with the new one"""

    base, oldext = os.path.splitext(filename)
    return base + newext

if __name__ == "__main__":
    if len(sys.argv) > 1:
        for arg in sys.argv[1:]:
            try:
                savefile(extreplace(arg, ".wav"), wavextract(arg))
                run_status = 0
            except Error as e:
                print(e)
                run_status = 1
            except CriticalError as e:
                print(e)
                sys.exit(1)
    else:
        print("wavextract - program for extracting embedded audio data from JPEG images")
        print("Usage: %s image1.jpg image2.jpg ..." % sys.argv[0])
        sys.exit(0)

    sys.exit(run_status)
