| @ -0,0 +1,123 @@ | |||||
| #!/usr/bin/env python | |||||
| from PIL import Image, ImageOps | |||||
| import wave, math, array, argparse, sys, timeit | |||||
| def parser(): | |||||
| parser = argparse.ArgumentParser() | |||||
| # Specified command options and its helps message | |||||
| parser.add_argument ("INPUT_FILE", help="Name of the image to be converted.") | |||||
| parser.add_argument ("-r", "--rotate", help="Rotate image 90 degrees.", action='store_true') | |||||
| parser.add_argument ("-i", "--invert", help="Invert image colors.", action='store_true') | |||||
| parser.add_argument ("-o", "--output", help="Name of the output wav file. Default value: out.wav).") | |||||
| parser.add_argument ("-b", "--bottom", help="Bottom frequency range. Default value: 200.", type=int) | |||||
| parser.add_argument ("-t", "--top", help="Top frequency range. Default value: 20000.", type=int) | |||||
| parser.add_argument ("-p", "--pixels", help="Pixels per second. Default value: 30.", type=int) | |||||
| parser.add_argument ("-s", "--sampling", help="Sampling rate. Default value: 44100.", type=int) | |||||
| # Create "arguments" object based on user input | |||||
| arguments = parser.parse_args() | |||||
| # Default values | |||||
| min_freq = 200 | |||||
| max_freq = 20000 | |||||
| sampling_rate = 44100 | |||||
| pixels = 30 | |||||
| output = "out.wav" | |||||
| rotate = False | |||||
| invert = False | |||||
| # Check arguments values | |||||
| if arguments.output: | |||||
| output = arguments.output | |||||
| if arguments.bottom: | |||||
| min_freq = arguments.bottom | |||||
| if arguments.top: | |||||
| max_freq = arguments.top | |||||
| if arguments.pixels: | |||||
| pixels = arguments.pixels | |||||
| if arguments.sampling: | |||||
| sampling_rate = arguments.sampling | |||||
| if arguments.rotate: | |||||
| rotate = True | |||||
| if arguments.invert: | |||||
| invert = True | |||||
| print ("------------------------------------ Simple Image To Sound Script ------------------------------------\n") | |||||
| print ('Input file: %s.' % arguments.INPUT_FILE) | |||||
| print ('Frequency range: %d - %d.' % (min_freq, max_freq)) | |||||
| print ('Pixels per second: %d.' % pixels) | |||||
| print ('Sampling rate: %d.' % sampling_rate) | |||||
| print ('Rotate Image: %s.' % ('Yes' if rotate else 'No')) | |||||
| return (arguments.INPUT_FILE, output, min_freq, max_freq, pixels, sampling_rate, rotate, invert) | |||||
| def convert (INPUT_FILE, output, min_freq, max_freq, pixels, sampling_rate, rotate, invert): | |||||
| image = Image.open (INPUT_FILE).convert ('L') | |||||
| # rotate image if requested | |||||
| if rotate: | |||||
| image = image.rotate (90) | |||||
| # invert image if requested | |||||
| if invert: | |||||
| image = ImageOps.invert (image) | |||||
| output = wave.open (output, 'w') | |||||
| output.setparams ((1, 2, sampling_rate, 0, 'NONE', 'not compressed')) | |||||
| freq_range = max_freq - min_freq | |||||
| interval = freq_range / image.size[1] | |||||
| samples = sampling_rate // pixels | |||||
| data = array.array ('h') | |||||
| # Converting process start | |||||
| time_start = timeit.default_timer() | |||||
| for x in range (image.size[0]): | |||||
| row = [] | |||||
| for y in range (image.size[1]): | |||||
| yinv = image.size[1] - y - 1 | |||||
| amplitude = image.getpixel ((x,y)) | |||||
| if (amplitude > 0): | |||||
| row.append (gen_wave (yinv * interval + min_freq, amplitude, samples, sampling_rate)) | |||||
| for i in range(samples): | |||||
| for j in row: | |||||
| try: | |||||
| data[i + x * samples] += j[i] | |||||
| except (IndexError): | |||||
| data.insert (i + x * samples, j[i]) | |||||
| except (OverflowError): | |||||
| if j[i] > 0: | |||||
| data[i + x * samples] = 32767 | |||||
| else: | |||||
| data[i + x * samples] = -32768 | |||||
| sys.stdout.write ("Conversion progress: %d%% \r" % (float(x) / image.size[0] * 100)) | |||||
| sys.stdout.flush() | |||||
| output.writeframes (data.tobytes()) | |||||
| output.close() | |||||
| # Converting process end | |||||
| time_end = timeit.default_timer() | |||||
| print ("Conversion progress: 100%") | |||||
| print ("Success. Completed in %d seconds." % int(time_end - time_start)) | |||||
| def gen_wave (frequency, amplitude, samples, sampling_rate): | |||||
| cycles = samples * frequency / sampling_rate | |||||
| wave = [] | |||||
| for i in range(samples): | |||||
| x = math.sin (float (cycles) * 2 * math.pi * i / float (samples)) * float (amplitude) | |||||
| wave.append (int (math.floor (x))) | |||||
| return wave | |||||
| if __name__ == '__main__': | |||||
| input_choice = parser() | |||||
| convert (*input_choice) | |||||