Exemplo n.º 1
0
    def test_save_cjpeg(self):
        img = Image.open(TEST_FILE)

        tempfile = self.tempfile("temp.jpg")
        JpegImagePlugin._save_cjpeg(img, 0, tempfile)
        # Default save quality is 75%, so a tiny bit of difference is alright
        self.assert_image_similar(img, Image.open(tempfile), 17)
Exemplo n.º 2
0
    def test_save_cjpeg(self):
        img = Image.open(TEST_FILE)

        tempfile = self.tempfile("temp.jpg")
        JpegImagePlugin._save_cjpeg(img, 0, tempfile)
        # Default save quality is 75%, so a tiny bit of difference is alright
        self.assert_image_similar(img, Image.open(tempfile), 17)
Exemplo n.º 3
0
    def test_jpeg(self):
        path = os.path.join(TEST_DATA_PATH, "Sam_Hat1.jpg")
        image = Image.objects.create_from_path(path)

        # Re-load the image, now that the task is done
        image = Image.objects.get(id=image.id)

        self.assertTrue(image.source.path.endswith("Sam_Hat1.jpg"))
        self.assertEqual(image.width, 3264)
        self.assertEqual(image.height, 2448)
        self.assertEqual(image.jpeg_quality, None)
        self.assertTrue(os.path.exists(image.optimized.path))
        self.assertTrue(os.path.exists(image.source.path))

        source = PILImage.open(image.source.path)
        optimized = PILImage.open(image.optimized.path)

        self.assertEqual(
            source.quantization,
            optimized.quantization
        )

        self.assertEqual(
            JpegImagePlugin.get_sampling(source),
            JpegImagePlugin.get_sampling(optimized),
        )
Exemplo n.º 4
0
def read_q_table(file_name):
    jpg = JpegImagePlugin.JpegImageFile(file_name)
    qtable = JpegImagePlugin.convert_dict_qtables(jpg.quantization)
    Y_qtable = qtable[0]
    Y_qtable_2d = np.zeros((8, 8))

    qtable_idx = 0
    for i in range(0, 8):
        for j in range(0, 8):
            Y_qtable_2d[i, j] = Y_qtable[qtable_idx]
            qtable_idx = qtable_idx + 1

    return Y_qtable_2d
Exemplo n.º 5
0
    def create_image(self, buffer):
        try:
            img = Image.open(BytesIO(buffer))
        except DECOMPRESSION_BOMB_EXCEPTIONS as error:
            logger.warning("[PILEngine] create_image failed: %s", error)

            return None
        self.icc_profile = img.info.get("icc_profile")
        self.exif = img.info.get("exif")
        self.original_mode = img.mode

        self.subsampling = JpegImagePlugin.get_sampling(img)

        if self.subsampling == -1:  # n/a for this file
            self.subsampling = None
        self.qtables = getattr(img, "quantization", None)

        if (self.context.config.ALLOW_ANIMATED_GIFS
                and self.extension == ".gif"):
            frames = []

            for frame in ImageSequence.Iterator(img):
                frames.append(frame.convert("P"))
            img.seek(0)
            self.frame_count = len(frames)

            return frames

        return img
Exemplo n.º 6
0
def optimize_image(image_model, image_buffer, filename):

    im = PILImage.open(image_buffer)

    # Let's cache some important stuff
    format = im.format
    icc_profile = im.info.get("icc_profile")
    quantization = getattr(im, "quantization", None)
    subsampling = None
    if format == "JPEG":
        try:
            subsampling = JpegImagePlugin.get_sampling(im)
        except IndexError:
            # Ignore if sampling fails
            logger.debug('JPEG sampling failed, ignoring')
        except:
            # mparent(2016-03-25): Eventually eliminate "catch all", but need to log errors to see
            # if we're missing any other exception types in the wild
            logger.exception('JPEG sampling error')

    if im.size[0] > settings.BETTY_MAX_WIDTH:
        # If the image is really large, we'll save a more reasonable version as the "original"
        height = settings.BETTY_MAX_WIDTH * float(im.size[1]) / float(im.size[0])
        im = im.resize((settings.BETTY_MAX_WIDTH, int(round(height))), PILImage.ANTIALIAS)

        out_buffer = io.BytesIO()
        if format == "JPEG" and im.mode == "RGB":
            # For JPEG files, we need to make sure that we keep the quantization profile
            try:
                im.save(
                    out_buffer,
                    icc_profile=icc_profile,
                    qtables=quantization,
                    subsampling=subsampling,
                    format="JPEG")
            except ValueError as e:
                # Maybe the image already had an invalid quant table?
                if e.args[:1] == ('Invalid quantization table',):
                    out_buffer = io.BytesIO()  # Make sure it's empty after failed save attempt
                    im.save(
                        out_buffer,
                        icc_profile=icc_profile,
                        format=format,
                    )
                else:
                    raise
        else:
            im.save(out_buffer,
                    icc_profile=icc_profile,
                    format=format)

        image_model.optimized.save(filename, File(out_buffer))

    else:
        # No modifications, just save original as optimized
        image_buffer.seek(0)
        image_model.optimized.save(filename, File(image_buffer))

    image_model.save()
