# Copyright 2025 XMOS LIMITED.
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
"""
Converts an RGB image to YUV422 format and generates a C header file with the data.
- Resizes the input image to 480x270 and converts it to YUV422.
- Saves the binary output as 'img.bin'.
- Generates a C header file 'img.h' with the image data as a uint8_t array.
Requires: OpenCV, NumPy
"""

import cv2
import os
import re
import numpy as np
import subprocess

from pathlib import Path

cwd = Path(__file__).parent.resolve()
dest_width = 480
dest_height = 270
dest_shape = (dest_width, dest_height)

def rgb_to_yuv422(in_file:Path, out_file:Path) -> np.ndarray:
    # Open the image, convert to yuv
    image = cv2.imread(str(in_file))
    image = cv2.resize(image, dest_shape, interpolation=cv2.INTER_LINEAR)
    yuv = cv2.cvtColor(image, cv2.COLOR_BGR2YUV) # default opencv is bgr

    # Extract Y, U, V channels
    Y = yuv[:, :, 0]
    U = yuv[:, :, 1]
    V = yuv[:, :, 2]

    # Subsample U and V channels
    U_sub = U[:, ::2]  # Take every second U value
    V_sub = V[:, ::2]  # Take every second V value

    # Interleave Y, U, and V in YUV422 format (Y1 U Y2 V)
    h, w = Y.shape
    yuv422 = np.zeros((h, 2*w), dtype=np.uint8)
    yuv422[:, 0::4] = Y[:, ::2]   # Y1
    yuv422[:, 1::4] = U_sub       # U (shared)
    yuv422[:, 2::4] = Y[:, 1::2]  # Y2
    yuv422[:, 3::4] = V_sub       # V (shared)

    # save to file
    yuv422.tofile(out_file)  # Saves raw YUV422 data
    return yuv422


def bin2c(filename, out_file, varname='data', linesize=80, indent=4):
    """ Read binary data from file and return as a C array

    :param filename: a filename of a file to read.
    :param varname: a C array variable name.
    :param linesize: a size of a line (min value is 40).
    :param indent: an indent (number of spaces) that prepend each line.
    """
    file_path = Path(filename)

    if not file_path.is_file():
        print(f'File "{filename}" is not found!')
        return ''


    with file_path.open('rb') as in_file:
        data = in_file.read()

    # limit the line length
    if linesize < 40:
        linesize = 40
    byte_len = 6  # '0x00, '
    out = "#include <stdint.h>\n\n"
    out += f"// img shape {dest_shape}\n\n"
    out += f'uint8_t {varname}[{len(data)}] = {{\n'
    line = ''
    for byte in data:
        line += f'0x{byte:02x}, '
        if len(line) + indent + byte_len >= linesize:
            out += ' ' * indent + line + '\n'
            line = ''
    # add the last line
    if len(line) + indent + byte_len < linesize:
        out += ' ' * indent + line + '\n'
    # strip the last comma
    out = out.rstrip(', \n') + '\n'
    out += '};'

    # save to file
    with out_file.open('w') as out_f:
        out_f.write(out)

    return

if __name__ == "__main__":
    in_file = cwd / "img_sky.png"
    out_file = cwd / "img.bin"
    out_file_header = cwd / "img.h"

    yuv422_image = rgb_to_yuv422(in_file, out_file)  # Replace with your image path
    bin2c(out_file, out_file_header, varname='img_yuv')
    print("Binary saved as :", out_file.name)
    print("Header created as :", out_file_header.name)


