示例#1
0
def pngquant_bts(img, ncolors=8):
    img = conv2png(img)
    img = Image.open(BytesIO(img)).convert('RGBA')
    w, h = img.width, img.height
    bytes = img.tobytes()

    attr = liq.Attr()
    attr.max_colors = ncolors
    img = attr.create_rgba(bytes, w, h, 0)
    res = img.quantize(attr)
    res.dithering_level = 1.0
    bytes = res.remap_image(img)
    palette = res.get_palette()

    img = Image.frombytes('P', (w, h), bytes)

    palette_data = []
    for color in palette:
        palette_data.append(color.r)
        palette_data.append(color.g)
        palette_data.append(color.b)
    img.putpalette(palette_data)

    bio = BytesIO()
    img.save(bio, 'PNG', optimize=True)
    return bio.getvalue()
示例#2
0
    def test_against(image_filename, points):
        q_in = QtGui.QImage(image_filename)

        for pos, expected in points:
            qcolor = q_in.pixelColor(*pos)
            assert (qcolor.red(), qcolor.green(), qcolor.blue(),
                    qcolor.alpha()) == expected

        attr = liq.Attr()
        img = liq_Qt.to_liq(q_in, attr)

        result = img.quantize(attr)
        q_out = liq_Qt.from_liq(result, img)

        assert q_out.format() == QtGui.QImage.Format.Format_Indexed8

        q_out_rgba = q_out.convertToFormat(QtGui.QImage.Format.Format_ARGB32)

        for pos, expected in points:
            qcolor = q_out_rgba.pixelColor(*pos)
            r, g, b, a = qcolor.red(), qcolor.green(), qcolor.blue(
            ), qcolor.alpha()
            print(pos, expected, (r, g, b, a))
            assert near(r, expected[0])
            assert near(g, expected[1])
            assert near(b, expected[2])
            assert near(a, expected[3])
def test_bitmap_not_available_error():
    """
    Trigger LIQ_BITMAP_NOT_AVAILABLE and ensure that
    liq.BitmapNotAvailableError is raised
    """

    attr = liq.Attr()
    hist = liq.Histogram(attr)

    with pytest.raises(liq.BitmapNotAvailableError):
        result = hist.quantize(attr)
示例#4
0
    def image_callback(value, image):

        # Load the background as an Image
        width, height, input_pixels = utils.load_test_image(value)
        attr = liq.Attr()
        background = attr.create_rgba(input_pixels, width, height, 0)
        backgrounds.append(background)

        # Test both the getter and setter methods
        image.background = background
        with pytest.raises(AttributeError):
            image.background
示例#5
0
def test_attr_copy():
    """
    Test Attr.copy()
    """
    width, height, input_pixels = utils.load_test_image('flower')

    attr = liq.Attr()
    attr.max_colors = 88
    attr.min_posterization = 3
    attr.min_quality = 55

    attr2 = attr.copy()
    assert attr2.max_colors == 88
    assert attr2.min_posterization == 3
    assert attr2.min_quality == 55