Exemplo n.º 7
0
def save_image(img, fname):
    print(fname)
    quantization = getattr(img, 'quantization', None)
    subsampling = JpegImagePlugin.get_sampling(img) if quantization else None
    if subsampling:
        img.save(fname, subsampling=subsampling, qtables=quantization)
    else:
        img.save(fname)
Exemplo n.º 8
0
def optimize_image(image):

    im = PILImage.open(image.source.path)
    
    # Let's cache some important stuff
    format = im.format
    icc_profile = im.info.get("icc_profile")
    quantization = getattr(im, "quantization", None)
    subsampling = None
    if format == "JPEG":
        try:
            subsampling = JpegImagePlugin.get_sampling(im)
        except:
            pass  # Sometimes, crazy images exist.

    filename = os.path.split(image.source.path)[1]

    if im.size[0] > settings.BETTY_MAX_WIDTH:
        # If the image is really large, we'll save a more reasonable version as the "original"
        height = settings.BETTY_MAX_WIDTH * float(im.size[1]) / float(im.size[0])
        im = im.resize((settings.BETTY_MAX_WIDTH, int(round(height))), PILImage.ANTIALIAS)

        """OK, so this suuuuuucks. When we convert or resize an Image, it
        is no longer a JPEG. So, in order to reset the quanitzation, etc,
        we need to save this to a file and then re-read it from the
        filesystem. Silly, I know. Once my pull request is approved, this
        can be removed, and we can just pass the qtables into the save method.
        PR is here: https://github.com/python-imaging/Pillow/pull/677
        """
        temp = tempfile.NamedTemporaryFile()
        im.save(temp, format="JPEG")
        temp.seek(0)
        im = PILImage.open(temp)

        im.quantization = quantization

    image.optimized.name = optimized_upload_to(image, filename)
    if format == "JPEG" and im.mode == "RGB":
        # For JPEG files, we need to make sure that we keep the quantization profile
        try:
            im.save(
                image.optimized.name,
                icc_profile=icc_profile,
                quality="keep",
                subsampling=subsampling)
        except (TypeError, ValueError) as e:
            # Maybe the image already had an invalid quant table?
            if e.message.startswith("Not a valid numbers of quantization tables"):
                im.save(
                    image.optimized.name,
                    icc_profile=icc_profile
                )
            else:
                raise
    else:
        im.save(image.optimized.name, icc_profile=icc_profile)
    image.save()
Exemplo n.º 9
0
        def decode_jpeg(encoded,
                        tables=b'',
                        photometric=None,
                        ycbcr_subsampling=None,
                        ycbcr_positioning=None):
            ''' ycbcr resampling is missing in both tifffile and PIL '''
            from StringIO import StringIO
            from PIL import JpegImagePlugin

            return JpegImagePlugin.JpegImageFile(StringIO(tables +
                                                          encoded)).tobytes()
