| @ -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) | |||