diff --git a/layouter.py b/layouter.py index 58dbde9..3e9f38f 100644 --- a/layouter.py +++ b/layouter.py @@ -21,10 +21,9 @@ FONT_PATH = "/usr/share/fonts" DEFAULT_FONT_REGULAR = "DejaVuSans.ttf" DEFAULT_FONT_BOLD = "DejaVuSans-Bold.ttf" OUTPUT_WIDTH = 696 # px -OUTPUT_HEIGHT = 300 # px -TEXT_X_OFFSET = 300 # px -QR_CODE_SIZE = 289 # px - +OUTPUT_HEIGHT = 190 # px +TEXT_X_OFFSET = 190 # px +QR_CODE_SIZE = 179 # px # Configure logging logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s" @@ -46,6 +45,20 @@ class DriveData: shred_duration: int +@dataclasses.dataclass +class DriveDataJson: + state: str + fam: str + name: str + cap: int + sn: str + poh: int + pc: int + err: int + time: int + dur: int + + @dataclasses.dataclass class DriveDataPrintable: modelfamily: str @@ -61,13 +74,13 @@ class DriveDataPrintable: @dataclasses.dataclass class ReHddInfo: - link: str - version: str + ref: str + ver: str @dataclasses.dataclass -class DriveDataJson: - drive: DriveData +class QrDataJson: + drive: DriveDataJson rehdd: ReHddInfo @@ -122,7 +135,7 @@ def format_to_printable(drive): cut_string(20, re.sub(r"[^a-zA-Z0-9. ]", "", drive.modelfamily), "end"), cut_string(20, re.sub(r"[^a-zA-Z0-9. ]", "", drive.modelname), "end"), cut_string(20, human_readable_capacity(drive.capacity), "end"), - cut_string(16, re.sub(r"[^a-zA-Z0-9.-_]", "", drive.serialnumber), "start"), + cut_string(20, re.sub(r"[^a-zA-Z0-9.-_]", "", drive.serialnumber), "start"), cut_string(30, human_readable_power_on_hours(drive.power_on_hours), "end"), cut_string(10, str(drive.power_cycle), "end"), cut_string(10, str(drive.smart_error_count), "end"), @@ -138,40 +151,98 @@ def format_to_printable(drive): def draw_text(drawable, printable_data, font_regular, font_bold, font_bold_bigger): - """Draws the formatted text onto the image.""" - text_y_offset = 10 - value_column_x_offset = 120 - font_size = 20 + """Draws formatted text with Cycles and Errors on one row.""" + line_height = 26 + label_x = TEXT_X_OFFSET + value_offset = 115 + right_field_spacing = 200 # Horizontal gap between Cycles and Errors + x_capacity = 520 + y_capacity = 142 + y_start = 4 + + # Serial Number + drawable.text((label_x, y_start), "Serial:", fill=0, font=font_bold) drawable.text( - (TEXT_X_OFFSET, text_y_offset), printable_data.serialnumber, (0), font=font_bold + (label_x + value_offset, y_start), + printable_data.serialnumber, + fill=0, + font=font_bold, ) - text_y_offset += 25 - fields = [ - ("Family:", printable_data.modelfamily, font_regular), - ("Model:", printable_data.modelname, font_regular), - ("Hours:", printable_data.power_on_hours, font_regular), - ("Cycles:", printable_data.power_cycle, font_regular), - ("Errors:", printable_data.smart_error_count, font_regular), - ("Shred on:", printable_data.shred_timestamp, font_regular), - ("Duration:", printable_data.shred_duration, font_regular), - ] + y1 = y_start + line_height + y2 = y1 + line_height + y3 = y2 + line_height + y4 = y3 + line_height + y5 = y4 + line_height + y6 = y5 + line_height - for label, value, font in fields: - drawable.text((TEXT_X_OFFSET, text_y_offset), label, fill=0, font=font_bold) - drawable.text( - (TEXT_X_OFFSET + value_column_x_offset, text_y_offset), - value, - fill=0, - font=font, - ) - text_y_offset += 25 + # Left-Aligned Fields (One per row) + drawable.text((label_x, y1), "Family:", fill=0, font=font_bold) + drawable.text( + (label_x + value_offset, y1), + printable_data.modelfamily, + fill=0, + font=font_regular, + ) + + drawable.text((label_x, y2), "Model:", fill=0, font=font_bold) + drawable.text( + (label_x + value_offset, y2), + printable_data.modelname, + fill=0, + font=font_regular, + ) + + drawable.text((label_x, y3), "Hours:", fill=0, font=font_bold) + drawable.text( + (label_x + value_offset, y3), + printable_data.power_on_hours, + fill=0, + font=font_regular, + ) + + # Cycles and Errors on the same line + drawable.text((label_x, y4), "Cycles:", fill=0, font=font_bold) + drawable.text( + (label_x + value_offset, y4), + printable_data.power_cycle, + fill=0, + font=font_regular, + ) drawable.text( - (TEXT_X_OFFSET, text_y_offset), + (label_x + right_field_spacing, y4), "Errors:", fill=0, font=font_bold + ) + drawable.text( + (label_x + right_field_spacing + value_offset, y4), + printable_data.smart_error_count, + fill=0, + font=font_regular, + ) + + # Continue remaining fields + drawable.text((label_x, y5), "Shred on:", fill=0, font=font_bold) + drawable.text( + (label_x + value_offset, y5), + printable_data.shred_timestamp, + fill=0, + font=font_regular, + ) + + drawable.text((label_x, y6), "Duration:", fill=0, font=font_bold) + drawable.text( + (label_x + value_offset, y6), + printable_data.shred_duration, + fill=0, + font=font_regular, + ) + + # Capacity at the bottom + drawable.text( + (x_capacity, y_capacity), printable_data.capacity, - (0), + fill=0, font=font_bold_bigger, ) @@ -232,7 +303,21 @@ def draw_outline(drawable, margin, width, output_width, output_height): def generate_image(drive, rehdd_info, output_file): """Generates an image containing drive data and a QR code.""" try: - qr_data = json.dumps(dataclasses.asdict(DriveDataJson(drive, rehdd_info))) + + drive_json = DriveDataJson( + state=drive.drive_state, + fam=drive.modelfamily, + name=drive.modelname, + cap=drive.capacity, + sn=drive.serialnumber, + poh=drive.power_on_hours, + pc=drive.power_cycle, + err=drive.smart_error_count, + time=int(drive.shred_timestamp), + dur=drive.shred_duration, + ) + + qr_data = json.dumps(dataclasses.asdict(QrDataJson(drive_json, rehdd_info))) printable_data = format_to_printable(drive) except Exception as e: logging.error(f"Error preparing data: {e}") @@ -243,9 +328,9 @@ def generate_image(drive, rehdd_info, output_file): font_regular = ImageFont.truetype(find_font_path(DEFAULT_FONT_REGULAR), 20) font_bold = ImageFont.truetype(find_font_path(DEFAULT_FONT_BOLD), 20) - font_bold_bigger = ImageFont.truetype(find_font_path(DEFAULT_FONT_BOLD), 60) + font_bold_bigger = ImageFont.truetype(find_font_path(DEFAULT_FONT_BOLD), 42) - draw_outline(draw, 1, 4, OUTPUT_WIDTH, OUTPUT_HEIGHT) + draw_outline(draw, 0, 3, OUTPUT_WIDTH + 1, OUTPUT_HEIGHT + 1) draw_text(draw, printable_data, font_regular, font_bold, font_bold_bigger) draw_qr_code(output_image, qr_data) @@ -264,7 +349,7 @@ def main(): drive_state="shredded", modelfamily='Toshiba 2.5" HDD MK..65GSSX', modelname="TOSHIBA MK3265GSDX", - capacity=343597383680, + capacity=343597383000, serialnumber="YG6742U56UDRL123456789ABCDEFGJKL", power_on_hours=7074, power_cycle=4792, @@ -275,5 +360,6 @@ def main(): generate_image(temp_drive, rehdd_info, "output.png") + if __name__ == "__main__": main() diff --git a/output.png b/output.png index 59eb1bc..7f9d9dc 100644 Binary files a/output.png and b/output.png differ