Compare commits

..
1 Commits
Author SHA1 Message Date
Gitea Action f83411929c Update coverage badges [skip ci] 2025-11-23 14:10:14 +00:00
7 changed files with 60 additions and 593 deletions
+58
View File
@@ -0,0 +1,58 @@
<svg width="140" height="20" viewBox="0 0 140 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<title>interrogate: 99.7%</title>
<g transform="matrix(1,0,0,1,22,0)">
<g id="backgrounds" transform="matrix(1.32789,0,0,1,-22.3892,0)">
<rect x="0" y="0" width="71" height="20" style="fill:rgb(85,85,85);"/>
</g>
<rect x="71" y="0" width="47" height="20" data-interrogate="color" style="fill:#4c1"/>
<g transform="matrix(1.19746,0,0,1,-22.3744,-4.85723e-16)">
<rect x="0" y="0" width="118" height="20" style="fill:url(#_Linear1);"/>
</g>
</g>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110">
<text x="590" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="610">interrogate</text>
<text x="590" y="140" transform="scale(.1)" textLength="610">interrogate</text>
<text x="1160" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="370" data-interrogate="result">99.7%</text>
<text x="1160" y="140" transform="scale(.1)" textLength="370" data-interrogate="result">99.7%</text>
</g>
<g id="logo-shadow" serif:id="logo shadow" transform="matrix(0.854876,0,0,0.854876,-6.73514,1.732)">
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<path d="M50,64.25C52.76,64.25 55,61.13 55,59.75C55,58.37 52.76,57.25 50,57.25C47.24,57.25 45,58.37 45,59.75C45,61.13 47.24,64.25 50,64.25Z" style="fill:rgb(1,1,1);fill-opacity:0.3;fill-rule:nonzero;"/>
</g>
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<path d="M88,49.05C86.506,43.475 83.018,38.638 78.2,35.46C72.969,32.002 66.539,30.844 60.43,32.26C56.576,33.145 52.995,34.958 50,37.54C46.998,34.958 43.411,33.149 39.55,32.27C33.441,30.853 27.011,32.011 21.78,35.47C16.97,38.652 13.489,43.489 12,49.06L12,49.13C11.82,49.79 11.66,50.46 11.53,51.13C11.146,53.207 11.021,55.323 11.16,57.43C11.16,58.03 11.26,58.63 11.34,59.23C11.34,59.51 11.43,59.79 11.48,60.07C11.53,60.35 11.58,60.68 11.64,60.98C11.7,61.28 11.8,61.69 11.89,62.05C11.98,62.41 11.99,62.47 12.05,62.68C12.16,63.07 12.28,63.46 12.41,63.84L12.58,64.34C12.72,64.74 12.88,65.14 13.04,65.53L13.23,65.98C13.403,66.373 13.583,66.767 13.77,67.16L13.99,67.59C14.19,67.97 14.39,68.35 14.61,68.73L14.87,69.15C15.1,69.52 15.33,69.89 15.58,70.26L15.58,70.32L15.99,70.93C16.14,71.14 16.29,71.36 16.45,71.57C20.206,75.83 25.086,78.95 30.53,80.57C36.839,82.48 43.41,83.385 50,83.25C56.599,83.374 63.177,82.456 69.49,80.53C74.644,78.978 79.303,76.102 83,72.19C83.34,71.78 83.65,71.35 84,70.92L84.18,70.66L84.33,70.44L84.41,70.32C84.55,70.12 84.67,69.9 84.81,69.7C85.07,69.3 85.32,68.89 85.55,68.48C85.78,68.07 86.02,67.65 86.23,67.22C86.31,67.05 86.39,66.88 86.47,66.7C86.67,66.28 86.85,65.87 87.03,65.44L87.23,64.92C87.397,64.487 87.55,64.05 87.69,63.61L87.85,63.09C87.98,62.64 88.1,62.19 88.21,61.74C88.21,61.57 88.3,61.39 88.33,61.22C88.43,60.75 88.52,60.22 88.6,59.79C88.6,59.64 88.66,59.49 88.68,59.33C88.77,58.71 88.84,58.08 88.88,57.45L88.88,54.17C88.817,53.164 88.693,52.162 88.51,51.17C88.38,50.5 88.23,49.84 88.05,49.17L88,49.05ZM85.89,56.44L85.89,57.23C85.89,57.78 85.79,58.32 85.72,58.86C85.72,59.01 85.72,59.15 85.65,59.3C85.59,59.7 85.51,60.11 85.43,60.51L85.32,60.99C85.23,61.38 85.12,61.77 85.01,62.16C85.01,62.31 84.93,62.46 84.88,62.6C84.74,63.04 84.59,63.47 84.42,63.9L84.27,64.28C84.1,64.71 83.91,65.14 83.71,65.56C83.51,65.98 83.43,66.12 83.28,66.4L83.01,66.91C82.83,67.223 82.643,67.537 82.45,67.85L82.35,68.01C79.121,68.047 75.918,67.434 72.93,66.21C64.27,62.74 59,55.52 61.18,50.11C62.18,47.6 64.7,45.82 68.26,45.11C72.489,44.395 76.835,44.908 80.78,46.59C82.141,47.144 83.453,47.813 84.7,48.59C84.76,48.76 84.82,48.93 84.88,49.1C84.94,49.27 85.05,49.63 85.12,49.9C85.28,50.5 85.44,51.1 85.55,51.73C85.691,52.507 85.792,53.292 85.85,54.08L85.85,55.89C85.85,56.12 85.91,56.25 85.91,56.45L85.89,56.44ZM17.66,68C16.668,66.435 15.869,64.756 15.28,63L15.17,62.68C15.06,62.35 14.96,62.01 14.87,61.68C14.823,61.493 14.777,61.31 14.73,61.13C14.66,60.84 14.59,60.55 14.53,60.27C14.47,59.99 14.43,59.72 14.38,59.44C14.33,59.16 14.3,59 14.27,58.78C14.2,58.27 14.15,57.78 14.11,57.23L14.11,57.03C14.008,55.236 14.122,53.437 14.45,51.67C14.56,51.06 14.71,50.46 14.88,49.87C14.96,49.59 15.04,49.32 15.13,49.05C15.22,48.78 15.24,48.72 15.3,48.55C16.548,47.774 17.859,47.105 19.22,46.55C27.86,43.09 36.65,44.67 38.82,50.08C40.99,55.49 35.73,62.74 27.09,66.2C24.101,67.431 20.893,68.043 17.66,68ZM68.57,77.68C62.554,79.508 56.287,80.376 50,80.25C43.737,80.37 37.495,79.506 31.5,77.69C27.185,76.38 23.243,74.062 20,70.93C22.815,70.706 25.58,70.055 28.2,69C38.37,64.92 44.39,56 41.6,49C38.81,42 28.27,39.72 18.1,43.8L17.43,44.09C18.973,41.648 21.019,39.561 23.43,37.97C26.671,35.824 30.473,34.68 34.36,34.68C35.884,34.681 37.404,34.852 38.89,35.19C42.694,36.049 46.191,37.935 49,40.64L50,41.64L51,40.64C53.797,37.937 57.279,36.049 61.07,35.18C66.402,33.947 72.014,34.968 76.57,38C78.98,39.588 81.026,41.671 82.57,44.11L81.9,43.82C77.409,41.921 72.464,41.355 67.66,42.19C63.08,43.12 59.79,45.54 58.39,49.02C55.6,55.97 61.62,64.94 71.79,69.02C74.414,70.07 77.182,70.714 80,70.93C76.776,74.05 72.859,76.363 68.57,77.68Z" style="fill:rgb(1,1,1);fill-opacity:0.3;fill-rule:nonzero;"/>
</g>
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<circle cx="71.33" cy="56" r="5.16" style="fill:rgb(1,1,1);fill-opacity:0.3;"/>
</g>
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<circle cx="28.67" cy="56" r="5.16" style="fill:rgb(1,1,1);fill-opacity:0.3;"/>
</g>
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<path d="M58,66C55.912,68.161 53.003,69.339 50,69.24C46.997,69.339 44.088,68.161 42,66C41.714,65.677 41.302,65.491 40.87,65.491C40.042,65.491 39.361,66.172 39.361,67C39.361,67.368 39.496,67.724 39.74,68C42.403,70.804 46.134,72.35 50,72.25C53.862,72.347 57.59,70.802 60.25,68C60.495,67.725 60.63,67.369 60.63,67C60.63,66.174 59.951,65.495 59.125,65.495C58.695,65.495 58.285,65.679 58,66Z" style="fill:rgb(1,1,1);fill-opacity:0.3;fill-rule:nonzero;"/>
</g>
</g>
<g id="logo-pink" serif:id="logo pink" transform="matrix(0.854876,0,0,0.854876,-6.73514,0.877124)">
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<path d="M50,64.25C52.76,64.25 55,61.13 55,59.75C55,58.37 52.76,57.25 50,57.25C47.24,57.25 45,58.37 45,59.75C45,61.13 47.24,64.25 50,64.25Z" style="fill:rgb(222,120,160);fill-rule:nonzero;"/>
</g>
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<path d="M88,49.05C86.506,43.475 83.018,38.638 78.2,35.46C72.969,32.002 66.539,30.844 60.43,32.26C56.576,33.145 52.995,34.958 50,37.54C46.998,34.958 43.411,33.149 39.55,32.27C33.441,30.853 27.011,32.011 21.78,35.47C16.97,38.652 13.489,43.489 12,49.06L12,49.13C11.82,49.79 11.66,50.46 11.53,51.13C11.146,53.207 11.021,55.323 11.16,57.43C11.16,58.03 11.26,58.63 11.34,59.23C11.34,59.51 11.43,59.79 11.48,60.07C11.53,60.35 11.58,60.68 11.64,60.98C11.7,61.28 11.8,61.69 11.89,62.05C11.98,62.41 11.99,62.47 12.05,62.68C12.16,63.07 12.28,63.46 12.41,63.84L12.58,64.34C12.72,64.74 12.88,65.14 13.04,65.53L13.23,65.98C13.403,66.373 13.583,66.767 13.77,67.16L13.99,67.59C14.19,67.97 14.39,68.35 14.61,68.73L14.87,69.15C15.1,69.52 15.33,69.89 15.58,70.26L15.58,70.32L15.99,70.93C16.14,71.14 16.29,71.36 16.45,71.57C20.206,75.83 25.086,78.95 30.53,80.57C36.839,82.48 43.41,83.385 50,83.25C56.599,83.374 63.177,82.456 69.49,80.53C74.644,78.978 79.303,76.102 83,72.19C83.34,71.78 83.65,71.35 84,70.92L84.18,70.66L84.33,70.44L84.41,70.32C84.55,70.12 84.67,69.9 84.81,69.7C85.07,69.3 85.32,68.89 85.55,68.48C85.78,68.07 86.02,67.65 86.23,67.22C86.31,67.05 86.39,66.88 86.47,66.7C86.67,66.28 86.85,65.87 87.03,65.44L87.23,64.92C87.397,64.487 87.55,64.05 87.69,63.61L87.85,63.09C87.98,62.64 88.1,62.19 88.21,61.74C88.21,61.57 88.3,61.39 88.33,61.22C88.43,60.75 88.52,60.22 88.6,59.79C88.6,59.64 88.66,59.49 88.68,59.33C88.77,58.71 88.84,58.08 88.88,57.45L88.88,54.17C88.817,53.164 88.693,52.162 88.51,51.17C88.38,50.5 88.23,49.84 88.05,49.17L88,49.05ZM85.89,56.44L85.89,57.23C85.89,57.78 85.79,58.32 85.72,58.86C85.72,59.01 85.72,59.15 85.65,59.3C85.59,59.7 85.51,60.11 85.43,60.51L85.32,60.99C85.23,61.38 85.12,61.77 85.01,62.16C85.01,62.31 84.93,62.46 84.88,62.6C84.74,63.04 84.59,63.47 84.42,63.9L84.27,64.28C84.1,64.71 83.91,65.14 83.71,65.56C83.51,65.98 83.43,66.12 83.28,66.4L83.01,66.91C82.83,67.223 82.643,67.537 82.45,67.85L82.35,68.01C79.121,68.047 75.918,67.434 72.93,66.21C64.27,62.74 59,55.52 61.18,50.11C62.18,47.6 64.7,45.82 68.26,45.11C72.489,44.395 76.835,44.908 80.78,46.59C82.141,47.144 83.453,47.813 84.7,48.59C84.76,48.76 84.82,48.93 84.88,49.1C84.94,49.27 85.05,49.63 85.12,49.9C85.28,50.5 85.44,51.1 85.55,51.73C85.691,52.507 85.792,53.292 85.85,54.08L85.85,55.89C85.85,56.12 85.91,56.25 85.91,56.45L85.89,56.44ZM17.66,68C16.668,66.435 15.869,64.756 15.28,63L15.17,62.68C15.06,62.35 14.96,62.01 14.87,61.68C14.823,61.493 14.777,61.31 14.73,61.13C14.66,60.84 14.59,60.55 14.53,60.27C14.47,59.99 14.43,59.72 14.38,59.44C14.33,59.16 14.3,59 14.27,58.78C14.2,58.27 14.15,57.78 14.11,57.23L14.11,57.03C14.008,55.236 14.122,53.437 14.45,51.67C14.56,51.06 14.71,50.46 14.88,49.87C14.96,49.59 15.04,49.32 15.13,49.05C15.22,48.78 15.24,48.72 15.3,48.55C16.548,47.774 17.859,47.105 19.22,46.55C27.86,43.09 36.65,44.67 38.82,50.08C40.99,55.49 35.73,62.74 27.09,66.2C24.101,67.431 20.893,68.043 17.66,68ZM68.57,77.68C62.554,79.508 56.287,80.376 50,80.25C43.737,80.37 37.495,79.506 31.5,77.69C27.185,76.38 23.243,74.062 20,70.93C22.815,70.706 25.58,70.055 28.2,69C38.37,64.92 44.39,56 41.6,49C38.81,42 28.27,39.72 18.1,43.8L17.43,44.09C18.973,41.648 21.019,39.561 23.43,37.97C26.671,35.824 30.473,34.68 34.36,34.68C35.884,34.681 37.404,34.852 38.89,35.19C42.694,36.049 46.191,37.935 49,40.64L50,41.64L51,40.64C53.797,37.937 57.279,36.049 61.07,35.18C66.402,33.947 72.014,34.968 76.57,38C78.98,39.588 81.026,41.671 82.57,44.11L81.9,43.82C77.409,41.921 72.464,41.355 67.66,42.19C63.08,43.12 59.79,45.54 58.39,49.02C55.6,55.97 61.62,64.94 71.79,69.02C74.414,70.07 77.182,70.714 80,70.93C76.776,74.05 72.859,76.363 68.57,77.68Z" style="fill:rgb(222,120,160);fill-rule:nonzero;"/>
</g>
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<circle cx="71.33" cy="56" r="5.16" style="fill:rgb(222,120,160);"/>
</g>
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<circle cx="28.67" cy="56" r="5.16" style="fill:rgb(222,120,160);"/>
</g>
<g transform="matrix(0.299012,0,0,0.299012,9.70229,-6.68582)">
<path d="M58,66C55.912,68.161 53.003,69.339 50,69.24C46.997,69.339 44.088,68.161 42,66C41.714,65.677 41.302,65.491 40.87,65.491C40.042,65.491 39.361,66.172 39.361,67C39.361,67.368 39.496,67.724 39.74,68C42.403,70.804 46.134,72.35 50,72.25C53.862,72.347 57.59,70.802 60.25,68C60.495,67.725 60.63,67.369 60.63,67C60.63,66.174 59.951,65.495 59.125,65.495C58.695,65.495 58.285,65.679 58,66Z" style="fill:rgb(222,120,160);fill-rule:nonzero;"/>
</g>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.22465e-15,20,-20,1.22465e-15,0,0)">
<stop offset="0" style="stop-color:rgb(187,187,187);stop-opacity:0.1"/>
<stop offset="1" style="stop-color:black;stop-opacity:0.1"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="20" role="img" aria-label="coverage: failed"><title>coverage: failed</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="100" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="61" height="20" fill="#555"/><rect x="61" width="39" height="20" fill="#e05d44"/><rect width="100" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="315" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="510">coverage</text><text x="315" y="140" transform="scale(.1)" fill="#fff" textLength="510">coverage</text><text aria-hidden="true" x="795" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="290">failed</text><text x="795" y="140" transform="scale(.1)" fill="#fff" textLength="290">failed</text></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

