mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-25 17:36:18 +03:00
Merge branch 'master' of https://github.com/python-imaging/Pillow
This commit is contained in:
commit
a05bf23b05
|
@ -433,8 +433,9 @@ class Parser:
|
|||
# @param im Image object.
|
||||
# @param fp File object.
|
||||
# @param tile Tile list.
|
||||
# @param bufsize Optional buffer size
|
||||
|
||||
def _save(im, fp, tile):
|
||||
def _save(im, fp, tile, bufsize=0):
|
||||
"Helper to save image based on tile list"
|
||||
|
||||
im.load()
|
||||
|
@ -442,7 +443,10 @@ def _save(im, fp, tile):
|
|||
im.encoderconfig = ()
|
||||
tile.sort(key=_tilesort)
|
||||
# FIXME: make MAXBLOCK a configuration parameter
|
||||
bufsize = max(MAXBLOCK, im.size[0] * 4) # see RawEncode.c
|
||||
# It would be great if we could have the encoder specifiy what it needs
|
||||
# But, it would need at least the image size in most cases. RawEncode is
|
||||
# a tricky case.
|
||||
bufsize = max(MAXBLOCK, bufsize, im.size[0] * 4) # see RawEncode.c
|
||||
try:
|
||||
fh = fp.fileno()
|
||||
fp.flush()
|
||||
|
|
|
@ -554,7 +554,15 @@ def _save(im, fp, filename):
|
|||
info.get("exif", b"")
|
||||
)
|
||||
|
||||
ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)])
|
||||
# if we optimize, libjpeg needs a buffer big enough to hold the whole image in a shot.
|
||||
# Guessing on the size, at im.size bytes. (raw pizel size is channels*size, this
|
||||
# is a value that's been used in a django patch.
|
||||
# https://github.com/jdriscoll/django-imagekit/issues/50
|
||||
bufsize=0
|
||||
if "optimize" in info:
|
||||
bufsize = im.size[0]*im.size[1]
|
||||
|
||||
ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)], bufsize)
|
||||
|
||||
def _save_cjpeg(im, fp, filename):
|
||||
# ALTERNATIVE: handle JPEGs via the IJG command line utilities.
|
||||
|
|
|
@ -1202,7 +1202,7 @@ PySane_get_devices(PyObject *self, PyObject *args)
|
|||
const SANE_Device *dev;
|
||||
SANE_Status st;
|
||||
PyObject *list;
|
||||
int local_only, i;
|
||||
int local_only = 0, i;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|i", &local_only))
|
||||
{
|
||||
|
|
|
@ -113,6 +113,13 @@ def test_optimize():
|
|||
assert_image_equal(im1, im2)
|
||||
assert_true(im1.bytes >= im2.bytes)
|
||||
|
||||
def test_optimize_large_buffer():
|
||||
#https://github.com/python-imaging/Pillow/issues/148
|
||||
f = tempfile('temp.jpg')
|
||||
# this requires ~ 1.5x Image.MAXBLOCK
|
||||
im = Image.new("RGB", (4096,4096), 0xff3333)
|
||||
im.save(f, format="JPEG", optimize=True)
|
||||
|
||||
def test_progressive():
|
||||
im1 = roundtrip(lena())
|
||||
im2 = roundtrip(lena(), progressive=1)
|
||||
|
|
|
@ -2,7 +2,7 @@ from tester import *
|
|||
|
||||
from PIL import Image
|
||||
|
||||
def test_read():
|
||||
def xtest_read():
|
||||
""" Can we write a webp without error. Does it have the bits we expect?"""
|
||||
|
||||
file = "Images/lena.webp"
|
||||
|
@ -37,7 +37,18 @@ def test_write():
|
|||
assert_no_exception(lambda: im.load())
|
||||
assert_no_exception(lambda: im.getdata())
|
||||
|
||||
# If we're using the exact same version of webp, this test should pass.
|
||||
# but it doesn't if the webp is generated on Ubuntu and tested on Fedora.
|
||||
|
||||
# generated with: dwebp -ppm temp.webp -o lena_webp_write.ppm
|
||||
target = Image.open('Tests/images/lena_webp_write.ppm')
|
||||
assert_image_equal(im, target)
|
||||
#target = Image.open('Tests/images/lena_webp_write.ppm')
|
||||
#assert_image_equal(im, target)
|
||||
|
||||
# This test asserts that the images are similar. If the average pixel difference
|
||||
# between the two images is less than the epsilon value, then we're going to
|
||||
# accept that it's a reasonable lossy version of the image. The included lena images
|
||||
# for webp are showing ~16 on Ubuntu, the jpegs are showing ~18.
|
||||
target = lena('RGB')
|
||||
assert_image_similar(im, target, 20.0)
|
||||
|
||||
|
||||
|
|
|
@ -150,6 +150,26 @@ def assert_image_equal(a, b, msg=None):
|
|||
else:
|
||||
success()
|
||||
|
||||
def assert_image_similar(a, b, epsilon, msg=None):
|
||||
epsilon = float(epsilon)
|
||||
if a.mode != b.mode:
|
||||
return failure(msg or "got mode %r, expected %r" % (a.mode, b.mode))
|
||||
elif a.size != b.size:
|
||||
return failure(msg or "got size %r, expected %r" % (a.size, b.size))
|
||||
diff = 0
|
||||
try:
|
||||
ord(b'0')
|
||||
for abyte,bbyte in zip(a.tobytes(),b.tobytes()):
|
||||
diff += abs(ord(abyte)-ord(bbyte))
|
||||
except:
|
||||
for abyte,bbyte in zip(a.tobytes(),b.tobytes()):
|
||||
diff += abs(abyte-bbyte)
|
||||
ave_diff = float(diff)/(a.size[0]*a.size[1])
|
||||
if epsilon < ave_diff:
|
||||
failure(msg or "average pixel value difference %.4f > epsilon %.4f" %(ave_diff, epsilon))
|
||||
else:
|
||||
success()
|
||||
|
||||
def tempfile(template, *extra):
|
||||
import os, sys
|
||||
files = []
|
||||
|
|
|
@ -12,81 +12,84 @@
|
|||
#include "Imaging.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 r;
|
||||
UINT8 g;
|
||||
UINT8 b;
|
||||
UINT8 a;
|
||||
} rgba8;
|
||||
|
||||
|
||||
|
||||
Imaging
|
||||
ImagingAlphaComposite(Imaging imDst, Imaging imSrc)
|
||||
{
|
||||
Imaging imOut;
|
||||
int x, y;
|
||||
float dstR, dstG, dstB, dstA;
|
||||
float srcR, srcG, srcB, srcA;
|
||||
float outR, outG, outB, outA;
|
||||
|
||||
/* Check arguments */
|
||||
if (!imDst || !imSrc ||
|
||||
strcmp(imDst->mode, "RGBA") ||
|
||||
imDst->type != IMAGING_TYPE_UINT8 ||
|
||||
imDst->bands != 4)
|
||||
return ImagingError_ModeError();
|
||||
strcmp(imDst->mode, "RGBA") ||
|
||||
imDst->type != IMAGING_TYPE_UINT8 ||
|
||||
imDst->bands != 4)
|
||||
return ImagingError_ModeError();
|
||||
|
||||
if (strcmp(imDst->mode, imSrc->mode) ||
|
||||
imDst->type != imSrc->type ||
|
||||
imDst->bands != imSrc->bands ||
|
||||
imDst->xsize != imSrc->xsize ||
|
||||
imDst->ysize != imSrc->ysize)
|
||||
return ImagingError_Mismatch();
|
||||
imDst->type != imSrc->type ||
|
||||
imDst->bands != imSrc->bands ||
|
||||
imDst->xsize != imSrc->xsize ||
|
||||
imDst->ysize != imSrc->ysize)
|
||||
return ImagingError_Mismatch();
|
||||
|
||||
imOut = ImagingNew(imDst->mode, imDst->xsize, imDst->ysize);
|
||||
if (!imOut)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
ImagingCopyInfo(imOut, imDst);
|
||||
|
||||
for (y = 0; y < imDst->ysize; y++) {
|
||||
|
||||
UINT8* dst = (UINT8*) imDst->image[y];
|
||||
UINT8* src = (UINT8*) imSrc->image[y];
|
||||
UINT8* out = (UINT8*) imOut->image[y];
|
||||
rgba8* dst = (rgba8*) imDst->image[y];
|
||||
rgba8* src = (rgba8*) imSrc->image[y];
|
||||
rgba8* out = (rgba8*) imOut->image[y];
|
||||
|
||||
for (x = 0; x < imDst->linesize; x += 4) {
|
||||
for (x = 0; x < imDst->xsize; x ++) {
|
||||
|
||||
dstR = dst[x + 0] / 255.0;
|
||||
dstG = dst[x + 1] / 255.0;
|
||||
dstB = dst[x + 2] / 255.0;
|
||||
dstA = dst[x + 3] / 255.0;
|
||||
if (src->a == 0) {
|
||||
// Copy 4 bytes at once.
|
||||
*out = *dst;
|
||||
} else {
|
||||
// Integer implementation with increased precision.
|
||||
// Each variable has extra meaningful bits.
|
||||
// Divisions are rounded.
|
||||
|
||||
srcR = src[x + 0] / 255.0;
|
||||
srcG = src[x + 1] / 255.0;
|
||||
srcB = src[x + 2] / 255.0;
|
||||
srcA = src[x + 3] / 255.0;
|
||||
// This code uses trick from Paste.c:
|
||||
// (a + (2 << (n-1)) - 1) / ((2 << n)-1)
|
||||
// almost equivalent to:
|
||||
// tmp = a + (2 << (n-1)), ((tmp >> n) + tmp) >> n
|
||||
|
||||
if (dstA == 1.0) {
|
||||
outR = srcR * srcA + dstR * (1.0 - srcA);
|
||||
outG = srcG * srcA + dstG * (1.0 - srcA);
|
||||
outB = srcB * srcA + dstB * (1.0 - srcA);
|
||||
outA = 1.0;
|
||||
} else if (srcA == 0.0) {
|
||||
outR = dstR;
|
||||
outG = dstG;
|
||||
outB = dstB;
|
||||
outA = dstA;
|
||||
} else {
|
||||
outA = srcA + dstA * (1.0 - srcA);
|
||||
if (outA == 0.0) {
|
||||
outR = 0.0;
|
||||
outG = 0.0;
|
||||
outB = 0.0;
|
||||
} else {
|
||||
outR = (srcR * srcA + dstR * dstA * (1.0 - srcA)) / outA;
|
||||
outG = (srcG * srcA + dstG * dstA * (1.0 - srcA)) / outA;
|
||||
outB = (srcB * srcA + dstB * dstA * (1.0 - srcA)) / outA;
|
||||
}
|
||||
}
|
||||
UINT16 blend = dst->a * (255 - src->a);
|
||||
UINT16 outa255 = src->a * 255 + blend;
|
||||
// There we use 7 bits for precision.
|
||||
// We could use more, but we go beyond 32 bits.
|
||||
UINT16 coef1 = src->a * 255 * 255 * 128 / outa255;
|
||||
UINT16 coef2 = blend * 255 * 128 / outa255;
|
||||
|
||||
out[x + 0] = (UINT8) (255.0 * outR + 0.5);
|
||||
out[x + 1] = (UINT8) (255.0 * outG + 0.5);
|
||||
out[x + 2] = (UINT8) (255.0 * outB + 0.5);
|
||||
out[x + 3] = (UINT8) (255.0 * outA + 0.5);
|
||||
#define SHIFTFORDIV255(a)\
|
||||
((a >> 8) + a >> 8)
|
||||
|
||||
}
|
||||
UINT32 tmpr = src->r * coef1 + dst->r * coef2 + (0x80 << 7);
|
||||
out->r = SHIFTFORDIV255(tmpr) >> 7;
|
||||
UINT32 tmpg = src->g * coef1 + dst->g * coef2 + (0x80 << 7);
|
||||
out->g = SHIFTFORDIV255(tmpg) >> 7;
|
||||
UINT32 tmpb = src->b * coef1 + dst->b * coef2 + (0x80 << 7);
|
||||
out->b = SHIFTFORDIV255(tmpb) >> 7;
|
||||
out->a = SHIFTFORDIV255(outa255 + 0x80);
|
||||
}
|
||||
|
||||
dst++; src++; out++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user