Exemplo n.º 10
0
def test_jpeg():
    shutil.rmtree(bettysettings.BETTY_IMAGE_ROOT, ignore_errors=True)

    path = os.path.join(TEST_DATA_PATH, "Sam_Hat1.jpg")
    image = Image.objects.create_from_path(path)

    # Re-load the image, now that the task is done
    image = Image.objects.get(id=image.id)

    assert image.source.path.endswith("Sam_Hat1.jpg")
    assert image.width == 3264
    assert image.height == 2448
    assert image.jpeg_quality is None
    assert os.path.exists(image.optimized.path)
    assert os.path.exists(image.source.path)

    source = PILImage.open(image.source.path)
    optimized = PILImage.open(image.optimized.path)

    assert source.quantization == optimized.quantization
    assert JpegImagePlugin.get_sampling(source) == JpegImagePlugin.get_sampling(optimized)
Exemplo n.º 11
0
def test_jpeg():

    path = os.path.join(TEST_DATA_PATH, "Sam_Hat1.jpg")
    image = Image.objects.create_from_path(path)

    # Re-load the image, now that the task is done
    image = Image.objects.get(id=image.id)

    assert image.source.path.endswith("Sam_Hat1.jpg")
    assert image.width == 3264
    assert image.height == 2448
    assert image.jpeg_quality is None
    assert os.path.exists(image.optimized.path)
    assert os.path.exists(image.source.path)
    assert not image.animated

    source = PILImage.open(image.source.path)
    optimized = PILImage.open(image.optimized.path)

    assert source.quantization == optimized.quantization
    assert JpegImagePlugin.get_sampling(source) == JpegImagePlugin.get_sampling(optimized)
Exemplo n.º 12
0
def optimize_image(image):

    im = PILImage.open(image.source.path)

    # Let's cache some important stuff
    format = im.format
    icc_profile = im.info.get("icc_profile")
    quantization = getattr(im, "quantization", None)
    subsampling = None
    if format == "JPEG":
        try:
            subsampling = JpegImagePlugin.get_sampling(im)
        except:
            pass  # Sometimes, crazy images exist.

    filename = os.path.split(image.source.path)[1]

    image.optimized.name = optimized_upload_to(image, filename)
    if im.size[0] > settings.BETTY_MAX_WIDTH:
        # If the image is really large, we'll save a more reasonable version as the "original"
        height = settings.BETTY_MAX_WIDTH * float(im.size[1]) / float(im.size[0])
        im = im.resize((settings.BETTY_MAX_WIDTH, int(round(height))), PILImage.ANTIALIAS)

        if format == "JPEG" and im.mode == "RGB":
            # For JPEG files, we need to make sure that we keep the quantization profile
            try:
                im.save(
                    image.optimized.name,
                    icc_profile=icc_profile,
                    qtables=quantization,
                    subsampling=subsampling,
                    format="JPEG")
            except (TypeError, ValueError) as e:
                # Maybe the image already had an invalid quant table?
                if e.message.startswith("Not a valid numbers of quantization tables"):
                    im.save(
                        image.optimized.name,
                        icc_profile=icc_profile
                    )
                else:
                    raise
        else:
            im.save(image.optimized.name, icc_profile=icc_profile)
    else:
        shutil.copy2(image.source.path, image.optimized.name)

    image.save()
Exemplo n.º 13
0
def optimize_image(image):

    im = PILImage.open(image.source.path)

    # Let's cache some important stuff
    format = im.format
    icc_profile = im.info.get("icc_profile")
    quantization = getattr(im, "quantization", None)
    subsampling = None
    if format == "JPEG":
        try:
            subsampling = JpegImagePlugin.get_sampling(im)
        except:
            pass  # Sometimes, crazy images exist.

    filename = os.path.split(image.source.path)[1]

    if im.size[0] > settings.BETTY_MAX_WIDTH:
        # If the image is really large, we'll save a more reasonable version as the "original"
        height = settings.BETTY_MAX_WIDTH * float(im.size[1]) / float(
            im.size[0])
        im = im.resize((settings.BETTY_MAX_WIDTH, int(round(height))),
                       PILImage.ANTIALIAS)

    image.optimized.name = optimized_upload_to(image, filename)
    if format == "JPEG" and im.mode == "RGB":
        # For JPEG files, we need to make sure that we keep the quantization profile
        try:
            im.save(image.optimized.name,
                    icc_profile=icc_profile,
                    qtables=quantization,
                    subsampling=subsampling,
                    format="JPEG")
        except (TypeError, ValueError) as e:
            # Maybe the image already had an invalid quant table?
            if e.message.startswith(
                    "Not a valid numbers of quantization tables"):
                im.save(image.optimized.name, icc_profile=icc_profile)
            else:
                raise
    else:
        im.save(image.optimized.name, icc_profile=icc_profile)
    image.save()
