def _parse_jp2_header()

in infrastructure/pillow-layer/python/PIL/Jpeg2KImagePlugin.py [0:0]


def _parse_jp2_header(fp):
    """Parse the JP2 header box to extract size, component count and
    color space information, returning a (size, mode, mimetype) tuple."""

    # Find the JP2 header box
    header = None
    mimetype = None
    while True:
        lbox, tbox = struct.unpack(">I4s", fp.read(8))
        if lbox == 1:
            lbox = struct.unpack(">Q", fp.read(8))[0]
            hlen = 16
        else:
            hlen = 8

        if lbox < hlen:
            raise SyntaxError("Invalid JP2 header length")

        if tbox == b"jp2h":
            header = fp.read(lbox - hlen)
            break
        elif tbox == b"ftyp":
            if fp.read(4) == b"jpx ":
                mimetype = "image/jpx"
            fp.seek(lbox - hlen - 4, os.SEEK_CUR)
        else:
            fp.seek(lbox - hlen, os.SEEK_CUR)

    if header is None:
        raise SyntaxError("could not find JP2 header")

    size = None
    mode = None
    bpc = None
    nc = None

    hio = io.BytesIO(header)
    while True:
        lbox, tbox = struct.unpack(">I4s", hio.read(8))
        if lbox == 1:
            lbox = struct.unpack(">Q", hio.read(8))[0]
            hlen = 16
        else:
            hlen = 8

        content = hio.read(lbox - hlen)

        if tbox == b"ihdr":
            height, width, nc, bpc, c, unkc, ipr = struct.unpack(">IIHBBBB", content)
            size = (width, height)
            if unkc:
                if nc == 1 and (bpc & 0x7F) > 8:
                    mode = "I;16"
                elif nc == 1:
                    mode = "L"
                elif nc == 2:
                    mode = "LA"
                elif nc == 3:
                    mode = "RGB"
                elif nc == 4:
                    mode = "RGBA"
                break
        elif tbox == b"colr":
            meth, prec, approx = struct.unpack_from(">BBB", content)
            if meth == 1:
                cs = struct.unpack_from(">I", content, 3)[0]
                if cs == 16:  # sRGB
                    if nc == 1 and (bpc & 0x7F) > 8:
                        mode = "I;16"
                    elif nc == 1:
                        mode = "L"
                    elif nc == 3:
                        mode = "RGB"
                    elif nc == 4:
                        mode = "RGBA"
                    break
                elif cs == 17:  # grayscale
                    if nc == 1 and (bpc & 0x7F) > 8:
                        mode = "I;16"
                    elif nc == 1:
                        mode = "L"
                    elif nc == 2:
                        mode = "LA"
                    break
                elif cs == 18:  # sYCC
                    if nc == 3:
                        mode = "RGB"
                    elif nc == 4:
                        mode = "RGBA"
                    break

    if size is None or mode is None:
        raise SyntaxError("Malformed jp2 header")

    return (size, mode, mimetype)