Skip to content

Commit

Permalink
Fixing a problem with copynone using libjpeg-turbo 3.0.0 (#76)
Browse files Browse the repository at this point in the history
Fixing a problem with copynone using libjpeg-turbo 3.0.0 (#74). Thanks to @erikogabrielsson for his contribution.
---------

Co-authored-by: Erik O Gabrielsson <83275777+erikogabrielsson@users.noreply.github.com>
  • Loading branch information
lilohuang and erikogabrielsson authored Dec 6, 2023
1 parent c491d2a commit c9a4973
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 37 deletions.
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from setuptools import setup, find_packages
setup(
name='PyTurboJPEG',
version='1.7.2',
version='1.7.3',
description='A Python wrapper of libjpeg-turbo for decoding and encoding JPEG image.',
author='Lilo Huang',
author_email='kuso.cc@gmail.com',
Expand Down
107 changes: 71 additions & 36 deletions turbojpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
# SOFTWARE.

__author__ = 'Lilo Huang <kuso.cc@gmail.com>'
__version__ = '1.7.2'
__version__ = '1.7.3'

from ctypes import *
from ctypes.util import find_library
Expand Down Expand Up @@ -353,6 +353,12 @@ def __init__(self, lib_path=None):
c_void_p, POINTER(c_ubyte), c_ulong, c_int, POINTER(c_void_p),
POINTER(c_ulong), POINTER(TransformStruct), c_int]
self.__transform.restype = c_int
self.__transform3 = getattr(turbo_jpeg, 'tj3Transform', None)
if self.__transform3 is not None:
self.__transform3.argtypes = [
c_void_p, POINTER(c_ubyte), c_size_t, c_int, POINTER(c_void_p),
POINTER(c_size_t), POINTER(TransformStruct)]
self.__transform3.restype = c_int
self.__free = turbo_jpeg.tjFree
self.__free.argtypes = [c_void_p]
self.__free.restype = None
Expand Down Expand Up @@ -552,7 +558,7 @@ def scale_with_quality(self, jpeg_buf, scaling_factor=None, quality=85, flags=0)
finally:
self.__destroy(handle)

def crop(self, jpeg_buf, x, y, w, h, preserve=False, gray=False):
def crop(self, jpeg_buf, x, y, w, h, preserve=False, gray=False, copynone=False):
"""losslessly crop a jpeg image with optional grayscale"""
handle = self.__init_transform()
try:
Expand All @@ -571,20 +577,11 @@ def crop(self, jpeg_buf, x, y, w, h, preserve=False, gray=False):
x, w, width.value, preserve, tjMCUWidth[jpeg_subsample.value])
y, h = self.__axis_to_image_boundaries(
y, h, height.value, preserve, tjMCUHeight[jpeg_subsample.value])
dest_array = c_void_p()
dest_size = c_ulong()
region = CroppingRegion(x, y, w, h)
crop_transform = TransformStruct(region, TJXOP_NONE,
TJXOPT_CROP | (gray and TJXOPT_GRAY))
status = self.__transform(
handle, src_addr, jpeg_array.size, 1, byref(dest_array), byref(dest_size),
byref(crop_transform), 0)
dest_buf = create_string_buffer(dest_size.value)
memmove(dest_buf, dest_array.value, dest_size.value)
self.__free(dest_array)
if status != 0:
self.__report_error(handle)
return dest_buf.raw
TJXOPT_CROP | (gray and TJXOPT_GRAY) | (copynone and TJXOPT_COPYNONE))
return self.__do_transform(handle, src_addr, jpeg_array.size, 1, byref(crop_transform))[0]

finally:
self.__destroy(handle)

Expand Down Expand Up @@ -672,41 +669,79 @@ def crop_multiple(self, jpeg_buf, crop_parameters, background_luminance=1.0, gra
TJXOP_NONE,
TJXOPT_PERFECT | TJXOPT_CROP | (gray and TJXOPT_GRAY) | (copynone and TJXOPT_COPYNONE)
)
results = self.__do_transform(handle, src_addr, jpeg_array.size, number_of_operations, crop_transforms)

return results

finally:
self.__destroy(handle)

def __do_transform(self, handle, src_buf, src_size, number_of_transforms, transforms):
"""Do transform.
# Pointers to output image buffers and buffer size
dest_array = (c_void_p * number_of_operations)()
dest_size = (c_ulong * number_of_operations)()
Parameters
----------
handle: int
Initiated transform handle.
src_buf: LP_c_ubyte
Pointer to source buffer for transform
src_size: int
Size of source buffer.
number_of_transforms: int
Number of transforms to perform.
transforms: CArgObject
C-array of transforms to perform.
# Do the transforms
transform_status = self.__transform(
Returns
----------
List[bytes]
Cropped and/or extended jpeg images.
"""
# Pointers to output image buffers
dest_array = (c_void_p * number_of_transforms)()
try:
if self.__transform3 is not None:
dest_size = (c_size_t * number_of_transforms)()
transform_status = self.__transform3(
handle,
src_addr,
jpeg_array.size,
number_of_operations,
src_buf,
src_size,
number_of_transforms,
dest_array,
dest_size,
transforms,
)
else:
dest_size = (c_ulong * number_of_transforms)()
transform_status = self.__transform(
handle,
src_buf,
src_size,
number_of_transforms,
dest_array,
dest_size,
crop_transforms,
TJFLAG_ACCURATEDCT
transforms,
0
)

if transform_status != 0:
self.__report_error(handle)

# Copy the transform results into python bytes
results = []
for i in range(number_of_operations):
dest_buf = create_string_buffer(dest_size[i])
memmove(dest_buf, dest_array[i], dest_size[i])
results.append(dest_buf.raw)

# Copy the transform results into python bytes
return [
self.__copy_from_buffer(dest_array[i], dest_size[i])
for i in range(number_of_transforms)
]
finally:
# Free the output image buffers
for dest in dest_array:
self.__free(dest)

return results

finally:
self.__destroy(handle)
@staticmethod
def __copy_from_buffer(buffer, size):
"""Copy bytes from buffer to python bytes."""
dest_buf = create_string_buffer(size)
memmove(dest_buf, buffer, size)
return dest_buf.raw

def __get_header_and_dimensions(self, handle, jpeg_array_size, src_addr, scaling_factor):
"""returns scaled image dimensions and header data"""
Expand Down

0 comments on commit c9a4973

Please sign in to comment.