Exemplo n.º 14
0
    def create_image(self, buffer):
        img = Image.open(BytesIO(buffer))
        self.icc_profile = img.info.get('icc_profile')
        self.transparency = img.info.get('transparency')
        self.exif = img.info.get('exif')

        self.subsampling = JpegImagePlugin.get_sampling(img)
        if (self.subsampling == -1):  # n/a for this file
            self.subsampling = None
        self.qtables = getattr(img, 'quantization', None)

        if self.context.config.ALLOW_ANIMATED_GIFS and self.extension == '.gif':
            frames = []
            for frame in ImageSequence.Iterator(img):
                frames.append(frame.convert('P'))
            img.seek(0)
            self.frame_count = len(frames)
            return frames

        return img
Exemplo n.º 15
0
    def create_image(self, buffer):
        img = Image.open(BytesIO(buffer))
        self.icc_profile = img.info.get('icc_profile')
        self.transparency = img.info.get('transparency')
        self.exif = img.info.get('exif')

        self.subsampling = JpegImagePlugin.get_sampling(img)
        if (self.subsampling == -1):  # n/a for this file
            self.subsampling = None
        self.qtables = getattr(img, 'quantization', None)

        if self.context.config.ALLOW_ANIMATED_GIFS and self.extension == '.gif':
            frames = []
            for frame in ImageSequence.Iterator(img):
                frames.append(frame.convert('P'))
            img.seek(0)
            self.frame_count = len(frames)
            return frames

        return img
Exemplo n.º 16
0
def resize_and_crop(org, dst, size, center=(0.5, 0.5)):
    from PIL import Image, JpegImagePlugin as JIP
    img = adjust_rotation(Image.open(org))
    org_r = img.size[1] / img.size[0]
    dst_r = size[1] / size[0]

    s1 = (size[0],
          int(size[0] * org_r)) if org_r > dst_r else (int(size[1] / org_r),
                                                       size[1])
    d = [int((s1[i] - size[i]) / 2) for i in (0, 1)]
    c = [int((0.5 - center[i]) * s1[i]) for i in (0, 1)]
    i2 = img.resize(s1).crop(
        (d[0] - c[0], d[1] - c[1], s1[0] - d[0] - c[0], s1[1] - d[1] - c[1]))
    restore_rotation(i2.resize(size)).save(validate_path(dst),
                                           'JPEG',
                                           optimize=True,
                                           exif=img.info['exif'],
                                           icc_profile=img.info.get(
                                               'icc_profile', ''),
                                           subsampling=JIP.get_sampling(img))
    return i2
Exemplo n.º 17
0
    def put_data_to_image(self, data):
        img = Image.new(self.image.mode, self.image.size)
        pixels = self.image.load()
        pixels_new = img.load()
        size_x, size_y = img.size
        data_pieces = (data[x:x+2] for x in range(0, len(data), 2))
        for x in range(size_x):
            for y in range(size_y):
                r, g, b = pixels[x, y]
                r = bin(r)[2:]
                g = bin(g)[2:]
                b = bin(b)[2:]
                data_r = next(data_pieces, '')
                data_g = next(data_pieces, '')
                data_b = next(data_pieces, '')
                new_r = r[:-len(data_r) or len(r)] + data_r
                new_g = g[:-len(data_g) or len(g)] + data_g
                new_b = b[:-len(data_b) or len(b)] + data_b
                pixels_new[x, y] = (int(new_r, 2), int(new_g, 2), int(new_b, 2))

        new_file_name = '.'.join(self.photo_path.split('.')[:-1]) + '_new.' + 'png'
        img.save(new_file_name, subsampling=JIP.get_sampling(img))
