1
2
3
4
5
6
7
8
9
10
11 "Routines to do various file format conversions"
12 from __future__ import with_statement
13 import contextlib
14 import os
15 import tempfile
16 import struct
17 import subprocess
18 import sys
19 import wx
20
21
22 import common
23
25
26 helperdir=os.path.join(common.get_main_dir(), "helpers")
27
28 osext={'win32': '.exe',
29 'darwin': '.mbin',
30 'linux2': '.lbin'} \
31 [sys.platform]
32
33
34
35 if sys.platform=='win32':
36 import win32api
38
39
40 if " " in x:
41 return win32api.GetShortPathName(x)
42 return x
43 else:
45
59
60
61 _foundpvconv=None
62
64 "PVConv can't be distributed with BitPim so the user has to install it and we have to find it"
65 global _foundpvconv
66
67 if _foundpvconv is not None and os.path.isfile(_foundpvconv):
68 return _foundpvconv
69 _foundpvconv=None
70 lookin=[]
71 if sys.platform=='win32':
72 binary="pvconv.exe"
73 lookin.append("c:\\bin")
74 from win32com.shell import shell, shellcon
75 path=shell.SHGetFolderPath(0, shellcon.CSIDL_PROGRAM_FILES, None, 0)
76 if path:
77 lookin.append(os.path.join(path, "Qualcomm"))
78 lookin.append(os.path.join(path, "pvconv"))
79 path=shell.SHGetFolderPath(0, shellcon.CSIDL_WINDOWS, None, 0)
80 if path:
81 lookin.append(path)
82 elif sys.platform=='linux2':
83 binary="pvconv"
84 lookin.append(_expand("~/bin"))
85 lookin.append(_expand("~"))
86 lookin.append(_expand("/usr/local/bin"))
87 elif sys.platform=='darwin':
88 binary="pvconv"
89 lookin.append(_expand("~/bin"))
90 lookin.append(_expand("~"))
91 lookin.append(_expand("/usr/local/bin"))
92 lookin.append(_expand("/usr/bin"))
93 else:
94 raise Exception("Unknown platform "+sys.platform)
95 for dir in lookin:
96 f=os.path.join(dir, binary)
97 if os.path.exists(f):
98 _foundpvconv=f
99 return _foundpvconv
100
101 raise common.HelperBinaryNotFound("pvconv", binary, lookin)
102
103
104
106 return os.path.expandvars(os.path.expanduser(x))
107
109 """Runs the specified command (args[0]) with supplied parameters.
110 Note that your path is not searched for the command."""
111 print args
112 p=subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
113 universal_newlines=True)
114 _res=p.communicate()
115 if p.returncode:
116
117 print _res[1]
118 raise common.CommandExecutionFailed(p.returncode, args, _res[1])
119
121 "Convert a PNG file to 8bit color map"
122
123
124 size=len(pngdata)
125 if size<=maxsize or pngdata[1:4]!='PNG':
126 return pngdata
127
128 p=sys.path[0]
129 if os.path.isfile(p):
130 p=os.path.dirname(p)
131 helpersdirectory=os.path.abspath(os.path.join(p, 'helpers'))
132 print "Helper Directory: "+helpersdirectory
133 if sys.platform=='win32':
134 osext=".exe"
135 if sys.platform=='darwin':
136 osext=".mbin"
137 if sys.platform=='linux2':
138 osext=".lbin"
139
140 pngtopnmbin=gethelperbinary('pngtopnm')
141 ppmquantbin=gethelperbinary('ppmquant')
142 pnmtopngbin=gethelperbinary('pnmtopng')
143 print "pngtopnm: "+pngtopnmbin
144 print "ppmquant: "+ppmquantbin
145 print "pnmtopng: "+pnmtopngbin
146
147
148 png=common.gettempfilename("png")
149 open(png, "wb").write(pngdata)
150
151
152 pnm=common.gettempfilename("pnm")
153 s='"'+pngtopnmbin+'"' + ' < '+png+' > '+pnm
154 os.system(s)
155
156 os.remove(png)
157
158
159
160
161 ncolormax=257
162 ncolormin=1
163 ncolortry=256
164 ncolor=ncolortry
165 pnmq=common.gettempfilename("pnm")
166
167 while size>maxsize or ncolormax-ncolor>1:
168 ncolor=ncolortry
169 s='"'+ppmquantbin+'"'+' '+`ncolortry`+' '+pnm+ ' > '+pnmq
170
171 os.system(s)
172 s ='"'+pnmtopngbin+'"' + ' < ' + pnmq + ' > '+png
173
174 os.system(s)
175 os.remove(pnmq)
176 pngquantdata=open(png,"rb").read()
177 os.remove(png)
178 size=len(pngquantdata)
179 print `ncolor`+' '+`size`
180 if size>maxsize:
181 ncolormax=ncolor
182 ncolortry=(ncolor+ncolormin)/2
183 else:
184 ncolormin=ncolor
185 ncolortry=(ncolor+ncolormax)/2
186
187 os.remove(pnm)
188 return pngquantdata
189
191 "Convert a PNG file to 8bit color map"
192 "Separate routine for now so not to screw up existing one, may merge later"
193 if pngdata[1:4]!='PNG':
194 return pngdata
195
196
197 pngtopnmbin=gethelperbinary('pngtopnm')
198 ppmquantbin=gethelperbinary('ppmquant')
199 pnmtopngbin=gethelperbinary('pnmtopng')
200 print "pngtopnm: "+pngtopnmbin
201 print "ppmquant: "+ppmquantbin
202 print "pnmtopng: "+pnmtopngbin
203
204 png=common.gettempfilename("png")
205 open(png, "wb").write(pngdata)
206 num_of_colors=wx.Image(png).ComputeHistogram(wx.ImageHistogram())
207 print 'number of colors:', num_of_colors
208 if num_of_colors>256:
209
210 os.remove(png)
211 return pngdata
212
213
214 pnm=common.gettempfilename("pnm")
215 s='"'+pngtopnmbin+'"' + ' < '+png+' > '+pnm
216 os.system(s)
217 os.remove(png)
218
219 pnmq=common.gettempfilename("pnm")
220 s='"'+ppmquantbin+'"'+' '+`num_of_colors`+' '+pnm+ ' > '+pnmq
221 os.system(s)
222 s ='"'+pnmtopngbin+'"' + ' < ' + pnmq + ' > '+png
223 os.system(s)
224 os.remove(pnmq)
225 pngquantdata=open(png, 'rb').read()
226 os.remove(png)
227 os.remove(pnm)
228 print 'old size: ',len(pngdata),', new size: ',len(pngquantdata)
229 return pngquantdata
230
231
232 -def converttomp3(inputfilename, bitrate, samplerate, channels):
233 """Reads inputfilename and returns data for an mp3 conversion
234
235 @param bitrate: bitrate to use in khz (ie 16 is 16000 bits per second)
236 @param samplerate: audio sampling rate in Hertz
237 @param channels: 1 is mono, 2 is stereo
238 """
239 ffmpeg=gethelperbinary("ffmpeg")
240 with common.usetempfile('mp3') as mp3file:
241 try:
242 run(ffmpeg, "-i", shortfilename(inputfilename), "-hq", "-ab", `bitrate`, "-ar", `samplerate`, "-ac", `channels`, shortfilename(mp3file))
243 except common.CommandExecutionFailed, e:
244
245
246 raise ConversionFailed, ' '.join(e.args)+'\n'+e.logstr
247 return file(mp3file, "rb").read()
248
249 -def converttowav(mp3filename, wavfilename, samplerate=None,
250 channels=None, start=None, duration=None):
267
268 _qcp_optimization_params=('ffr', 'vfr', 'fhr', 'vhr')
288
303
305 """ Ajdust the volume of a wav file.
306 """
307 with file(wavfilename, 'rb') as f:
308
309 headers=f.read(20)
310 subchunk1size=common.LSBUint32(headers[16:20])
311 headers+=f.read(subchunk1size)
312 headers+=f.read(8)
313 subchunk2size=common.LSBUint32(headers[-4:])
314 bitspersample=common.LSBUint16(headers[34:36])
315 if bitspersample!=16:
316 print 'Volume adjustment only works with 16-bit wav file',bitspersample
317 return
318 sample_num=subchunk2size/2
319 temp_name=common.gettempfilename("wav")
320 with file(temp_name, 'wb') as f_temp:
321 f_temp.write(headers)
322 delta=pow(10.0, (gain/10.0))
323 for i in range(sample_num):
324 d=int(struct.unpack('<h', f.read(2))[0]*delta)
325 if d>32767:
326 d=32767
327 elif d<-32768:
328 d=-32768
329 f_temp.write(struct.pack('<h', d))
330 os.remove(wavfilename)
331 os.rename(temp_name, wavfilename)
332
333 -def trimwavfile(wavfilename, wavoutfilename, start, duration=None, gain=None):
334 with file(wavfilename, 'rb') as f:
335
336 headers=f.read(20)
337 subchunk1size=common.LSBUint32(headers[16:20])
338 headers+=f.read(subchunk1size)
339 subchunk2id=f.read(4)
340 subchunk2size=common.LSBUint32(f.read(4))
341
342 if headers[:4]!='RIFF' or headers[8:12]!='WAVE' or \
343 headers[12:16]!='fmt ' or common.LSBUint16(headers[20:22])!=1:
344
345 raise TypeError
346 subchunk2start=20+subchunk1size
347 subchunk2datastart=subchunk2start+8
348 samplerate=common.LSBUint32(headers[24:28])
349 blockalign=common.LSBUint16(headers[32:34])
350
351 new_start=int(start*samplerate)*blockalign
352 new_size=subchunk2size-new_start
353 if duration is not None:
354 i=int(duration*samplerate)*blockalign
355 if i<new_size:
356 new_size=i
357
358 f.seek(new_start, 1)
359 open(wavoutfilename, 'wb').write("".join(['RIFF',
360 common.LSBstr32(4+8+subchunk1size+8+new_size),
361 headers[8:],
362 'data',
363 common.LSBstr32(new_size),
364 f.read(new_size)]))
365 if gain is not None:
366 adjustwavfilevolume(wavoutfilename, gain)
367
369
370 if wavedatain[:4]!='RIFF' or wavedatain[8:12]!='WAVE' or \
371 wavedatain[12:16]!='fmt ' or common.LSBUint16(wavedatain[20:22])!=1:
372 raise ValueError, 'not a PCM file'
373 subchunk1size=common.LSBUint32(wavedatain[16:20])
374 subchunk2start=20+subchunk1size
375 subchunk2size=common.LSBUint32(wavedatain[subchunk2start+4:subchunk2start+8])
376 subchunk2datastart=subchunk2start+8
377 samplerate=common.LSBUint32(wavedatain[24:28])
378 blockalign=common.LSBUint16(wavedatain[32:34])
379
380 new_start=int(start*samplerate)*blockalign
381 newsubchunk2datastart=subchunk2datastart+new_start
382 new_size=subchunk2size-new_start
383 if duration is not None:
384 i=int(duration*samplerate)*blockalign
385 if i<new_size:
386 new_size=i
387
388 return 'RIFF'+common.LSBstr32(4+8+subchunk1size+8+new_size)+\
389 wavedatain[8:subchunk2start]+\
390 'data'+common.LSBstr32(new_size)+\
391 wavedatain[newsubchunk2datastart:newsubchunk2datastart+new_size]
392
394 bmp2avi=shortfilename(gethelperbinary('bmp2avi'))
395 if new_file:
396
397 try:
398 os.remove(avi_file_name)
399 except:
400 pass
401
402 with contextlib.nested(common.usetempfile('jpg'),
403 common.usetempfile('bmp')) as (_jpg, _bmp):
404 jpg_name=shortfilename(_jpg)
405 bmp_name=shortfilename(_bmp)
406 file(jpg_name, "wb").write(jpg_data)
407 wx.Image(jpg_name).SaveFile(bmp_name, wx.BITMAP_TYPE_BMP)
408
409 run(bmp2avi, '-f', `fps`, '-i', bmp_name, '-o', avi_file_name)
410
416
424
426 "File-based wrapper for convertlgbittobmp."
427 with common.usetempfile('png') as bmp:
428 bmpdata=convertlgbittobmp(file(bit_file_name,"rb").read())
429 file(bmp, "wb").write(bmpdata)
430 return wx.Image(bmp)
431
478
480 """Takes a BMP image file and returns BIT image file (LG proprietary)
481
482 @param bit_data: 8BPP or 24BPP BMP image file data
483 @return: 16BPP LGBIT image file data
484 """
485
486
487 if bmp_data[0:2]!='BM':
488 return None
489 width=common.LSBUint32(bmp_data[18:22])
490 height=common.LSBUint32(bmp_data[22:26])
491 offset=common.LSBUint32(bmp_data[10:14])
492 bpp=common.LSBUint16(bmp_data[28:30])
493 img=common.LSBstr16(width)
494 img+=common.LSBstr16(height)
495
496 if bpp==8:
497
498 palette=bmp_data[54:54+256*4]
499 for h in range(height):
500 for w in range(width):
501 bitind=(height-h-1)*width+w+offset
502 palind=ord(bmp_data[bitind:bitind+1])*4
503 blue=ord(palette[palind:palind+1])
504 green=ord(palette[palind+1:palind+2])
505 red=ord(palette[palind+2:palind+3])
506 bitval=((red & 0xf8) << 8) | ((green & 0xfc) << 3) | ((blue & 0xf8) >> 3)
507 img+=common.LSBstr16(bitval)
508 elif bpp==24:
509
510 for h in range(height):
511 for w in range(width):
512 bitind=(height-h-1)*width*3+(w*3)+offset
513 blue=ord(bmp_data[bitind:bitind+1])
514 green=ord(bmp_data[bitind+1:bitind+2])
515 red=ord(bmp_data[bitind+2:bitind+3])
516 bitval=((red & 0xf8) << 8) | ((green & 0xfc) << 3) | ((blue & 0xf8) >> 3)
517 img+=common.LSBstr16(bitval)
518 else:
519 return None
520 return img
521
531