-201
View File
@@ -1,201 +0,0 @@
#!/usr/bin/env python3
"""
Simple test to verify the hardware HAL can display images.
Creates a test pattern and displays it on the e-ink screen.
"""
import sys
import asyncio
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont
# Add parent directory to path
sys.path.insert(0, str(Path(__file__).parent.parent))
from dreader.hal_hardware import HardwareDisplayHAL
def create_test_image(width=1404, height=1872 ):
"""Create a test pattern image."""
print("Creating test image...")
# Create white background
img = Image.new('RGBA', (width, height), color='white')
draw = ImageDraw.Draw(img)
# Draw border
border_width = 10
draw.rectangle(
[(border_width, border_width),
(width - border_width, height - border_width)],
outline='black',
width=border_width
)
# Draw title
try:
font_large = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 80)
font_medium = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 50)
except:
font_large = ImageFont.load_default()
font_medium = ImageFont.load_default()
# Center text
title = "Hardware Display Test"
title_bbox = draw.textbbox((0, 0), title, font=font_large)
title_width = title_bbox[2] - title_bbox[0]
title_x = (width - title_width) // 2
draw.text((title_x, 100), title, fill='black', font=font_large)
# Instructions
instructions = [
"If you can see this, the display is working!",
"",
"Test pattern includes:",
"• Border around the screen",
"• Centered text",
"• Diagonal lines",
"• Corner markers"
]
y = 250
for line in instructions:
if line:
bbox = draw.textbbox((0, 0), line, font=font_medium)
line_width = bbox[2] - bbox[0]
x = (width - line_width) // 2
draw.text((x, y), line, fill='black', font=font_medium)
y += 70
# Draw diagonal lines
draw.line([(50, 50), (width-50, height-50)], fill='black', width=3)
draw.line([(width-50, 50), (50, height-50)], fill='black', width=3)
# Draw corner markers
marker_size = 100
# Top-left
draw.rectangle([(20, 20), (20 + marker_size, 20 + marker_size)],
fill='black')
draw.text((30, 30), "TL", fill='white', font=font_medium)
# Top-right
draw.rectangle([(width - 20 - marker_size, 20),
(width - 20, 20 + marker_size)],
fill='black')
draw.text((width - 100, 30), "TR", fill='white', font=font_medium)
# Bottom-left
draw.rectangle([(20, height - 20 - marker_size),
(20 + marker_size, height - 20)],
fill='black')
draw.text((30, height - 100), "BL", fill='white', font=font_medium)
# Bottom-right
draw.rectangle([(width - 20 - marker_size, height - 20 - marker_size),
(width - 20, height - 20)],
fill='black')
draw.text((width - 100, height - 100), "BR", fill='white', font=font_medium)
print(f"Test image created: {width}x{height} RGBA")
return img
async def main(args):
"""Test hardware display."""
print("=" * 60)
print("Hardware Display Test")
print("=" * 60)
print()
# Get VCOM from args
vcom = args.vcom if hasattr(args, 'vcom') else -1.65
print(f"Using VCOM: {vcom}V")
print()
# Create test image
test_image = create_test_image(1872, 1404)
# Save test image for reference
output_file = "test_pattern.png"
test_image.save(output_file)
print(f"Test pattern saved to: {output_file}")
print()
# Initialize hardware HAL
print("Initializing hardware HAL...")
hal = HardwareDisplayHAL(
width=1872,
height=1404,
vcom=vcom,
config_file="hardware_config.json"
)
print("Initializing hardware components...")
await hal.initialize()
print("✓ Hardware initialized")
print()
# Display the test image
print("Displaying test image on e-ink screen...")
print("(This may take a few seconds for the full refresh)")
print(f"Converting image from {test_image.mode} to grayscale for e-ink...")
# Convert RGBA to grayscale (L mode) for e-ink display
if test_image.mode == 'RGBA':
# Convert RGBA to RGB first (flatten alpha)
rgb_image = Image.new('RGB', test_image.size, (255, 255, 255))
rgb_image.paste(test_image, mask=test_image.split()[3]) # Use alpha as mask
test_image_gray = rgb_image.convert('L')
else:
test_image_gray = test_image.convert('L')
print(f"Image converted to {test_image_gray.mode} mode")
await hal.show_image(test_image_gray)
print("✓ Image displayed!")
print()
print("=" * 60)
print("SUCCESS!")
print("=" * 60)
print()
print("If you can see the test pattern on the screen, the")
print("hardware display is working correctly!")
print()
print("Check that you can see:")
print(" • Black border around the edges")
print(" • Title text centered at the top")
print(" • Diagonal lines crossing the screen")
print(" • Corner markers labeled TL, TR, BL, BR")
print()
print("Press Ctrl+C to exit")
print()
# Keep running so user can see the image
try:
while True:
await asyncio.sleep(1)
except KeyboardInterrupt:
print("\nCleaning up...")
await hal.cleanup()
print("Done!")
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description='Test hardware display')
parser.add_argument('--vcom', type=float, default=-1.65,
help='VCOM voltage (check your display label, default: -1.65)')
args = parser.parse_args()
try:
asyncio.run(main(args))
except KeyboardInterrupt:
print("\nTest interrupted")
except Exception as e:
print(f"\nERROR: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
-175
View File
@@ -1,175 +0,0 @@
#!/usr/bin/env python3
"""
Test script to render the library view and display it on hardware.
Combines library rendering with hardware display testing.
"""
import sys
import asyncio
from pathlib import Path
# Add parent directory to path
sys.path.insert(0, str(Path(__file__).parent.parent))
from dreader.library import LibraryManager
from dreader.hal_hardware import HardwareDisplayHAL
async def main(args):
"""Test library rendering on hardware display."""
library_path = args.library_path
output_path = "library_render_test.png"
vcom = args.vcom
print("=" * 60)
print("Library Rendering on Hardware Test")
print("=" * 60)
print(f"Library path: {library_path}")
print(f"VCOM: {vcom}V")
print(f"Output file: {output_path}")
print()
# Step 1: Create library manager and scan
print("Step 1: Creating library manager...")
library = LibraryManager(
library_path=library_path,
page_size=(1872, 1404)
)
print("Scanning library...")
library.scan_library()
print()
print(f"Found {len(library.books)} books:")
for i, book in enumerate(library.books[:10], 1): # Show first 10
print(f" {i}. {book['title']} by {book['author']}")
if len(library.books) > 10:
print(f" ... and {len(library.books) - 10} more")
print()
# Step 2: Create and render library table
print("Step 2: Creating library table (page 1)...")
table = library.create_library_table(page=0)
print(f"✓ Library table created: {table is not None}")
if table:
print(f" Table has {len(table.rows)} rows")
print()
print("Rendering library view...")
image = library.render_library()
if not image:
print("ERROR: No image rendered!")
print(f" library.library_table = {library.library_table}")
print(f" library.rendered_page = {library.rendered_page}")
return 1
print(f"✓ Library rendered: {image.size} {image.mode}")
# Check if image is not blank
import numpy as np
img_array = np.array(image)
unique_colors = len(np.unique(img_array.reshape(-1, img_array.shape[-1]), axis=0))
print(f" Image has {unique_colors} unique colors (blank would be ~1)")
# Sample some pixels to see what we have
print(f" Sample pixels:")
print(f" Top-left corner: {image.getpixel((10, 10))}")
print(f" Center: {image.getpixel((936, 702))}")
print(f" Bottom-right: {image.getpixel((1860, 1390))}")
print()
# Save for reference
print(f"Saving to {output_path}...")
image.save(output_path)
print(f"✓ Saved to {output_path}")
print()
# Step 3: Initialize hardware HAL
print("Step 3: Initializing hardware HAL...")
hal = HardwareDisplayHAL(
width=1872,
height=1404,
vcom=vcom,
config_file="hardware_config.json"
)
print("Initializing hardware components...")
await hal.initialize()
print("✓ Hardware initialized")
print()
# Step 4: Display on e-ink screen
print("Step 4: Displaying library on e-ink screen...")
print("(This may take a few seconds for the full refresh)")
print(f"Converting image from {image.mode} to grayscale for e-ink...")
# Convert to grayscale (L mode) for e-ink display
if image.mode == 'RGBA':
# Convert RGBA to RGB first (flatten alpha)
rgb_image = Image.new('RGB', image.size, (255, 255, 255))
rgb_image.paste(image, mask=image.split()[3]) # Use alpha as mask
image_gray = rgb_image.convert('L')
else:
image_gray = image.convert('L')
print(f"Image converted to {image_gray.mode} mode")
await hal.show_image(image_gray)
print("✓ Image displayed!")
print()
print("=" * 60)
print("SUCCESS!")
print("=" * 60)
print()
print("The library view should now be visible on your e-ink screen.")
print()
print(f"You can also view the saved PNG: {output_path}")
print()
print("Press Ctrl+C to exit")
print()
# Keep running so user can see the image
try:
while True:
await asyncio.sleep(1)
except KeyboardInterrupt:
print("\nCleaning up...")
await hal.cleanup()
print("Done!")
return 0
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(
description='Test library rendering on hardware display'
)
parser.add_argument(
'library_path',
nargs='?',
default='tests/data/library-epub',
help='Path to library directory (default: tests/data/library-epub)'
)
parser.add_argument(
'--vcom',
type=float,
default=-1.65,
help='VCOM voltage (check your display label, default: -1.65)'
)
args = parser.parse_args()
try:
exit_code = asyncio.run(main(args))
sys.exit(exit_code or 0)
except KeyboardInterrupt:
print("\nTest interrupted")
sys.exit(0)
except Exception as e:
print(f"\nERROR: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
-89
View File
@@ -1,89 +0,0 @@
#!/usr/bin/env python3
"""
Test script to render the library view and save it as PNG.
This helps verify the rendering is working correctly.
"""
import sys
from pathlib import Path
# Add parent directory to path
sys.path.insert(0, str(Path(__file__).parent.parent))
from dreader.library import LibraryManager
def main():
"""Test library rendering and save as PNG."""
library_path = "tests/data/library-epub"
output_path = "library_render_test.png"
print("=" * 60)
print("Library Rendering Test")
print("=" * 60)
print(f"Library path: {library_path}")
print(f"Output file: {output_path}")
print()
# Create library manager
print("Creating library manager...")
library = LibraryManager(
library_path=library_path,
page_size=(1872, 1404)
)
# Scan library
print("Scanning library...")
library.scan_library()
print()
print(f"Found {len(library.books)} books:")
for book in library.books:
print(f" - {book['title']} by {book['author']}")
print()
# Create library table (renders the first page)
print("Creating library table (page 1)...")
library.create_library_table(page=0)
# Render the table
print("Rendering library view...")
image = library.render_library()
if image:
print(f"Image size: {image.size}")
print(f"Image mode: {image.mode}")
# Save as PNG
print(f"Saving to {output_path}...")
image.save(output_path)
print()
print("=" * 60)
print("SUCCESS!")
print("=" * 60)
print(f"Library view saved to: {output_path}")
print()
print("You can view the image with:")
print(f" xdg-open {output_path} # Linux")
print(f" open {output_path} # macOS")
print()
return 0
else:
print()
print("=" * 60)
print("ERROR: No image rendered")
print("=" * 60)
return 1
if __name__ == "__main__":
try:
sys.exit(main())
except Exception as e:
print(f"\nERROR: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
-126
View File
@@ -1,126 +0,0 @@
#!/usr/bin/env python3
"""
Simplest possible test - half black, half white screen.
This verifies the display can show black pixels.
"""
import sys
import asyncio
from pathlib import Path
from PIL import Image, ImageDraw
# Add parent directory to path
sys.path.insert(0, str(Path(__file__).parent.parent))
from dreader.hal_hardware import HardwareDisplayHAL
def create_simple_test():
"""Create a simple half-black, half-white test image."""
print("Creating simple test pattern...")
print("Left half: BLACK")
print("Right half: WHITE")
width, height = 1872, 1404
# Create grayscale image (L mode = 8-bit grayscale)
img = Image.new('L', (width, height), color=255) # Start with white
draw = ImageDraw.Draw(img)
# Draw left half black
draw.rectangle(
[(0, 0), (width // 2, height)],
fill=0 # 0 = black
)
print(f"Test image created: {width}x{height} grayscale")
print(f" Left half ({width//2}px): BLACK (0)")
print(f" Right half ({width//2}px): WHITE (255)")
return img
async def main(args):
"""Test hardware display with simple pattern."""
print("=" * 60)
print("Simple Display Test - Half Black, Half White")
print("=" * 60)
print()
vcom = args.vcom
print(f"Using VCOM: {vcom}V")
print()
# Create simple test image
test_image = create_simple_test()
# Save test image for reference
output_file = "simple_test.png"
test_image.save(output_file)
print(f"Test pattern saved to: {output_file}")
print()
# Initialize hardware HAL
print("Initializing hardware HAL...")
hal = HardwareDisplayHAL(
width=1872,
height=1404,
vcom=vcom,
config_file="hardware_config.json"
)
print("Initializing hardware components...")
await hal.initialize()
print("✓ Hardware initialized")
print()
# Display the test image
print("Displaying test pattern on e-ink screen...")
print("(This may take a few seconds for the full refresh)")
await hal.show_image(test_image)
print("✓ Image displayed!")
print()
print("=" * 60)
print("CHECK YOUR SCREEN:")
print("=" * 60)
print()
print("You should see:")
print(" • LEFT HALF: BLACK")
print(" • RIGHT HALF: WHITE")
print()
print("If you see this, the display is working!")
print("If the screen is all white, there may be a driver issue.")
print()
print("Press Ctrl+C to exit")
print()
# Keep running so user can see the image
try:
while True:
await asyncio.sleep(1)
except KeyboardInterrupt:
print("\nCleaning up...")
await hal.cleanup()
print("Done!")
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description='Simple display test')
parser.add_argument('--vcom', type=float, default=-1.65,
help='VCOM voltage (check your display label, default: -1.65)')
args = parser.parse_args()
try:
asyncio.run(main(args))
except KeyboardInterrupt:
print("\nTest interrupted")
except Exception as e:
print(f"\nERROR: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
+1 -2
View File
@@ -5,9 +5,8 @@
"display": {
"width": 1872,
"height": 1404,
"vcom": -1.7,
"vcom": -2.0,
"spi_hz": 24000000,
"rotate": "CW",
"auto_sleep": true
},