def convertAllToEnpg(imgs):
    """
    Palette-reduce the two images to 256-colors (both with the same
    palette), save them as PNGs, and save them as ENPGs
    Currently assumes both images are 256x256.
    """
    n = len(imgs)

    # Combine into one PIL image
    comb = PIL.Image.new('RGBA', (256 * n, 256), (0, 0, 0, 0))
    for i, img in enumerate(imgs):
        comb.paste(qImageToPilImage(img), (256 * i, 0))

    # Quantize
    # combQ = comb.quantize(255, 3) # leave one color for transparent
    attr = liq.Attr()
    attr.max_colors = 255  # leave one color for transparent
    comb_liq = libimagequant_integrations.PIL.to_liq(comb, attr)
    combQ = libimagequant_integrations.PIL.from_liq(comb_liq.quantize(attr),
                                                    comb_liq)

    # Create the ENPG data arrays
    ENPG_LEN = 256 * 256 + 256 * 2
    enpgs = [bytearray(ENPG_LEN) for i in range(n)]

    # Convert the palette to RGB555 and put it in both the enpgs
    pal888 = combQ.getpalette()[:255 * 3]
    for enpg in enpgs:
        struct.pack_into('<H', enpg, 256**2, 0x8000)
    shrink = lambda c: min((c + 4) >> 3, 0x1F) & 0x1F
    for i, (r, g, b) in enumerate(grouper(pal888, 3)):
        rgb = shrink(b) << 10 | shrink(g) << 5 | shrink(r)
        for enpg in enpgs:
            struct.pack_into('<H', enpg, 256**2 + 2 * i + 2, rgb)

    # Put the color indices in the enpgs
    for i, enpg in enumerate(enpgs):
        for y in range(256):
            for x in range(256):
                alpha = comb.getpixel((256 * i + x, y))[3]
                if alpha < 255:
                    col = 0
                else:
                    col = combQ.getpixel((256 * i + x, y)) + 1
                enpg[y * 256 + x] = col

    return enpgs
def test_unsupported_error():
    """
    Trigger LIQ_UNSUPPORTED and ensure that liq.UnsupportedError is
    raised
    """

    # A simple way of getting LIQ_UNSUPPORTED is adding more than 256
    # fixed colors to a histogram

    attr = liq.Attr()
    hist = liq.Histogram(attr)

    for i in range(256):
        hist.add_fixed_color(liq.Color(i, 0, 0, 255), 0)

    with pytest.raises(liq.UnsupportedError):
        hist.add_fixed_color(liq.Color(255, 255, 0, 255), 0)
def test_buffer_too_small_error():
    """
    Trigger LIQ_BUFFER_TOO_SMALL and ensure that liq.BufferTooSmallError
    is raised
    """

    # Load the background as an Image
    width, height, input_pixels = utils.load_test_image('test-card')
    attr = liq.Attr()
    background = attr.create_rgba(input_pixels, width, height, 0)

    def image_callback(value, image):
        # The image is too large, so using it as a background should fail
        with pytest.raises(liq.BufferTooSmallError):
            image.background = background

    utils.try_multiple_values('alpha-gradient', [None],
                              image_callback=image_callback)
示例#9
0
def main(argv):
    if len(argv) < 2:
        print('Please specify a path to a PNG file', file=sys.stderr)
        return 1

    input_png_file_path = argv[1]

    # Load PNG file and decode it as raw RGBA pixels
    # This uses the Pillow library for PNG reading (not part of libimagequant)

    img = PIL.Image.open(input_png_file_path).convert('RGBA')
    width = img.width
    height = img.height
    input_rgba_pixels = img.tobytes()

    # Use libimagequant to make a palette for the RGBA pixels

    attr = liq.Attr()
    input_image = attr.create_rgba(input_rgba_pixels, width, height, 0)

    result = input_image.quantize(attr)

    # Use libimagequant to make new image pixels from the palette

    result.dithering_level = 1.0

    raw_8bit_pixels = result.remap_image(input_image)
    palette = result.get_palette()

    # Save converted pixels as a PNG file
    # This uses the Pillow library for PNG writing (not part of libimagequant)
    img = PIL.Image.frombytes('P', (width, height), raw_8bit_pixels)

    palette_data = []
    for color in palette:
        palette_data.append(color.r)
        palette_data.append(color.g)
        palette_data.append(color.b)
    img.putpalette(palette_data)

    output_png_file_path = 'quantized_example.png'
    img.save(output_png_file_path)

    print('Written ' + output_png_file_path)