Exemplo n.º 18
0
    def create_image(self, buffer):
        try:
            img = Image.open(BytesIO(buffer))
        except Image.DecompressionBombWarning as e:
            logger.warning("[PILEngine] create_image failed: {0}".format(e))
            return None
        self.icc_profile = img.info.get('icc_profile')
        self.exif = img.info.get('exif')

        self.subsampling = JpegImagePlugin.get_sampling(img)
        if (self.subsampling == -1):  # n/a for this file
            self.subsampling = None
        self.qtables = getattr(img, 'quantization', None)

        if self.context.config.ALLOW_ANIMATED_GIFS and self.extension == '.gif':
            frames = []
            for frame in ImageSequence.Iterator(img):
                frames.append(frame.convert('P'))
            img.seek(0)
            self.frame_count = len(frames)
            return frames

        return img
Exemplo n.º 19
0
    def _make_page(self, args, filename):
        self.img = Image.open(filename)
        #self.img = change_resolution(self.img, [8.5, 11], 320, False)
        self.quantization = getattr(self.img, 'quantization', None)
        self.subsampling = JpegImagePlugin.get_sampling(
            self.img) if self.quantization else None

        if args.bg:
            bg = args.bg
            if bg.lower() == 'none':
                bg = None
        else:
            bg = detect_background_color(self.img)

        if args.scale != 1.0:
            print('Scaling image: {}'.format(args.scale))
            self.img = self.img.resize(
                [int(i * args.scale) for i in self.img.size])

        self.landscape = self.img.size[0] > self.img.size[1]
        if self.landscape:
            self.img = self.img.rotate(90, expand=True)

        im = image_to_array(self.img)

        threshold = args.threshold
        if not threshold:
            if Page.threshold is None:
                #Page.threshold, _ = auto_threshold(im)
                Page.threshold = np.mean(im)
                print('auto threshold:', Page.threshold)
            threshold = Page.threshold
        #panels = panelize_crop(im, threshold)
        #im = cv2.convertScaleAbs(im, alpha=2.5)
        panels, Page.kern_size, Page.iters = panelize_contours(
            im, threshold, Page.kern_size, Page.iters)
        return self._set_panels(args, self.img, panels, bg)
Exemplo n.º 20
0
def test_pil_palette():
    # img = cv2.imread('./img2.jpg')
    img = Image.open('./featuremaps.png')
    arr = np.array([
        7, 24, 86, 236, 255, 255, 255, 255, 57, 60, 112, 88, 255, 255, 255,
        255, 146, 176, 199, 173, 255, 255, 255, 255, 247, 171, 199, 185, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255
    ])
    arr2 = np.array([
        16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, 14, 13,
        16, 24, 40, 57, 69, 56, 14, 17, 22, 29, 51, 87, 80, 62, 18, 22, 37, 56,
        68, 109, 103, 77, 24, 35, 55, 64, 81, 104, 113, 92, 49, 64, 78, 87,
        103, 121, 120, 101, 72, 92, 95, 98, 112, 100, 103, 99
    ])
    arr3 = np.array([
        1, 1, 255, 255, 255, 255, 255, 255, 1, 1, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255
    ])
    arr = (arr).astype(np.int)
    qt = {0: arr3}
    from PIL import JpegImagePlugin
    qt = JpegImagePlugin.convert_dict_qtables(qt)
    file = io.BytesIO()
    img_qt = img.save(file, 'JPEG', qtables=qt)
    file.seek(0)
    img_data = file.read()
    img__ = cv2.imdecode(np.frombuffer(img_data, dtype=np.uint8), 1)
    cv2.imshow('tmp', img__)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    qt_n = img__.quantization
    print(0)
Exemplo n.º 21
0
    def create_image(self, buffer):
        try:
            img = Image.open(BytesIO(buffer))
        except DecompressionBombExceptions as e:
            logger.warning("[PILEngine] create_image failed: {0}".format(e))
            return None
        self.icc_profile = img.info.get('icc_profile')
        self.exif = img.info.get('exif')
        self.original_mode = img.mode

        self.subsampling = JpegImagePlugin.get_sampling(img)
        if (self.subsampling == -1):  # n/a for this file
            self.subsampling = None
        self.qtables = getattr(img, 'quantization', None)

        if self.context.config.ALLOW_ANIMATED_GIFS and self.extension == '.gif':
            frames = []
            for frame in ImageSequence.Iterator(img):
                frames.append(frame.convert('P'))
            img.seek(0)
            self.frame_count = len(frames)
            return frames

        return img
