~divmod-dev/divmod.org/no-non-executables-bincache-1625

« back to all changes in this revision

Viewing changes to Mantissa/xmantissa/test/test_people.py

  • Committer: pjd
  • Date: 2008-02-21 23:28:16 UTC
  • Revision ID: svn-v4:866e43f7-fbfc-0310-8f2a-ec88d1da2979:trunk:14992
Merge mugshot-resize-2385

Author: pjd
Reviewer: oubiwann
Fixes #2385

This fixes thumbnailing of paletted and bicolor mugshot images to avoid heavy
aliasing due to nearest-neighbor sampling.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
"""
3
3
Tests for L{xmantissa.people}.
4
4
"""
 
5
from __future__ import division
 
6
 
5
7
import warnings
6
8
 
7
9
from zope.interface import implements
175
177
        self.assertEqual(output['b'], u'c')
176
178
 
177
179
 
178
 
    def test_makeThumbnail(self):
 
180
    def _makeThumbnailPairs(self, inputSizes, outputSize):
179
181
        """
180
 
        Verify that L{makeThumbnail} makes a correctly scaled thumbnail image.
 
182
        Generate a collection of L{makeThumbnail} input/output image pairs in
 
183
        various formats, for the given input sizes.
181
184
        """
182
185
        try:
183
186
            from PIL import Image
184
187
        except ImportError:
185
188
            raise unittest.SkipTest('PIL is not available')
186
 
 
187
 
        # make an image to thumbnail
188
 
        fullSizePath = self.mktemp()
189
 
        fullSizeFormat = 'JPEG'
190
 
        fullWidth = 543
191
 
        fullHeight = 102
192
 
        Image.new('RGB', (fullWidth, fullHeight)).save(
193
 
            file(fullSizePath, 'w'), fullSizeFormat)
194
 
        # thumbnail it
195
 
        thumbnailPath = self.mktemp()
196
 
        thumbnailSize = 60
197
 
        thumbnailFormat = 'TIFF'
198
 
        makeThumbnail(
199
 
            fullSizePath, thumbnailPath, thumbnailSize, thumbnailFormat)
200
 
        # open the thumbnail, make sure it's the right size and format
201
 
        thumbnailImage = Image.open(file(thumbnailPath))
202
 
        scaleFactor = float(thumbnailSize) / fullWidth
203
 
        expectedHeight = int(fullHeight * scaleFactor)
204
 
        self.assertEqual(
205
 
            thumbnailImage.size, (thumbnailSize, expectedHeight))
206
 
        self.assertEqual(thumbnailImage.format, thumbnailFormat)
207
 
        # make sure the original image is untouched
208
 
        originalImage = Image.open(file(fullSizePath))
209
 
        self.assertEqual(originalImage.format, fullSizeFormat)
210
 
        self.assertEqual(originalImage.size, (fullWidth, fullHeight))
 
189
        formatsToModes = {
 
190
            'JPEG': ['L', 'RGB'],
 
191
            'PNG': ['1', 'L', 'P', 'RGB', 'RGBA'],
 
192
        }
 
193
        modesToWhite = {
 
194
            '1': 1,
 
195
            'L': 0xFF,
 
196
            'P': 0xFF,
 
197
            'RGB': (0xFF, 0xFF, 0xFF),
 
198
            'RGBA': (0xFF, 0xFF, 0xFF, 0xFF),
 
199
        }
 
200
        for format in formatsToModes:
 
201
            for mode in formatsToModes[format]:
 
202
                for inputSize in inputSizes:
 
203
                    cause = ('Image.new(%r, %r) via %s'
 
204
                             % (mode, inputSize, format))
 
205
                    (inFile, outFile) = (self.mktemp(), self.mktemp())
 
206
                    # Input image...
 
207
                    image = Image.new(mode, inputSize)
 
208
                    # Plot pixels along the diagonal to provoke aliasing.
 
209
                    for i in xrange(min(inputSize)):
 
210
                        image.putpixel((i, i), modesToWhite[mode])
 
211
                    image.save(file(inFile, 'w'), format)
 
212
                    self.assertEqual(Image.open(inFile).mode, mode, cause)
 
213
                    untouchedInput = file(inFile).read()
 
214
                    # Output image...
 
215
                    makeThumbnail(file(inFile), file(outFile, 'w'),
 
216
                                  outputSize, format)
 
217
                    self.assertEqual(file(inFile).read(), untouchedInput, cause)
 
218
                    yield (Image.open(inFile), Image.open(outFile), cause)
 
219
 
 
220
 
 
221
    def test_makeThumbnail(self):
 
222
        """
 
223
        L{makeThumbnail} should scale images, preserving their aspect ratio, and
 
224
        expanding their color space if necessary.
 
225
        """
 
226
        sizes = [(x, y) for x in [30, 60, 120]
 
227
                        for y in [30, 60, 120]
 
228
                        if 60 < max(x, y)]
 
229
        for (input, output, cause) in self._makeThumbnailPairs(sizes, 60):
 
230
            (x1, y1) = input.size
 
231
            (x2, y2) = output.size
 
232
            self.assertEquals(max(x2, y2), 60, cause)
 
233
            self.assertEquals(x2/y2, x1/y1, cause)
 
234
            expectedMode = {'1': 'L', 'P': 'RGB'}.get(input.mode, input.mode)
 
235
            self.assertEquals(output.mode, expectedMode, cause)
 
236
            self.assertEquals(output.format, input.format, cause)
 
237
            # Compare the output color distribution to Image.ANTIALIAS sampling.
 
238
            # (Skip JPEG due to interfering noise.)
 
239
            if output.format != 'JPEG':
 
240
                expectedColors = (9, 13)[input.size != (120, 120)]
 
241
                self.assertEqual(len(output.getcolors()), expectedColors, cause)
 
242
                if 1 < len(output.getbands()):  # Ugh.
 
243
                    for extrema in output.getextrema():
 
244
                        self.assertEqual(extrema, (0, 119), cause)
 
245
                else:
 
246
                    self.assertEqual(output.getextrema(), (0, 119), cause)
 
247
 
 
248
 
 
249
    def test_makeThumbnailNoResize(self):
 
250
        """
 
251
        L{makeThumbnail} should leave images under thumbnail size unchanged.
 
252
        """
 
253
        sizes = [(x, y) for x in [30, 60]
 
254
                        for y in [30, 60]]
 
255
        for (input, output, cause) in self._makeThumbnailPairs(sizes, 60):
 
256
            self.assertEquals(output.size, input.size, cause)
 
257
            self.assertEquals(output.mode, input.mode, cause)
 
258
            self.assertEquals(output.format, input.format, cause)
211
259
 
212
260
 
213
261
    def test_descriptiveIdentifier(self):