def test_histogram_add_fixed_color():
    """
    Test Histogram.add_fixed_color
    """
    width_A, height_A, input_pixels_A = utils.load_test_image('flower')
    width_B, height_B, input_pixels_B = utils.load_test_image('flower-huechange-1')
    assert width_A == width_B
    width, height = width_A, height_A

    attr = liq.Attr()
    hist = liq.Histogram(attr)

    image_A = attr.create_rgba(input_pixels_A, width, height, 0)
    hist.add_image(attr, image_A)

    image_B = attr.create_rgba(input_pixels_B, width, height, 0)
    hist.add_image(attr, image_B)

    FIXED_COLORS = [
        liq.Color(255, 0, 0, 255), # red
        liq.Color(0, 0, 255, 255), # blue
        liq.Color(128, 0, 128, 255), # purple
        liq.Color(255, 255, 0, 255), # yellow
    ]

    for fixedColor in FIXED_COLORS:
        hist.add_fixed_color(fixedColor, 0)

    result = hist.quantize(attr)
    result_palette = result.get_palette()

    # Check that we have a decently-sized palette
    assert len(result_palette) > 128

    # Try remapping both images -- make sure we don't get an exception
    # or something
    result.remap_image(image_A)
    result.remap_image(image_B)

    # Check that the fixed colors are present in the output palette
    for fixedColor in FIXED_COLORS:
        assert fixedColor in result_palette
示例#11
0
def try_multiple_values(img,
                        values,
                        *,
                        attr_callback=None,
                        image_callback=None,
                        result_callback=None,
                        allow_exceptions=False):
    """
    Helper function that lets you easily perform multiple quantizations
    and ensure that all of the outputs are different.
    Use attr_callback(value, attr) to modify the Attr object, and use
    result_callback(value, result) to modify the Result object.
    """
    width, height, input_pixels = load_test_image(img)

    tuples = []
    for value in values:
        attr = input_image = result = exception = None

        try:
            attr = liq.Attr()
            if attr_callback is not None:
                attr_callback(value, attr)

            input_image = attr.create_rgba(input_pixels, width, height, 0)
            if image_callback is not None:
                image_callback(value, input_image)

            result = input_image.quantize(attr)
            if result_callback is not None:
                result_callback(value, result)

        except Exception as e:
            if allow_exceptions:
                exception = e
            else:
                raise

        tuples.append((attr, input_image, result, exception))

    return tuples
示例#12
0
    def test_against(image_filename, points):
        png_in_check = png.Reader(filename=image_filename)

        width, height, data, info = png_in_check.read_flat()

        for pos, expected in points:
            start = (pos[1] * width + pos[0]) * 4
            assert data[start + 0] == expected[0]
            assert data[start + 1] == expected[1]
            assert data[start + 2] == expected[2]
            assert data[start + 3] == expected[3]

        attr = liq.Attr()
        png_in = png.Reader(filename=image_filename)
        img = liq_png.to_liq(png_in, attr)

        result = img.quantize(attr)
        png_out, data = liq_png.from_liq(result, img)

        temp_output_buffer = io.BytesIO()
        png_out.write_array(temp_output_buffer, data)

        temp_output_buffer.seek(0)
        rereader_check = png.Reader(file=temp_output_buffer)
        _, _, _, info = rereader_check.read()

        assert info.get('palette')

        temp_output_buffer.seek(0)
        rereader = png.Reader(file=temp_output_buffer)
        _, _, data, _ = rereader.asRGBA()
        data = list(data)  # so we can index into it

        for (x, y), expected in points:
            r, g, b, a = data[y][x * 4:x * 4 + 4]
            print((x, y), expected, (r, g, b, a))
            assert near(r, expected[0])
            assert near(g, expected[1])
            assert near(b, expected[2])
            assert near(a, expected[3])
示例#13
0
    def test_against(image_filename, points):
        sk_in = skimage.io.imread(image_filename)
        assert sk_in.shape[2] == 4

        for (x, y), expected in points:
            assert np.array_equal(sk_in[y, x], np.array(expected))

        attr = liq.Attr()
        img = liq_skimage.to_liq(sk_in, attr)

        result = img.quantize(attr)
        sk_out_px, sk_out_pal = liq_skimage.from_liq(result, img)

        assert sk_out_px.shape[2] == 1
        assert sk_out_pal.shape[1] == 4

        for (x, y), expected in points:
            r, g, b, a = sk_out_pal[sk_out_px[y, x][0]]
            print((x, y), expected, (r, g, b, a))
            assert near(r, expected[0])
            assert near(g, expected[1])
            assert near(b, expected[2])
            assert near(a, expected[3])