Exemplo n.º 22
0
def _save(im, fp, filename):
    # Note that we can only save the current frame at present
    return JpegImagePlugin._save(im, fp, filename)
Exemplo n.º 23
0
def jpeg_image():
    return JpegImagePlugin.JpegImageFile(create_test_image('jpeg'))
Exemplo n.º 24
0
def getiptcinfo(im):

    import StringIO

    data = None

    if isinstance(im, IptcImageFile):
        # return info dictionary right away
        return im.info

    elif isinstance(im, JpegImagePlugin.JpegImageFile):
        # extract the IPTC/NAA resource
        try:
            app = im.app["APP13"]
            if app[:14] == "Photoshop 3.0\x00":
                app = app[14:]
                # parse the image resource block
                offset = 0
                while app[offset:offset+4] == "8BIM":
                    offset = offset + 4
                    # resource code
                    code = JpegImagePlugin.i16(app, offset)
                    offset = offset + 2
                    # resource name (usually empty)
                    name_len = ord(app[offset])
                    name = app[offset+1:offset+1+name_len]
                    offset = 1 + offset + name_len
                    if offset & 1:
                        offset = offset + 1
                    # resource data block
                    size = JpegImagePlugin.i32(app, offset)
                    offset = offset + 4
                    if code == 0x0404:
                        # 0x0404 contains IPTC/NAA data
                        data = app[offset:offset+size]
                        break
                    offset = offset + size
                    if offset & 1:
                        offset = offset + 1
        except (AttributeError, KeyError):
            pass

    elif isinstance(im, TiffImagePlugin.TiffImageFile):
        # get raw data from the IPTC/NAA tag (PhotoShop tags the data
        # as 4-byte integers, so we cannot use the get method...)
        try:
            type, data = im.tag.tagdata[TiffImagePlugin.IPTC_NAA_CHUNK]
        except (AttributeError, KeyError):
            pass

    if data is None:
        return None # no properties

    # create an IptcImagePlugin object without initializing it
    class FakeImage:
        pass
    im = FakeImage()
    im.__class__ = IptcImageFile

    # parse the IPTC information chunk
    im.info = {}
    im.fp = StringIO.StringIO(data)

    try:
        im._open()
    except (IndexError, KeyError):
        pass # expected failure

    return im.info
Exemplo n.º 25
0
def _save(im, fp, filename):
    return JpegImagePlugin._save(im, fp, filename)
Exemplo n.º 26
0
def _save(im, fp, filename):
    # Note that we can only save the current frame at present
    return JpegImagePlugin._save(im, fp, filename)
Exemplo n.º 27
0
def _accept(prefix):
    return JpegImagePlugin._accept(prefix)
Exemplo n.º 28
0
def _accept(prefix):
    return JpegImagePlugin._accept(prefix)
Exemplo n.º 29
0
 def test_save_cjpeg(self, tmp_path):
     with Image.open(TEST_FILE) as img:
         tempfile = str(tmp_path / "temp.jpg")
         JpegImagePlugin._save_cjpeg(img, 0, tempfile)
         # Default save quality is 75%, so a tiny bit of difference is alright
         assert_image_similar(img, Image.open(tempfile), 17)
Exemplo n.º 30
0
def getiptcinfo(im):

    from PIL import TiffImagePlugin, JpegImagePlugin
    import io

    data = None

    if isinstance(im, IptcImageFile):
        # return info dictionary right away
        return im.info

    elif isinstance(im, JpegImagePlugin.JpegImageFile):
        # extract the IPTC/NAA resource
        try:
            app = im.app["APP13"]
            if app[:14] == b"Photoshop 3.0\x00":
                app = app[14:]
                # parse the image resource block
                offset = 0
                while app[offset:offset + 4] == b"8BIM":
                    offset += 4
                    # resource code
                    code = JpegImagePlugin.i16(app, offset)
                    offset += 2
                    # resource name (usually empty)
                    name_len = i8(app[offset])
                    # name = app[offset+1:offset+1+name_len]
                    offset = 1 + offset + name_len
                    if offset & 1:
                        offset += 1
                    # resource data block
                    size = JpegImagePlugin.i32(app, offset)
                    offset += 4
                    if code == 0x0404:
                        # 0x0404 contains IPTC/NAA data
                        data = app[offset:offset + size]
                        break
                    offset = offset + size
                    if offset & 1:
                        offset += 1
        except (AttributeError, KeyError):
            pass

    elif isinstance(im, TiffImagePlugin.TiffImageFile):
        # get raw data from the IPTC/NAA tag (PhotoShop tags the data
        # as 4-byte integers, so we cannot use the get method...)
        try:
            data = im.tag.tagdata[TiffImagePlugin.IPTC_NAA_CHUNK]
        except (AttributeError, KeyError):
            pass

    if data is None:
        return None  # no properties

    # create an IptcImagePlugin object without initializing it
    class FakeImage(object):
        pass

    im = FakeImage()
    im.__class__ = IptcImageFile

    # parse the IPTC information chunk
    im.info = {}
    im.fp = io.BytesIO(data)

    try:
        im._open()
    except (IndexError, KeyError):
        pass  # expected failure

    return im.info
