# Implement 'jpeg' interface using SGI's compression library

# XXX Options 'smooth' and 'optimize' are ignored.

# XXX It appears that compressing grayscale images doesn't work right;
# XXX the resulting file causes weirdness.

class error(Exception):
    pass

options = {'quality': 75, 'optimize': 0, 'smooth': 0, 'forcegray': 0}

comp = None
decomp = None

def compress(imgdata, width, height, bytesperpixel):
    global comp
    import cl
    if comp is None: comp = cl.OpenCompressor(cl.JPEG)
    if bytesperpixel == 1:
        format = cl.GRAYSCALE
    elif bytesperpixel == 4:
        format = cl.RGBX
    if options['forcegray']:
        iformat = cl.GRAYSCALE
    else:
        iformat = cl.YUV
    # XXX How to support 'optimize'?
    params = [cl.IMAGE_WIDTH, width, cl.IMAGE_HEIGHT, height, \
              cl.ORIGINAL_FORMAT, format, \
              cl.ORIENTATION, cl.BOTTOM_UP, \
              cl.QUALITY_FACTOR, options['quality'], \
              cl.INTERNAL_FORMAT, iformat, \
             ]
    comp.SetParams(params)
    jpegdata = comp.Compress(1, imgdata)
    return jpegdata

def decompress(jpegdata):
    global decomp
    import cl
    if decomp is None: decomp = cl.OpenDecompressor(cl.JPEG)
    headersize = decomp.ReadHeader(jpegdata)
    params = [cl.IMAGE_WIDTH, 0, cl.IMAGE_HEIGHT, 0, cl.INTERNAL_FORMAT, 0]
    decomp.GetParams(params)
    width, height, format = params[1], params[3], params[5]
    if format == cl.GRAYSCALE or options['forcegray']:
        format = cl.GRAYSCALE
        bytesperpixel = 1
    else:
        format = cl.RGBX
        bytesperpixel = 4
    # XXX How to support 'smooth'?
    params = [cl.ORIGINAL_FORMAT, format, \
              cl.ORIENTATION, cl.BOTTOM_UP, \
              cl.FRAME_BUFFER_SIZE, width*height*bytesperpixel]
    decomp.SetParams(params)
    imgdata = decomp.Decompress(1, jpegdata)
    return imgdata, width, height, bytesperpixel

def setoption(name, value):
    if type(value) is not type(0):
        raise TypeError, 'jpeg.setoption: numeric options only'
    if name == 'forcegrey':
        name = 'forcegray'
    if not options.has_key(name):
        raise KeyError, 'jpeg.setoption: unknown option name'
    options[name] = int(value)

def test():
    import sys
    if sys.argv[1:2] == ['-g']:
        del sys.argv[1]
        setoption('forcegray', 1)
    if not sys.argv[1:]:
        sys.argv.append('/usr/local/images/data/jpg/asterix.jpg')
    for file in sys.argv[1:]:
        show(file)

def show(file):
    import gl, GL, DEVICE
    jpegdata = open(file, 'r').read()
    imgdata, width, height, bytesperpixel = decompress(jpegdata)
    gl.foreground()
    gl.prefsize(width, height)
    win = gl.winopen(file)
    if bytesperpixel == 1:
        gl.cmode()
        gl.pixmode(GL.PM_SIZE, 8)
        gl.gconfig()
        for i in range(256):
            gl.mapcolor(i, i, i, i)
    else:
        gl.RGBmode()
        gl.pixmode(GL.PM_SIZE, 32)
        gl.gconfig()
    gl.qdevice(DEVICE.REDRAW)
    gl.qdevice(DEVICE.ESCKEY)
    gl.qdevice(DEVICE.WINQUIT)
    gl.qdevice(DEVICE.WINSHUT)
    gl.lrectwrite(0, 0, width-1, height-1, imgdata)
    while 1:
        dev, val = gl.qread()
        if dev in (DEVICE.ESCKEY, DEVICE.WINSHUT, DEVICE.WINQUIT):
            break
        if dev == DEVICE.REDRAW:
            gl.lrectwrite(0, 0, width-1, height-1, imgdata)
    gl.winclose(win)
    # Now test the compression and write the result to a fixed filename
    newjpegdata = compress(imgdata, width, height, bytesperpixel)
    open('/tmp/j.jpg', 'w').write(newjpegdata)