示例#14
0
    def test_against(image_filename, points):
        pil_in = PIL.Image.open(image_filename)

        for pos, expected in points:
            assert pil_in.getpixel(pos) == expected

        attr = liq.Attr()
        img = liq_PIL.to_liq(pil_in, attr)

        result = img.quantize(attr)
        pil_out = liq_PIL.from_liq(result, img)

        assert pil_out.mode == 'P'

        pil_out_rgba = pil_out.convert('RGBA')

        for pos, expected in points:
            r, g, b, a = pil_out_rgba.getpixel(pos)
            print(pos, expected, (r, g, b, a))
            assert near(r, expected[0])
            assert near(g, expected[1])
            assert near(b, expected[2])
            assert near(a, expected[3])
def test_histogram_basic():
    """
    Basic test of Histogram:
    - __init__()
    - add_image()
    - quantize()
    """
    # Testing with three input images
    width_A, height_A, input_pixels_A = utils.load_test_image('flower')
    width_B, height_B, input_pixels_B = utils.load_test_image('flower-huechange-1')
    width_C, height_C, input_pixels_C = utils.load_test_image('flower-huechange-2')
    assert width_A == width_B == width_C
    assert height_A == height_B == height_C
    width, height = width_A, height_A

    attr = liq.Attr()
    hist = liq.Histogram(attr)

    image_A = attr.create_rgba(input_pixels_A, width, height, 0)
    hist.add_image(attr, image_A)

    image_B = attr.create_rgba(input_pixels_B, width, height, 0)
    hist.add_image(attr, image_B)

    image_C = attr.create_rgba(input_pixels_C, width, height, 0)
    hist.add_image(attr, image_C)

    result = hist.quantize(attr)

    # Check that we have a decently-sized palette
    assert len(result.get_palette()) > 128

    # Try remapping all three images -- make sure we don't get an
    # exception or something
    result.remap_image(image_A)
    result.remap_image(image_B)
    result.remap_image(image_C)
