From cbf4c3c273426ee1a21fe14beb72ab7f6e7db30f Mon Sep 17 00:00:00 2001 From: localhorst Date: Sun, 22 Jun 2025 12:43:13 +0200 Subject: [PATCH] shrink label --- layouter.py | 124 ++++++++++++++++++++++++++++++++++++++-------------- output.png | Bin 5599 -> 5129 bytes 2 files changed, 91 insertions(+), 33 deletions(-) diff --git a/layouter.py b/layouter.py index 58dbde9..deebd6e 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 = 212 # px +TEXT_X_OFFSET = 212 # px +QR_CODE_SIZE = 200 # px # Configure logging logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s" @@ -122,7 +121,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 +137,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 = 480 + y_capacity = 161 + y_start = 10 + + # 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, ) @@ -243,7 +300,7 @@ 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), 45) draw_outline(draw, 1, 4, OUTPUT_WIDTH, OUTPUT_HEIGHT) draw_text(draw, printable_data, font_regular, font_bold, font_bold_bigger) @@ -264,7 +321,7 @@ def main(): drive_state="shredded", modelfamily='Toshiba 2.5" HDD MK..65GSSX', modelname="TOSHIBA MK3265GSDX", - capacity=343597383680, + capacity=343597383600, serialnumber="YG6742U56UDRL123456789ABCDEFGJKL", power_on_hours=7074, power_cycle=4792, @@ -275,5 +332,6 @@ def main(): generate_image(temp_drive, rehdd_info, "output.png") + if __name__ == "__main__": main() diff --git a/output.png b/output.png index 59eb1bcba7d7bcac418aa256507df2c881470032..77808a0080a7ef7dfbac07cb5840118567be8109 100644 GIT binary patch literal 5129 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 r|2rer1h#Ii_$n* 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