diff --git a/tools/barcode_tools/DEPS b/tools/barcode_tools/DEPS new file mode 100644 index 0000000000..28fa8ac389 --- /dev/null +++ b/tools/barcode_tools/DEPS @@ -0,0 +1,21 @@ +# This is trimmed down version of the main tools DEPS file which is to be used +# in Chromiums PyAuto WebRTC video quality measurement test. We will only +# need the Zxing dependencies as we only use the barcode tools in this test. + +deps = { + # Used by tools/barcode_tools + "third_party/zxing/core": + "http://zxing.googlecode.com/svn/trunk/core@2349", + + # Used by tools/barcode_tools + "third_party/zxing/javase": + "http://zxing.googlecode.com/svn/trunk/javase@2349", +} + +hooks = [ + { + # A change to a .gyp, .gypi, or to GYP itself should run the generator. + "pattern": ".", + "action": ["python", "src/build/gyp_chromium", "--depth=.", + "barcode_tools.gyp"], + }, \ No newline at end of file diff --git a/tools/barcode_tools/barcode_decoder.py b/tools/barcode_tools/barcode_decoder.py new file mode 100755 index 0000000000..0c65f91f58 --- /dev/null +++ b/tools/barcode_tools/barcode_decoder.py @@ -0,0 +1,285 @@ +#!/usr/bin/env python +# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. +# +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file in the root of the source +# tree. An additional intellectual property rights grant can be found +# in the file PATENTS. All contributing project authors may +# be found in the AUTHORS file in the root of the source tree. + +import optparse +import os +import subprocess +import sys + +import helper_functions + +_DEFAULT_BARCODE_WIDTH = 352 + + +def convert_yuv_to_png_files(yuv_file_name, yuv_frame_width, yuv_frame_height, + output_directory = '.'): + """Converts a YUV video file into PNG frames. + + The function uses ffmpeg to convert the YUV file. The output of ffmpeg is in + the form frame_xxxx.png, where xxxx is the frame number, starting from 0001. + + Args: + yuv_file_name(string): The name of the YUV file. + yuv_frame_width(int): The width of one YUV frame. + yuv_frame_height(int): The height of one YUV frame. + output_directory(string): The output directory where the PNG frames will be + stored. + + Return: + (bool): True if the conversion was OK. + """ + size_string = str(yuv_frame_width) + 'x' + str(yuv_frame_height) + output_files_pattern = os.path.join(output_directory, 'frame_%04d.png') + command = ['ffmpeg', '-s', '%s' % size_string, '-i', '%s' + % yuv_file_name, '-f', 'image2', '-vcodec', 'png', + '%s' % output_files_pattern] + try: + helper_functions.run_shell_command( + command, msg='Error during YUV to PNG conversion') + except helper_functions.HelperError, err: + print err + return False + return True + + +def decode_frames(barcode_width, barcode_height, input_directory='.', + path_to_zxing='zxing-read-only'): + """Decodes the barcodes overlaid in each frame. + + The function uses the example Java command-line tool from the Zxing + distribution to decode the barcode in every PNG frame from the input + directory. The frames should be named frame_xxxx.png, where xxxx is the frame + number. The frame numbers should be consecutive and should start from 0001. + The decoding results in a frame_xxxx.txt file for every successfully decoded + barcode. This file contains the decoded barcode as 12-digit string (UPC-A + format: 11 digits content + one check digit). + + Args: + barcode_width(int): Width of the barcode. + barcode_height(int): Height of the barcode. + input_directory(string): The input directory from where the PNG frames are + read. + path_to_zxing(string): The path to Zxing. + Return: + (bool): True if the decoding went without errors. + """ + jars = helper_functions.form_jars_string(path_to_zxing) + command_line_decoder ='com.google.zxing.client.j2se.CommandLineRunner' + return helper_functions.perform_action_on_all_files( + directory=input_directory, file_pattern='frame_', + file_extension='png', start_number=1, action=_decode_barcode_in_file, + barcode_width=barcode_width, barcode_height=barcode_height, jars=jars, + command_line_decoder=command_line_decoder) + + +def _decode_barcode_in_file(file_name, barcode_width, barcode_height, jars, + command_line_decoder): + """Decodes the barcode in the upper left corner of a PNG file. + + Args: + file_name(string): File name of the PNG file. + barcode_width(int): Width of the barcode (in pixels). + barcode_height(int): Height of the barcode (in pixels) + jars(string): The Zxing core and javase string. + command_line_decoder(string): The ZXing command-line decoding tool. + + Return: + (bool): True upon success, False otherwise. + """ + command = ['java', '-cp', '%s' % jars, + '%s' % command_line_decoder, '--products_only', + '--dump_results', '--brief', '--crop=%d,%d,%d,%d' % + (0, 0, barcode_width, barcode_height), + '%s' % file_name] + try: + out = helper_functions.run_shell_command( + command, msg='Error during decoding of %s' % file_name) + if not 'Success' in out: + sys.stderr.write('Barcode in %s cannot be decoded\n' % file_name) + return False + except helper_functions.HelperError, err: + print err + return False + return True + + +def _generate_stats_file(stats_file_name, input_directory='.'): + """Generate statistics file. + + The function generates a statistics file. The contents of the file are in the + format , where frame name is the name of every frame + (effectively the frame number) and barcode is the decoded barcode. The frames + and the helper .txt files are removed after they have been used. + """ + file_prefix = os.path.join(input_directory, 'frame_') + stats_file = open(stats_file_name, 'w') + + for i in range(1, _count_frames_in(input_directory=input_directory) + 1): + frame_number = helper_functions.zero_pad(i) + barcode_file_name = file_prefix + frame_number + '.txt' + png_frame = file_prefix + frame_number + '.png' + entry_frame_number = helper_functions.zero_pad(i-1) + entry = 'frame_' + entry_frame_number + ' ' + + if os.path.isfile(barcode_file_name): + barcode = _read_barcode_from_text_file(barcode_file_name) + helper_functions.delete_file(barcode_file_name) + + if _check_barcode(barcode): + entry += (helper_functions.zero_pad(int(barcode[0:11])) + '\n') + else: + entry += 'Barcode error\n' # Barcode is wrongly detected. + else: # Barcode file doesn't exist. + entry += 'Barcode error\n' + + stats_file.write(entry) + helper_functions.delete_file(png_frame) + + stats_file.close() + + +def _read_barcode_from_text_file(barcode_file_name): + """Reads the decoded barcode for a .txt file. + + Args: + barcode_file_name(string): The name of the .txt file. + Return: + (string): The decoded barcode. + """ + barcode_file = open(barcode_file_name, 'r') + barcode = barcode_file.read() + barcode_file.close() + + return barcode + + +def _check_barcode(barcode): + """Check weather the UPC-A barcode was decoded correctly. + + This function calculates the check digit of the provided barcode and compares + it to the check digit that was decoded. + + Args: + barcode(string): The barcode (12-digit). + Return: + (bool): True if the barcode was decoded correctly. + """ + if len(barcode) != 12: + return False + + r1 = range(0, 11, 2) # Odd digits + r2 = range(1, 10, 2) # Even digits except last + dsum = 0 + # Sum all the even digits + for i in r1: + dsum += int(barcode[i]) + # Multiply the sum by 3 + dsum *= 3 + # Add all the even digits except the check digit (12th digit) + for i in r2: + dsum += int(barcode[i]) + # Get the modulo 10 + dsum = dsum % 10 + # If not 0 substract from 10 + if dsum != 0: + dsum = 10 - dsum + # Compare result and check digit + return dsum == int(barcode[11]) + + +def _count_frames_in(input_directory = '.'): + """Calculates the number of frames in the input directory. + + The function calculates the number of frames in the input directory. The + frames should be named frame_xxxx.png, where xxxx is the number of the frame. + The numbers should start from 1 and should be consecutive. + + Args: + input_directory(string): The input directory. + Return: + (int): The number of frames. + """ + file_prefix = os.path.join(input_directory, 'frame_') + file_exists = True + num = 1 + + while file_exists: + file_name = (file_prefix + helper_functions.zero_pad(num) + '.png') + if os.path.isfile(file_name): + num += 1 + else: + file_exists = False + return num - 1 + + +def _parse_args(): + """Registers the command-line options.""" + usage = "usage: %prog [options]" + parser = optparse.OptionParser(usage=usage) + + parser.add_option('--yuv_frame_width', type='int', default=352, + help=('Width of the YUV file\'s frames. ' + 'Default: %default')) + parser.add_option('--yuv_frame_height', type='int', default=288, + help=('Height of the YUV file\'s frames. ' + 'Default: %default')) + parser.add_option('--barcode_width', type='int', + default=_DEFAULT_BARCODE_WIDTH, + help=('Width of the barcodes. Default: %default')) + parser.add_option('--barcode_height', type='int', default=32, + help=('Height of the barcodes. Default: %default')) + parser.add_option('--yuv_file', type='string', default='output.yuv', + help=('The YUV file to be decoded. Default: %default')) + parser.add_option('--stats_file', type='string', default='stats.txt', + help=('The output stats file. Default: %default')) + parser.add_option('--png_output_dir', type='string', default='.', + help=('The output directory for the generated PNG files. ' + 'Default: %default')) + parser.add_option('--png_input_dir', type='string', default='.', + help=('The input directory for the generated PNG files. ' + 'Default: %default')) + parser.add_option('--path_to_zxing', type='string', default='zxing', + help=('The path to Zxing. Default: %default')) + options = parser.parse_args()[0] + return options + + +def _main(): + """The main function. + + A simple invocation is: + ./tools/barcode_tolls/barcode_decoder.py + --yuv_file= + --yuv_frame_width=352 --yuv_frame_height=288 --barcode_height=32 + --stats_file= + """ + options = _parse_args() + + # The barcodes with will be different than the base frame width only if + # explicitly specified at the command line. + if options.barcode_width == _DEFAULT_BARCODE_WIDTH: + options.barcode_width = options.yuv_frame_width + + script_dir = os.path.dirname(os.path.abspath(sys.argv[0])) + zxing_dir = os.path.join(script_dir, '..', 'third_party', 'zxing') + + # Convert the overlaid YUV video into a set of PNG frames. + convert_yuv_to_png_files(options.yuv_file, options.yuv_frame_width, + options.yuv_frame_height, + output_directory=options.png_output_dir) + # Decode the barcodes from the PNG frames. + decode_frames(options.barcode_width, options.barcode_height, + input_directory=options.png_input_dir, path_to_zxing=zxing_dir) + # Generate statistics file. + _generate_stats_file(options.stats_file, + input_directory=options.png_input_dir) + + +if __name__ == '__main__': + sys.exit(_main()) diff --git a/tools/barcode_tools/barcode_encoder.py b/tools/barcode_tools/barcode_encoder.py new file mode 100755 index 0000000000..244a8ccaac --- /dev/null +++ b/tools/barcode_tools/barcode_encoder.py @@ -0,0 +1,353 @@ +#!/usr/bin/env python +# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. +# +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file in the root of the source +# tree. An additional intellectual property rights grant can be found +# in the file PATENTS. All contributing project authors may +# be found in the AUTHORS file in the root of the source tree. + +import optparse +import os +import subprocess +import sys + +import helper_functions + +_DEFAULT_BARCODE_WIDTH = 352 +_DEFAULT_BARCODES_FILE = 'barcodes.yuv' + + +def generate_upca_barcodes(number_of_barcodes, barcode_width, barcode_height, + output_directory='.', + path_to_zxing='zxing-read-only'): + """Generates UPC-A barcodes. + + This function generates a number_of_barcodes UPC-A barcodes. The function + calls an example Java encoder from the Zxing library. The barcodes are + generated as PNG images. The width of the barcodes shouldn't be less than 102 + pixels because otherwise Zxing can't properly generate the barcodes. + + Args: + number_of_barcodes(int): The number of barcodes to generate. + barcode_width(int): Width of barcode in pixels. + barcode_height(int): Height of barcode in pixels. + output_directory(string): Output directory where to store generated + barcodes. + path_to_zxing(string): The path to Zxing. + + Return: + (bool): True if the conversion is successful. + """ + base_file_name = os.path.join(output_directory, "barcode_") + jars = helper_functions.form_jars_string(path_to_zxing) + command_line_encoder ='com.google.zxing.client.j2se.CommandLineEncoder' + barcode_width = str(barcode_width) + barcode_height = str(barcode_height) + + errors = False + for i in range(number_of_barcodes): + suffix = helper_functions.zero_pad(i) + # Barcodes starting from 0 + content = helper_functions.zero_pad(i, 11) + output_file_name = base_file_name + suffix + ".png" + + command = ["java", "-cp", jars, command_line_encoder, + "--barcode_format=UPC_A", "--height=%s" % barcode_height, + "--width=%s" % barcode_width, + "--output=%s" % (output_file_name), "%s" % (content)] + try: + helper_functions.run_shell_command( + command, msg=('Error during barcode %s generation' % content)) + except helper_functions.HelperError, err: + print err + errors = True + return not errors + + +def convert_png_to_yuv_barcodes(input_directory='.', output_directory='.'): + """Converts PNG barcodes to YUV barcode images. + + This function reads all the PNG files from the input directory which are in + the format frame_xxxx.png, where xxxx is the number of the frame, starting + from 0000. The frames should be consecutive numbers. The output YUV file is + named frame_xxxx.yuv. The function uses ffmpeg to do the conversion. + + Args: + input_directory(string): The input direcotry to read the PNG barcodes from. + output_directory(string): The putput directory to write the YUV files to. + Return: + (bool): True if the conversion was without errors. + """ + return helper_functions.perform_action_on_all_files( + input_directory, 'barcode_', 'png', 0, _convert_to_yuv_and_delete, + output_directory=output_directory, pattern='barcode_') + + +def _convert_to_yuv_and_delete(output_directory, file_name, pattern): + """Converts a PNG file to a YUV file and deletes the PNG file. + + Args: + output_directory(string): The output directory for the YUV file. + file_name(string): The PNG file name. + pattern(string): The file pattern of the PNG/YUV file. The PNG/YUV files are + named patternxx..x.png/yuv, where xx..x are digits starting from 00..0. + Return: + (bool): True upon successful conversion, false otherwise. + """ + # Pattern should be in file name + if not pattern in file_name: + return False + pattern_position = file_name.rfind(pattern) + + # Strip the path to the PNG file and replace the png extension with yuv + yuv_file_name = file_name[pattern_position:-3] + 'yuv' + yuv_file_name = os.path.join(output_directory, yuv_file_name) + + command = ['ffmpeg', '-i', '%s' % (file_name), '-pix_fmt', 'yuv420p', + '%s' % (yuv_file_name)] + try: + helper_functions.run_shell_command( + command, msg=('Error during PNG to YUV conversion of %s' % + file_name)); + helper_functions.delete_file(file_name) + except helper_functions.HelperError, err: + print err + return Flase + return True + + +def combine_yuv_frames_into_one_file(output_file_name, input_directory='.'): + """Combines several YUV frames into one YUV video file. + + The function combines the YUV frames from input_directory into one YUV video + file. The frames should be named in the format frame_xxxx.yuv where xxxx + stands for the frame number. The numbers have to be consecutive and start from + 0000. The YUV frames are removed after they have been added to the video. + + Args: + output_file_name(string): The name of the file to produce. + input_directory(string): The directory from which the YUV frames are read. + Return: + (bool): True if the frame stitching went OK. + """ + output_file = open(output_file_name, "wb") + success = helper_functions.perform_action_on_all_files( + input_directory, 'barcode_', 'yuv', 0, _add_to_file_and_delete, + output_file=output_file) + output_file.close() + return success + +def _add_to_file_and_delete(output_file, file_name): + """Adds the contents of a file to a previously opened file. + + Args: + output_file(file): The ouput file, previously opened. + file_name(string): The file name of the file to add to the output file. + + Return: + (bool): True if successful, False otherwise. + """ + input_file = open(file_name, "rb") + input_file_contents = input_file.read() + output_file.write(input_file_contents) + input_file.close() + return helper_functions.delete_file(file_name) + + +def _overlay_barcode_and_base_frames(barcodes_file, base_file, output_file, + barcodes_component_sizes, + base_component_sizes): + """Overlays the next YUV frame from a file with a barcode. + + Args: + barcodes_file(FileObject): The YUV file containing the barcodes (opened). + base_file(FileObject): The base YUV file (opened). + output_file(FileObject): The output overlaid file (opened). + barcodes_component_sizes(list of tuples): The width and height of each Y, U + and V plane of the barcodes YUV file. + base_component_sizes(list of tuples): The width and height of each Y, U and + V plane of the base YUV file. + Return: + (bool): True if there are more planes (i.e. frames) in the base file, false + otherwise. + """ + # We will loop three times - once for the Y, U and V planes + for ((barcode_comp_width, barcode_comp_height), + (base_comp_width, base_comp_height)) in zip(barcodes_component_sizes, + base_component_sizes): + for base_row in range(base_comp_height): + barcode_plane_traversed = False + if (base_row < barcode_comp_height) and not barcode_plane_traversed: + barcode_plane = barcodes_file.read(barcode_comp_width) + if barcode_plane == "": + barcode_plane_traversed = True + else: + barcode_plane_traversed = True + base_plane = base_file.read(base_comp_width) + + if base_plane == "": + return False + + if not barcode_plane_traversed: + # Substitute part of the base component with the top component + output_file.write(barcode_plane) + base_plane = base_plane[barcode_comp_width:] + output_file.write(base_plane) + return True + + +def overlay_yuv_files(barcode_width, barcode_height, base_width, base_height, + barcodes_file_name, base_file_name, output_file_name): + """Overlays two YUV files starting from the upper left corner of both. + + Args: + barcode_width(int): The width of the barcode (to be overlaid). + barcode_height(int): The height of the barcode (to be overlaid). + base_width(int): The width of a frame of the base file. + base_height(int): The height of a frame of the base file. + barcodes_file_name(string): The name of the YUV file containing the YUV + barcodes. + base_file_name(string): The name of the base YUV file. + output_file_name(string): The name of the output file where the overlaid + video will be written. + """ + # Component sizes = [Y_sizes, U_sizes, V_sizes] + barcodes_component_sizes = [(barcode_width, barcode_height), + (barcode_width/2, barcode_height/2), + (barcode_width/2, barcode_height/2)] + base_component_sizes = [(base_width, base_height), + (base_width/2, base_height/2), + (base_width/2, base_height/2)] + + barcodes_file = open(barcodes_file_name, 'rb') + base_file = open(base_file_name, 'rb') + output_file = open(output_file_name, 'wb') + + data_left = True + while data_left: + data_left = _overlay_barcode_and_base_frames(barcodes_file, base_file, + output_file, + barcodes_component_sizes, + base_component_sizes) + + barcodes_file.close() + base_file.close() + output_file.close() + + +def calculate_frames_number_from_yuv(yuv_width, yuv_height, file_name): + """Calculates the number of frames of a YUV video. + + Args: + yuv_width(int): Width of a frame of the yuv file. + yuv_height(int): Height of a frame of the YUV file. + file_name(string): The name of the YUV file. + Return: + (int): The number of frames in the YUV file. + """ + file_size = os.path.getsize(file_name) + + y_plane_size = yuv_width * yuv_height + u_plane_size = (yuv_width/2) * (yuv_height/2) # Equals to V plane size too + frame_size = y_plane_size + (2 * u_plane_size) + return int(file_size/frame_size) # Should be int anyway + + +def _parse_args(): + """Registers the command-line options.""" + usage = "usage: %prog [options]" + parser = optparse.OptionParser(usage=usage) + + parser.add_option('--barcode_width', type='int', + default=_DEFAULT_BARCODE_WIDTH, + help=('Width of the barcodes to be overlaid on top of the' + ' base file. Default: %default')) + parser.add_option('--barcode_height', type='int', default=32, + help=('Height of the barcodes to be overlaid on top of the' + ' base file. Default: %default')) + parser.add_option('--base_frame_width', type='int', default=352, + help=('Width of the base YUV file\'s frames. ' + 'Default: %default')) + parser.add_option('--base_frame_height', type='int', default=288, + help=('Height of the top YUV file\'s frames. ' + 'Default: %default')) + parser.add_option('--barcodes_yuv', type='string', + default=_DEFAULT_BARCODES_FILE, + help=('The YUV file with the barcodes in YUV. ' + 'Default: %default')) + parser.add_option('--base_yuv', type='string', default='base.yuv', + help=('The base YUV file to be overlaid. ' + 'Default: %default')) + parser.add_option('--output_yuv', type='string', default='output.yuv', + help=('The output YUV file containing the base overlaid' + ' with the barcodes. Default: %default')) + parser.add_option('--png_barcodes_output_dir', type='string', default='.', + help=('Output directory where the PNG barcodes will be ' + 'generated. Default: %default')) + parser.add_option('--png_barcodes_input_dir', type='string', default='.', + help=('Input directory from where the PNG barcodes will be ' + 'read. Default: %default')) + parser.add_option('--yuv_barcodes_output_dir', type='string', default='.', + help=('Output directory where the YUV barcodes will be ' + 'generated. Default: %default')) + parser.add_option('--yuv_frames_input_dir', type='string', default='.', + help=('Input directory from where the YUV will be ' + 'read before combination. Default: %default')) + parser.add_option('--zxing_dir', type='string', default='zxing', + help=('Path to the Zxing barcodes library. ' + 'Default: %default')) + options = parser.parse_args()[0] + return options + + +def _main(): + """The main function. + + A simple invocation will be: + ./tools/barcode_tools/barcode_encoder.py --barcode_height=32 + --base_frame_width=352 --base_frame_height=288 + --base_yuv= + --output_yuv= + """ + options = _parse_args() + # The barcodes with will be different than the base frame width only if + # explicitly specified at the command line. + if options.barcode_width == _DEFAULT_BARCODE_WIDTH: + options.barcode_width = options.base_frame_width + # If the user provides a value for the barcodes YUV video file, we will keep + # it. Otherwise we create a temp file which is removed after it has been used. + keep_barcodes_yuv_file = False + if options.barcodes_yuv != _DEFAULT_BARCODES_FILE: + keep_barcodes_yuv_file = True + + # Calculate the number of barcodes - it is equal to the number of frames in + # the base file. + number_of_barcodes = calculate_frames_number_from_yuv( + options.base_frame_width, options.base_frame_height, options.base_yuv) + + script_dir = os.path.dirname(os.path.abspath(sys.argv[0])) + zxing_dir = os.path.join(script_dir, '..', 'third_party', 'zxing') + # Generate barcodes - will generate them in PNG. + generate_upca_barcodes(number_of_barcodes, options.barcode_width, + options.barcode_height, + output_directory=options.png_barcodes_output_dir, + path_to_zxing=zxing_dir) + # Convert the PNG barcodes to to YUV format. + convert_png_to_yuv_barcodes(options.png_barcodes_input_dir, + options.yuv_barcodes_output_dir) + # Combine the YUV barcodes into one YUV file. + combine_yuv_frames_into_one_file(options.barcodes_yuv, + input_directory=options.yuv_frames_input_dir) + # Overlay the barcodes over the base file. + overlay_yuv_files(options.barcode_width, options.barcode_height, + options.base_frame_width, options.base_frame_height, + options.barcodes_yuv, options.base_yuv, options.output_yuv) + + if not keep_barcodes_yuv_file: + # Remove the temporary barcodes YUV file + helper_functions.delete_file(options.barcodes_yuv) + + +if __name__ == '__main__': + sys.exit(_main()) \ No newline at end of file diff --git a/tools/barcode_tools/barcode_tools.gyp b/tools/barcode_tools/barcode_tools.gyp new file mode 100644 index 0000000000..c1f40cf6ae --- /dev/null +++ b/tools/barcode_tools/barcode_tools.gyp @@ -0,0 +1,47 @@ +# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. +# +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file in the root of the source +# tree. An additional intellectual property rights grant can be found +# in the file PATENTS. All contributing project authors may +# be found in the AUTHORS file in the root of the source tree. + +{ + 'targets': [ + { + 'target_name': 'zxing', + 'message': 'build zxing barcode tool', + 'type': 'none', + 'actions': [ + { + 'action_name': 'build_zxing_core', + 'inputs': [ + '<(DEPTH)/third_party/zxing/core/build.xml', + ], + 'outputs': [ + '<(DEPTH)/third_party/zxing/core/core.jar', + ], + 'action': [ + 'ant', + '-buildfile', + '<(DEPTH)/third_party/zxing/core/build.xml', + ] + }, + { + 'action_name': 'build_zxing_javase', + 'inputs': [ + '<(DEPTH)/third_party/zxing/javase/build.xml', + ], + 'outputs': [ + '<(DEPTH)/third_party/zxing/javase/javase.jar', + ], + 'action': [ + 'ant', + '-buildfile', + '<(DEPTH)/third_party/zxing/javase/build.xml', + ] + }, + ], + }, + ], +} diff --git a/tools/barcode_tools/helper_functions.py b/tools/barcode_tools/helper_functions.py new file mode 100644 index 0000000000..cdd0219abe --- /dev/null +++ b/tools/barcode_tools/helper_functions.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python +# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. +# +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file in the root of the source +# tree. An additional intellectual property rights grant can be found +# in the file PATENTS. All contributing project authors may +# be found in the AUTHORS file in the root of the source tree. + +import os +import subprocess +import sys + +_DEFAULT_PADDING = 4 + + +class HelperError(Exception): + """Exception raised for errors in the helper.""" + pass + + +def zero_pad(number, padding=_DEFAULT_PADDING): + """Converts an int into a zero padded string. + + Args: + number(int): The number to convert. + padding(int): The number of chars in the output. Note that if you pass for + example number=23456 and padding=4, the output will still be '23456', + i.e. it will not be cropped. If you pass number=2 and padding=4, the + return value will be '0002'. + Return: + (string): The zero padded number converted to string. + """ + return str(number).zfill(padding) + + +def delete_file(file_name): + """Deletes the file with file_name. + + Args: + file_name(string): The file to be deleted. + Return: + (bool): True on success, False otherwise. + """ + try: + subprocess.check_call(['rm', '%s' % file_name]) + except subprocess.CalledProcessError, err: + sys.stderr.write('Error in deleting file %s' % file_name) + return False + return True + + +def run_shell_command(command, msg=None): + """Executes a command. + + Args: + command(list): Command list to execute. + msg(string): Message describing the error in case the command fails. + + Return: + (string): The standard output from running the command. + + Raise: + HelperError: If command fails. + """ + cmd_list = [str(x) for x in command] + cmd = ' '.join(cmd_list) + + process = subprocess.Popen(cmd_list, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + output, error = process.communicate() + if process.returncode != 0: + if msg: + print msg + raise HelperError('Failed to run %s: command returned %d and printed ' + '%s and %s' % (cmd, process.returncode, output, error)) + return output.strip() + + +def form_jars_string(path_to_zxing): + """Forms the the Zxing core and javase jars argument. + + Args: + path_to_zxing(string): The path to the Zxing checkout folder. + Return: + (string): The newly formed jars argument. + """ + javase_jar = os.path.join(path_to_zxing, "javase", "javase.jar") + core_jar = os.path.join(path_to_zxing, "core", "core.jar") + delimiter = ':' + if os.name != 'posix': + delimiter = ';' + return javase_jar + delimiter + core_jar + + +def perform_action_on_all_files(directory, file_pattern, file_extension, + start_number, action, **kwargs): + """Function that performs a given action on all files matching a pattern. + + It is assumed that the files are named file_patternxxxx.file_extension, where + xxxx are digits. The file names start from + file_patern0..start_number>.file_extension. + + Args: + directory(string): The directory where the files live. + file_pattern(string): The name pattern of the files. + file_extension(string): The files' extension. + start_number(int): From where to start to count frames. + action(function): The action to be performed over the files. + + Return: + (bool): Whether performing the action over all files was successful or not. + """ + file_prefix = os.path.join(directory, file_pattern) + file_exists = True + file_number = start_number + errors = False + + while file_exists: + zero_padded_file_number = zero_pad(file_number) + file_name = file_prefix + zero_padded_file_number + '.' + file_extension + if os.path.isfile(file_name): + if not action(file_name=file_name, **kwargs): + errors = True + file_number += 1 + else: + file_exists = False + return not errors + +