示例#16
0
def saveImagePair(img1, img2, fn1, fn2, rom, firstFileID):
    """
    Palette-reduce the two images to 256-colors (both with the same
    palette), save them as PNGs, and save them as ENPGs
    Currently assumes both images are 256x256.
    """

    # Temp
    img1.save('out-png/' + fn1 + '.png')
    img2.save('out-png/' + fn2 + '.png')

    # Convert both to PIL Images
    pimg1, pimg2 = map(qImageToPilImage, [img1, img2])

    # Combine
    comb = PIL.Image.new('RGBA', (512, 256), (0, 0, 0, 0))
    comb.paste(pimg1, (0, 0))
    comb.paste(pimg2, (256, 0))

    # Quantize
    # combQ = comb.quantize(255, 3) # leave one color for transparent
    attr = liq.Attr()
    attr.max_colors = 255 # leave one color for transparent
    comb_liq = libimagequant_integrations.PIL.to_liq(comb, attr)
    combQ = libimagequant_integrations.PIL.from_liq(comb_liq.quantize(attr), comb_liq)

    # Create the ENPG data arrays
    ENPG_LEN = 256 * 256 + 256 * 2
    enpg1, enpg2 = bytearray(ENPG_LEN), bytearray(ENPG_LEN)

    # Convert the palette to RGB555 and put it in both the enpgs
    pal888 = combQ.getpalette()[:255*3]
    struct.pack_into('<H', enpg1, 256**2, 0x8000)
    struct.pack_into('<H', enpg2, 256**2, 0x8000)
    shrink = lambda c: min((c + 4) >> 3, 0x1F) & 0x1F
    for i, (r, g, b) in enumerate(grouper(pal888, 3)):
        rgb = shrink(b) << 10 | shrink(g) << 5 | shrink(r)
        struct.pack_into('<H', enpg1, 256**2 + 2 * i + 2, rgb)
        struct.pack_into('<H', enpg2, 256**2 + 2 * i + 2, rgb)

    # Put the color indices in the enpgs
    for y in range(256):
        for x in range(256):
            alpha = comb.getpixel((x, y))[3]
            if alpha < 255:
                col = 0
            else:
                col = combQ.getpixel((x, y)) + 1
            enpg1[y * 256 + x] = col
    for y in range(256):
        for x in range(256):
            alpha = comb.getpixel((x + 256, y))[3]
            if alpha < 255:
                col = 0
            else:
                col = combQ.getpixel((x + 256, y)) + 1
            enpg2[y * 256 + x] = col

    # Compress them
    enpg1Compressed = ndspy.lz10.compress(enpg1)
    enpg2Compressed = ndspy.lz10.compress(enpg2)

    # Save them
    with open('out-enpg/' + fn1 + '.enpg', 'wb') as f:
        f.write(enpg1)
    with open('out-enpg/' + fn2 + '.enpg', 'wb') as f:
        f.write(enpg2)
    with open('out-enpg-lz/' + fn1 + '.enpg', 'wb') as f:
        f.write(enpg1Compressed)
    with open('out-enpg-lz/' + fn2 + '.enpg', 'wb') as f:
        f.write(enpg2Compressed)

    # Insert them into the rom
    rom.files[firstFileID] = enpg1Compressed
    rom.files[firstFileID + 1] = enpg2Compressed
    rom.filenames['zc_crsin'].files[firstFileID - rom.filenames['zc_crsin'].firstID] = f'{fn1}.enpg'
    rom.filenames['zc_crsin'].files[firstFileID - rom.filenames['zc_crsin'].firstID + 1] = f'{fn2}.enpg'

    # Render them as PNGs and save them elsewhere (for quality inspection)
    enpgPng1, enpgPng2 = map(enpgToImage, [enpg1, enpg2])
    enpgPng1.save('out-enpg-png/' + fn1 + '.png')
    enpgPng2.save('out-enpg-png/' + fn2 + '.png')
def test_histogram_add_colors():
    """
    Test Histogram.add_colors(), as well as the HistogramEntry class
    """

    # First, quantize flower-huechange-1.jpg on its own
    width, height, input_pixels = utils.load_test_image('flower-huechange-1')
    attr = liq.Attr()
    other_image = attr.create_rgba(input_pixels, width, height, 0)
    result = other_image.quantize(attr)
    result_pixels = result.remap_image(other_image)
    result_palette = result.get_palette()

    # ~

    # Create a list of HistogramEntrys for it
    entries = []
    for i, color in enumerate(result_palette):
        count = result_pixels.count(i)

        entry = liq.HistogramEntry(color, count)
        entries.append(entry)

        # Test HistogramEntry getters
        assert entry.color == color
        assert entry.count == count

        # Test setters
        entry.color = result_palette[0]
        entry.count = 50
        assert entry.color == result_palette[0]
        assert entry.count == 50

        # (Set properties back to what they should be)
        entry.color = color
        entry.count = count

    assert entries

    # ~

    # Set up a Histogram
    attr = liq.Attr()
    hist = liq.Histogram(attr)

    # Add flower.jpg as an image
    width, height, input_pixels = utils.load_test_image('flower')
    image = attr.create_rgba(input_pixels, width, height, 0)
    hist.add_image(attr, image)

    # Add the HistogramEntrys for flower-huechange-1.jpg
    hist.add_colors(attr, entries, 0)

    # And quantize
    result = hist.quantize(attr)

    # ~

    # Check that we have a decently-sized palette
    assert len(result.get_palette()) > 128

    # Try remapping both images -- make sure we don't get an exception
    # or something
    result.remap_image(image)
    result.remap_image(other_image)