×

Forget something during Black Friday/Cyber Monday? Check out the Week of Deals!

Brent Wilkins

Member Since: January 30, 2014

Country: United States

Profile

Like to design and sometimes manufacture fun designs.

  • I saw the JPEG to code script and was intrigued. I haven't been able to test it, and it could use a bit of polish, but here is an improved (?) version. The main addition is the ability to handle color images and to scale them; unverified. Here is the Python source: #!/usr/bin/env python3 # -- coding: utf-8 --

    """Convert a JPEG image into a format that can be used by the SparkFun HyperDisplay Transparent Graphical OLED Library.
    
    This code relies on the Pillow module. To get it try $ pip3 install Pillow
    
    Exports:
    * process_image(jpg_file_name, size): Process the JPEG file and return an intermediate format.
    * write_function_to_file(pixel_data, size, file_to_write): Write some C/C++ code to a file.
    """
    import getopt
    import sys
    
    from PIL import Image
    
    __author__ = 'Brent Wilkins'
    __version__ = '0.1.0'
    __license__ = 'Open. Not wasting time looking that up.'
    
    
    def _main(argv):
        """Convert the given input JPEG into the desired output format."""
        input_jpg, output_file, size = _parse_args(argv)
        pixel_states = process_image(input_jpg, size)
        write_function_to_file(pixel_states, size, output_file)
    
    
    def _parse_args(argv):
        """Parse the command ine arguments if any were provided.
    
        Return tuple of input JPG file name (str), output file name (str), and a tuple of hopefully ints specifiying
        the desired output size. Warn and exit if two file names and dimensions weren't provided.
        """
        input_file = None
        output_file = None
        width = None
        height = None
    
        try:
            opts, args = getopt.getopt(argv, 'hi:o:w:t:', ['ifile=', 'ofile=', 'width=', 'height='])
        except getopt.GetoptError:
            _fail(2)  # Didn't have the time to find the best exit status, so magic!
        for opt, arg in opts:
            if opt == '-h':
                _fail()
            elif opt in ('-i', '--ifile'):
                input_file = arg
            elif opt in ('-o', '--ofile'):
                output_file = arg
            elif opt in ('-w', '--width'):
                width = arg
            elif opt in ('-t', '--height'):
                height = arg
    
        if input_file and output_file and width and height:
            try:
                width = int(width)
            except ValueError as err:
                print(f'Invalid value given for width. Only interger values are valid: {err}')
                sys.exit(3)  # 3 is pure magic.
            try:
                height = int(height)
            except ValueError as err:
                print(f'Invalid value given for height. Only interger values are valid: {err}')
                sys.exit(3)  # 3 is pure magic.
            size = width, height
    
            print(f'Input file is "{input_file}"')
            print(f'Output file is "{output_file}"')
            print(f'Output dimensions are specified as {size}')
    
            return input_file, output_file, size
        else:
            _fail(2)
    
    
    def process_image(jpg_file_name, size, threshold=127):
        """Process the JPEG file and return an intermediate format.
    
        Params:
            jpg_file_name (str): Name of the image to open for processing.
            size (tuple): The (width, height) of the desired output.
            threshold (int): Pixels with luminance values greater or equal to this will be set high.
    
        Returns:
            List of pixel states. True means the pixel is on, False means it's off.
        """
        pixels = None
        with Image.open(jpg_file_name) as image:
            print(image)
            try:
                image = image.resize(size)
                print(image)
            except TypeError as err:
                print(f"Couldn't resize image: {err}")
                sys.exit(3)  # Again, 3 is pure magic.
            pixels = list(image.getdata())
            image.close()
        # Calculate luminance based on Photometric/digital ITU BT.709. This is likely overkill, but interesting.
        luma = [0.2126*pixel[0] + 0.7152*pixel[1] + 0.0722*pixel[2] for pixel in pixels]
    
        # This produces a result opposite of the script this is based on. Here bright pixels are on.
        return list(map(lambda lum: True if lum >= threshold else False, luma))
    
    
    def _fail(status=0):
        """Print usage and exit the script."""
        print('Usage: jpg_to_pixels.py -i <inputfile> -o <outputfile> -w <width in pixels> -t <height in pixels>')
        sys.exit(status)
    
    
    def write_function_to_file(pixel_data, size, file_to_write):
        """Write some C/C++ code to a file."""
        with open(file_to_write, 'w') as fp:
            # Write the 'header'.
            fp.write('void ShowLogo(void) {\n  myTOLED.clearDisplay();\n\n')
            # Write the array of values.
            width, height = size
            fp.write(f'  const int width = {width};\n  const int height = {height};\n\n')
            str_list = ['  bool states[width*height] = {']
            for idx, state in enumerate(pixel_data):
                val = 'true, ' if state else 'false, '
                if idx == width*height - 1:  # Replace comma on last entry with closing '}'.
                    val = val[:-2]
                    val += '};\n'
                elif (not idx % 8) and (idx != 0):  # Limit the length of generated lines.
                    val += '\n' + 31*' '  # Need 31 spaces for alignment.
                str_list.append(val)
            fp.write(''.join(str_list))
            # Write the loop.
            fp.write('  for ( int i = 0; i < width*height; ++i ) {\n    if (states[i]) {\n      '
                     'myTOLED.pixelSet(i%width, (int)(i/width));\n    }\n  }\n}')
    
    
    if __name__ == '__main__':
        if len(sys.argv) > 1:
            _main(sys.argv[1:])
        else:
            _fail(2)
    

    Here is the output for ./jpg_to_pixels.py -i sflogo.jpg -o out.c -w 12 -t 6 A next step might be to use bits rather than an array of bools to save space.

    void ShowLogo(void) {
      myTOLED.clearDisplay();
    
      const int width = 12;
      const int height = 6;
    
      bool states[width*height] = {true, true, true, true, true, true, true, true, true, 
                                   true, true, true, true, true, true, true, true, 
                                   true, true, false, false, true, true, true, true, 
                                   true, true, true, true, true, true, true, true, 
                                   true, true, true, false, true, false, true, false, 
                                   false, false, true, false, true, false, false, false, 
                                   false, true, false, false, false, false, true, true, 
                                   true, false, false, true, true, true, true, true, 
                                   true, true, true, true, true, true, true};
      for ( int i = 0; i < width*height; ++i ) {
        if (states[i]) {
          myTOLED.pixelSet(i%width, (int)(i/width));
        }
      }
    }
    
  • For those of us stuck on Eagle 5.x, does anyone have an engineering drawing or something equivalent for this board? It seems to use 0.1" pitch headers. How far from the center of these pins to the board edges? Is the programming header centered on the short dimension, and how from from the edge? The coordinates of A4 - A7 would be great too. Thanks. - Brent

No public wish lists :(