Exemplo n.º 31
0
def one_image(path):
    if os.path.splitext(path.lower())[1] not in (".jpg", ".jpeg"):
        return 0

    # a raw image may or may not exist, but we generally would want to keep any raw sync-ed up with its jpeg
    path_raw = os.path.splitext(path)[0] + ".cr2"

    if args.edit_in_place or args.dry_run:
        outpath = path
        outpath_raw = path_raw
    elif args.output_path:
        _, filepart = os.path.split(path)
        outpath = os.path.join(args.output_path, filepart)
        _, filepart = os.path.split(path_raw)
        outpath_raw = os.path.join(args.output_path, filepart)

    with Image.open(path) as imgobj:
        if 'exif' in imgobj.info:
            exif_dict = piexif.load(imgobj.info['exif'])
        else:
            print("Keys in image info: %s" % sorted(imgobj.info.keys()))
            raise Exception(
                "The file '%s' does not appear to contain exif data." % path)

        if args.filter_min_size and (
                imgobj.size[0] <= args.filter_min_size[0]
                or imgobj.size[1] <= args.filter_min_size[1]):
            return 0
        if args.filter_min_pixels and (
                imgobj.size[0] * imgobj.size[1] <=
                args.filter_min_pixels[0] * args.filter_min_pixels[1]):
            return 0

        if args.print_some_tags:
            print("Dims 1: %s x %s" %
                  (exif_dict["0th"].get(piexif.ImageIFD.ImageWidth),
                   exif_dict["0th"].get(piexif.ImageIFD.ImageLength)))
            print("Dims 2: %s x %s" %
                  (exif_dict["Exif"].get(piexif.ExifIFD.PixelXDimension),
                   exif_dict["Exif"].get(piexif.ExifIFD.PixelYDimension)))
            print("Date 1: %s" %
                  parsedate2(exif_dict["0th"][piexif.ImageIFD.DateTime]))
            print(
                "Date 2: %s" %
                parsedate2(exif_dict["Exif"][piexif.ExifIFD.DateTimeOriginal]))
            print("Date 3: %s" % parsedate2(
                exif_dict["Exif"][piexif.ExifIFD.DateTimeDigitized]))

        if args.print_all_tags:
            for ifd in ("0th", "Exif", "GPS", "1st"):
                for tag in exif_dict[ifd]:
                    val = exif_dict[ifd][tag]
                    try:
                        if len(val) > 100:
                            val = "%s len %s" % (str(type(val)), len(val))
                    except TypeError:
                        pass
                    print("(%s) (%s) %s = %s" %
                          (ifd, tag, piexif.TAGS[ifd][tag]["name"], val))

        if args.adjust_date:
            changeto = parsedate(exif_dict["Exif"][
                piexif.ExifIFD.DateTimeDigitized]) + datetime.timedelta(
                    minutes=args.adjust_date)
            exif_dict["0th"][piexif.ImageIFD.DateTime] = changeto.strftime(
                "%Y:%m:%d %H:%M:%S")
            exif_dict["Exif"][
                piexif.ExifIFD.DateTimeOriginal] = changeto.strftime(
                    "%Y:%m:%d %H:%M:%S")
            exif_bytes = piexif.dump(exif_dict)
            shutil.copy2(path, args.temporary_file)
            compare_files(path, args.temporary_file, True)
            compare_images(path, args.temporary_file, True)
            piexif.insert(exif_bytes, args.temporary_file)
            compare_files(path, args.temporary_file, False)
            compare_images(path, args.temporary_file, True)

        if args.scale_percent:
            newdims = (int(imgobj.size[0] * args.scale_percent),
                       int(imgobj.size[1] * args.scale_percent))
            exif_dict["0th"][piexif.ImageIFD.ImageWidth] = newdims[0]
            exif_dict["0th"][piexif.ImageIFD.ImageLength] = newdims[
                1]  # fix dims or they are wrong in exif
            exif_bytes = piexif.dump(exif_dict)
            quantization = getattr(imgobj, 'quantization', None)
            subsampling = JpegImagePlugin.get_sampling(imgobj)
            quality = 100 if quantization is None else 0
            imgobj2 = imgobj.resize(newdims, resample=Image.LANCZOS)
            # include exif or else it is lost
            # also attempt to compress with the settings that were used previously
            imgobj2.save(args.temporary_file,
                         exif=exif_bytes,
                         format='jpeg',
                         subsampling=subsampling,
                         qtables=quantization,
                         quality=quality)
            compare_files(path, args.temporary_file, False)
            compare_images(path, args.temporary_file, False)

        # the image object is closed here, now we can replace or delete the original jpeg

    if args.adjust_date or args.scale_percent:
        # we have theoretically made a temporary file with the contents we want, now we can get it where it needs to go
        if args.dry_run:
            print("Edit '%s'." % path)
        else:
            shutil.move(args.temporary_file, outpath)
        if os.path.exists(path_raw) and path_raw != outpath_raw:
            # the optional raw file is handled differently, as there is no modification and no temporary raw file
            if args.edit_in_place:
                shutil.move(path_raw, outpath_raw)
            elif args.output_path:
                shutil.copy2(path_raw, outpath_raw)
            else:
                print("Edit '%s'." % path_raw)

    if args.rename_images:
        changeto = parsedate(exif_dict["Exif"][
            piexif.ExifIFD.DateTimeOriginal]).strftime("img_%Y%m%d_%H%M%S")
        outpath, filepart = os.path.split(outpath)
        extra = 0
        finaloutpath = os.path.join(outpath, changeto +
                                    ".jpg")  # deal with name conflicts
        finaloutpath_raw = os.path.join(
            outpath, changeto + ".cr2")  # raw follows along if it exists
        while os.path.exists(finaloutpath) and path != finaloutpath:
            extra += 1
            finaloutpath = os.path.join(outpath,
                                        "%s.%d.jpg" % (changeto, extra))
            finaloutpath_raw = os.path.join(outpath,
                                            "%s.%d.cr2" % (changeto, extra))
            if extra > 100:  # because I don't trust unbounded loops
                raise Exception("Apparent runaway extra for %s." % path)

        if path == finaloutpath:
            return 0

        if args.edit_in_place:
            func = shutil.move
        elif args.output_path:
            func = shutil.copy2
        else:
            func = lambda x, y: print("Move '%s' to '%s'." % (x, y))

        func(path, finaloutpath)
        if os.path.exists(path_raw):
            func(path_raw, finaloutpath_raw)

    return 1
Exemplo n.º 32
0
 def test_convert_dict_qtables_deprecation(self):
     with pytest.warns(DeprecationWarning):
         qtable = {0: [1, 2, 3, 4]}
         qtable2 = JpegImagePlugin.convert_dict_qtables(qtable)
         assert qtable == qtable2
Exemplo n.º 33
0
from PIL import JpegImagePlugin
from PIL import Image, ImageFile, _binary
import struct, binascii
fd = open("124.jpg")
fd2 = open("125.jpg", "wr")
fdp = fd.read()
fd.close()
msg1 = "hello xxsfsdf"

msg = struct.pack(">BBH%ds" % len(msg1), 255, 254, len(msg1) + 2, msg1)
print binascii.hexlify(msg)
fd2.write(fdp[:2])
fd2.write(msg)
fd2.write(fdp[2:])
fd2.close()
img = Image.open("125.jpg")
info1 = JpegImagePlugin(img)
print info1