You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

struct.error报错求助:unpack_from所需缓冲区不足的修复方案

问题:struct.error 缓冲区不足的修复方案

我正在编写一个基于开源代码的Python脚本,之前碰到过struct.error的问题,当时简单调整就修复了,但现在给代码加了容错功能后,又出现同样的报错,试了很多方案都不匹配我的场景。想请教怎么添加缓冲区,或者有哪些可行的修复方法?

报错信息

struct.error: unpack_from requires a buffer of at least 10012 bytes for unpacking 4 bytes at offset 10008 (actual buffer size is 2048).

相关代码

import time
import struct
import operations as ops
import pyautogui as py
import Quartz.CoreGraphics as CG
from pngcanvas import PNGCanvas
from screeninfo import get_monitors

class ScreenPixel(object):

    def capture(self, region = None):

        if region is None:
            region = CG.CGRectInfinite
        else:
            if region.size.width % 2 > 0:
                emsg = "Capture region width should be even (was %s)" % (
                    region.size.width)
                raise ValueError(emsg)
            
        image = CG.CGWindowListCreateImage(
            region,
            CG.kCGWindowListOptionOnScreenOnly,
            CG.kCGNullWindowID,
            CG.kCGWindowImageDefault)

        # Intermediate step, get pixel data as CGDataProvider
        prov = CG.CGImageGetDataProvider(image)

        # Copy data out of CGDataProvider, becomes string of bytes

        # Get width/height of image
        self.width = CG.CGImageGetWidth(image)
        self.height = CG.CGImageGetHeight(image)

        _data = CG.CGDataProviderCopyData(prov)

        return _data
    
    def save(self,_data):
            sp = ScreenPixel()

            c = PNGCanvas(sp.width, sp.height)
            for x in range(sp.width):
                for y in range(sp.height):
                    (c.point(x, y, color = sp.pixel(x,y,_data)))

            with open("test.png", "wb") as f:
                f.write(c.dump())
    
    def pixel(self, x, y, _data):

        #Must call capture first.

        data_format = "BBBB"

        offset = 4 * ((self.width*int(round(y))) + int(round(x)))

        b, g, r, a = struct.unpack_from(data_format, _data, offset=offset)

        # Return BGRA as RGBA
        return (r, g, b, a)
    
    def testLoad(self):
        sp = ScreenPixel()

        pxls = []

        region = CG.CGRectMake(20, 20, sp.height, sp.width)

        _data = sp.capture(region=region)

        rgba =  (sp.pixel(21,21,_data))

        # run save if you want to save screenshot

        #sp.save()

        return rgba
    
    def loadLoop(self):
        while True:

            rgba = self.testLoad()

            if rgba == (78,80,85,255):
                rtrn = False
                break
            
            elif rgba == (222,121,46,255):
                rtrn = True
                break
            else: pass

        rgba = None

        if rtrn == False:
            while True:
                rgba = self.testLoad2()

                print(rgba)
                if rgba == (): return True         #idk this rgba yet
                elif rgba == (): return False      #this either
                else: pass

    def testLoad2(self): 
        # a 2nd wall to ensure page has loaded
        # adds a few milliseconds but drops false loads to almost 0
        sp = ScreenPixel()

        region = CG.CGRectMake(85, 150, sp.height, sp.width)

        _data = sp.capture(region=region)

        return  (sp.pixel(86,151,_data))

核心问题分析

报错根源是计算的偏移量offset超出了捕获到的_data实际长度。具体问题出在testLoad和testLoad2方法:

  1. 你在方法内新建了未初始化的ScreenPixel实例,用它的height/width构造捕获区域,但此时这些属性还没有被赋值,导致捕获的区域尺寸完全错误,返回的图像数据远小于预期。
  2. CG.CGRectMake的参数顺序是x, y, width, height,你搞反了宽高参数,进一步加剧了区域尺寸的错误。

可行修复方案

1. 修正捕获区域的参数错误

不要在方法内新建ScreenPixel实例,直接复用当前实例,同时正确设置捕获区域的宽高:

def testLoad(self):
    # 构造合理的捕获区域:x=20, y=20, width=100, height=100(可根据需求调整)
    region = CG.CGRectMake(20, 20, 100, 100)
    _data = self.capture(region=region)
    # capture方法会自动设置self.width和self.height为捕获区域的尺寸
    rgba = self.pixel(21, 21, _data)
    return rgba

def testLoad2(self): 
    region = CG.CGRectMake(85, 150, 100, 100)  # 设定实际需要的宽高
    _data = self.capture(region=region)
    return self.pixel(86, 151, _data)

2. 添加缓冲区越界检查

在pixel方法中先判断偏移量是否合法,避免直接报错:

def pixel(self, x, y, _data):
    data_format = "BBBB"
    offset = 4 * ((self.width * int(round(y))) + int(round(x)))
    # 检查偏移量+4字节是否超出数据长度
    if offset + 4 > len(_data):
        # 返回默认透明色,或根据需求抛出自定义异常
        return (0, 0, 0, 0)
    b, g, r, a = struct.unpack_from(data_format, _data, offset=offset)
    return (r, g, b, a)

3. 修复save方法的实例错误

save方法内新建的ScreenPixel实例未初始化宽高,改为使用当前实例的属性:

def save(self, _data):
    c = PNGCanvas(self.width, self.height)
    for x in range(self.width):
        for y in range(self.height):
            c.point(x, y, color=self.pixel(x, y, _data))
    with open("test.png", "wb") as f:
        f.write(c.dump())

4. 优化loadLoop的逻辑错误

loadLoop中testLoad2的判断条件重复,需要改成实际的目标颜色值:

if rtrn == False:
    while True:
        rgba = self.testLoad2()
        print(rgba)
        if rgba == (目标颜色1): 
            return True
        elif rgba == (目标颜色2): 
            return False
        else: 
            time.sleep(0.1)  # 添加短暂延迟,减少CPU占用

内容的提问来源于stack exchange,提问作者Learning_Python

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 09:22:16