Skip to content

Instantly share code, notes, and snippets.

@dixyes
Last active November 7, 2023 13:35
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dixyes/3c192b49816ca8ff6d87be93dd5294bd to your computer and use it in GitHub Desktop.
Save dixyes/3c192b49816ca8ff6d87be93dd5294bd to your computer and use it in GitHub Desktop.
GA402R anime matrix with python
from PIL import Image, ImageDraw, ImageOps, ImageStat
"""
convert picture to matrix data uint8 array
this script is too slow...
maybe we should rewrite it in np things
ref: https://blog.joshwalsh.me/asus-anime-matrix/
copyright 2022 Yun Dou
licensed by MIT license
"""
"""
the canvas:
< imageWidth >
**************** < top
**************** |
*************** | -> imageHeight
************** |
************* < bottom
"""
imageWidth = 2560
imageHeight = 1620
"""
< > - dotWidth: 4.1
* <
* * | -> dotHeight: 2.87
* # * <
* *
*
"""
dotWidth = imageWidth//((34*2)+1) # for GA402R, 34 dots on width
dotHeight = int(dotWidth*0.7)
class Dot:
areas = []
@classmethod
def dotArea(klass, x, y):
path = [
((2*x + 1)*dotWidth, 2*y*dotHeight),
((2*x + 2)*dotWidth, (2*y + 1)*dotHeight),
((2*x + 1)*dotWidth, (2*y + 2)*dotHeight),
(2*x*dotWidth, (2*y + 1)*dotHeight),
]
if (2*y + 2)*dotHeight > imageHeight or (2*x + 2)*dotWidth > imageWidth:
return None
return path
@classmethod
def makeAreas(klass):
if len(klass.areas) > 0:
return
for y in range(0, imageHeight//dotHeight):
# for GA402R
startX = y > 5 and y - 5 or 0
# odd line
for x in range(startX, (imageWidth//dotWidth)-1):
a = klass.dotArea(x, y)
if not a:
continue
klass.areas.append(a)
# even line
for x in range(startX, imageWidth//dotWidth):
a = klass.dotArea(x + 0.5, y + 0.5)
if not a:
continue
klass.areas.append(a)
Dot.makeAreas()
# start build image
# the canvas
im = Image.new('L', (imageWidth,imageHeight), 'white')
# 4.png is size of (640, 408), here scale it at 3.5x
r=3.5
inp = Image.open('4.png') \
.convert('L') \
.resize((int(640*r), int(408*r)), Image.BICUBIC)
# then put it on (600, -100)
im.paste(inp, (600, -100))
imBlack = Image.new('L', (imageWidth,imageHeight), 'black')
imPreview = Image.new('L', (imageWidth,imageHeight), 'black')
imPreviewDraw = ImageDraw.Draw(imPreview)
# build our data
data = []
for path in Dot.areas:
mask = imBlack.copy()
imMaskDraw = ImageDraw.Draw(mask)
imMaskDraw.polygon(path, fill ="white", outline ="white")
stat = ImageStat.Stat(im, mask)
color = int(stat.mean[0])
#print(stat.mean, end="")
data.append(color)
imPreviewDraw.polygon(path, fill = color, outline = color)
imPreview.show()
print(data)
#!/usr/bin/env python
"""
this will show a meme picture at matrix
copyright 2022 Yun Dou
licensed by MIT license
"""
import struct as st
import usb.core
import usb.util
# find our device
dev = usb.core.find(idVendor=0x0b05, idProduct=0x193b)
if dev is None:
raise ValueError('Device not found')
def write(data: bytes) -> int:
ret = dev.ctrl_transfer(
bmRequestType=
0x21, # REQUEST_TYPE_CLASS | RECIPIENT_INTERFACE | ENDPOINT_OUT
bRequest=0x9, # SET_REPORT
wValue=0x35e, # Feature 0x5e('^')
wIndex=0,
data_or_wLength=data, #.ljust(640, b'\0'),
timeout=500)
#print(ret)
return ret
def writeat(start: int, data: bytes) -> int:
#print(st.pack('<HH', start, len(data)))
return write(b'^\xc0\x02' + st.pack('<HH', start, len(data)) + data)
# init
write(b'^ASUS Tech.Inc.\0')
# c3 01 80 set boot off
write(b'^\xc3\x01\x80')
# c4 01 80 commit
write(b'^\xc4\x01\x80')
# c0 04 00 set on
write(b'^\xc0\x04\x03')
# c4 01 80 commit
write(b'^\xc4\x01\x80')
def fil(pix: bytes, l: int) -> bytes:
return pix * (l // len(pix))
# my meme pic
data = [
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
170, 101, 226, 255, 252, 219, 201, 233, 254, 255, 255, 254, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 163, 5, 14, 238, 199, 132, 150, 154, 153, 238, 255, 204,
217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 212, 5, 2, 25, 136, 174, 241, 252, 235,
162, 197, 126, 29, 161, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 13, 0, 4, 94, 246, 254,
254, 255, 254, 203, 104, 5, 2, 183, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 121, 0, 0, 39,
253, 254, 255, 255, 255, 254, 227, 10, 1, 7, 244, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 248, 3, 0,
5, 242, 254, 254, 255, 255, 254, 254, 210, 2, 0, 44, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 91, 0, 2, 190, 254, 254, 254, 254, 254, 254, 253, 139, 1, 1, 190, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 246, 1, 1, 136, 254, 254, 253, 252, 254, 251, 254, 254, 51, 0,
13, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 118, 1, 54, 254, 254, 225, 175, 211, 247,
172, 252, 245, 3, 0, 175, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 254, 18, 10, 249, 254, 233, 82, 64,
232, 150, 117, 251, 165, 2, 18, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 230, 7, 190,
254, 254, 149, 155, 109, 223, 147, 152, 253, 53, 2, 209, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 164, 67, 254, 255, 217, 225, 171, 182, 188, 237, 241, 246, 6, 58, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 159, 248, 255, 254, 164, 73, 203, 240, 151, 243, 254,
165, 4, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 193, 255, 255, 247, 161, 194, 254, 213,
130, 254, 254, 52, 170, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 208, 254, 255, 255, 253, 226,
254, 254, 198, 251, 254, 234, 88, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 251, 234, 255, 254, 255,
254, 252, 254, 254, 250, 255, 254, 126, 254, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 170, 255, 254,
255, 255, 249, 229, 254, 241, 255, 255, 251, 220, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 216, 253, 254,
255, 254, 253, 164, 236, 243, 228, 255, 254, 171, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 194, 254,
254, 254, 236, 187, 119, 135, 173, 250, 255, 254, 220, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 158, 254, 255,
254, 234, 174, 230, 77, 145, 189, 254, 255, 184, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 209, 218, 255, 254,
254, 200, 193, 234, 184, 253, 236, 254, 254, 166, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 250, 62, 254, 255, 254, 250,
188, 214, 122, 153, 251, 254, 254, 178, 205, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 47, 233, 255, 255, 254, 235, 176,
77, 133, 156, 252, 255, 254, 18, 249, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 119, 41, 254, 255, 254, 246, 193, 116, 124, 87,
249, 254, 255, 170, 27, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 182, 4, 175, 254, 255, 254, 223, 200, 208, 224, 219, 254, 255,
254, 13, 63, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 233, 5, 6,
248, 255, 255, 250, 201, 190, 223, 241, 254, 254, 254, 141, 3, 124, 255,
255, 255, 255, 255, 255, 255, 255, 255, 254, 16, 2, 49, 254, 255, 254, 243,
181, 121, 141, 240, 254, 254, 245, 3, 3, 141, 255, 255, 255, 255, 255, 255,
255, 255, 53, 2, 3, 113, 254, 255, 254, 235, 210, 134, 175, 254, 255, 254,
42, 2, 1, 175, 255, 255, 255, 255, 255, 255, 255, 90, 2, 1, 5, 143, 254,
255, 254, 246, 235, 215, 253, 255, 254, 91, 2, 0, 4, 192, 255, 255, 254,
255, 255, 126, 2, 1, 1, 4, 139, 254, 255, 254, 253, 248, 254, 254, 254,
118, 2, 0, 0, 2, 155, 254, 254, 97, 255, 155, 5, 1, 0, 0, 4, 143, 254, 255,
255, 254, 254, 254, 248, 115, 2, 1, 0, 0, 4, 89, 221, 76, 158, 5, 1, 0, 1,
2, 5, 120, 240, 254, 254, 254, 254, 211, 60, 2, 1, 1, 0, 0, 7, 15, 27, 11,
10, 1, 1, 2, 2, 1, 2, 53, 189, 241, 223, 204, 123, 16, 4, 3, 2, 1, 1, 1, 3,
2, 2, 2, 1, 3, 3, 2, 2, 3, 9, 72, 72, 46, 23, 4, 3, 7, 5, 7, 0, 0, 1, 1, 0,
1, 0, 3, 62, 42, 41, 42, 49, 54, 53, 56, 42, 65, 60, 72, 87, 97, 30, 1, 1,
1, 1, 1, 3, 150, 218, 209, 212, 216, 227, 222, 231, 219, 223, 232, 234,
240, 242, 242, 79, 4, 7, 1, 8, 14, 89, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 254, 153, 69, 29, 38, 101, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 244,
228, 201, 240, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
]
# let it dim a little to save life
data = [(x >> 2) for x in data]
writeat(1, bytes(data[:0x278]))
writeat(1 + 0x278, bytes(data[0x278:2 * 0x278]))
writeat(1 + (2 * 0x278), bytes(data[2 * 0x278:]))
# c0 03 flush
write(b'^\xc0\x03')
exit(0)
@DTNGNR
Copy link

DTNGNR commented May 3, 2023

I'm working on a ROG Zephyrus G14 GA402RK_GA402RK with Windows 10 and WSL and was trying your script diaotu.py but got the error message on the first write:
USBError: [Errno 5] Input/Output Error

Can you give me a hint how to fix the error?

@dixyes
Copy link
Author

dixyes commented May 5, 2023

I have never tried this (or any other libusb application) on WSL, I have no idea about how to use libusb in WSL, you may try native windows python and libusb

btw, I have returned my GA402RJ due to its poor quality, so I cannot debug this now

@holzmichlnator
Copy link

I've the same problem right now. I'm also trying to get this working on my GA402RK but in native windows and not in wsl and i'm getting the same error.
After setting PYUSB_DEBUG=debug and LIBUSB_DEBUG=4 the error log reported this line:
error [_hid_set_report] failed to write HID Output Report: [1] incorrect function

Sadly, i have still no idea what is causing this issue. @DTNGNR did you manage to fix it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment