PyTurboJPEG 1.7.7__tar.gz → 1.8.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2018-2024 Lilo Huang <kuso.cc@gmail.com>
3
+ Copyright (c) 2018-2025 Lilo Huang <kuso.cc@gmail.com>
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyTurboJPEG
3
- Version: 1.7.7
3
+ Version: 1.8.2
4
4
  Summary: A Python wrapper of libjpeg-turbo for decoding and encoding JPEG image.
5
5
  Home-page: https://github.com/lilohuang/PyTurboJPEG
6
6
  Author: Lilo Huang
@@ -108,6 +108,33 @@ in_file.close()
108
108
  out_file = open('lossless_cropped_output.jpg', 'wb')
109
109
  out_file.write(jpeg.crop(open('input.jpg', 'rb').read(), 8, 8, 320, 240))
110
110
  out_file.close()
111
+
112
+ # in-place decoding input.jpg to BGR array
113
+ # here I use a 640x480 example (in practise, read the dimensions)
114
+ in_file = open('input.jpg', 'rb')
115
+ img_array = np.empty((640, 480, 3), dtype=np.uint8)
116
+ result = jpeg.decode(in_file.read(), dst=img_array)
117
+ in_file.close()
118
+
119
+ # return value is the img_array argument value
120
+ id(result) == id(img_array)
121
+ # True
122
+
123
+ # Optional: display the in-place array
124
+ # cv2.imshow('img_array', img_array)
125
+ # cv2.waitKey(0)
126
+
127
+ # in-place encoding with default settings.
128
+ buffer_size = jpeg.buffer_size(img_array)
129
+ dest_buf = bytearray(buffer_size)
130
+ result, n_byte = jpeg.encode(img_array, dst=dest_buf)
131
+
132
+ # return value is the dest_buf argument value
133
+ id(result) == id(dest_buf)
134
+
135
+ out_file = open('output.jpg', 'wb')
136
+ out_file.write(dest_buf[:n_byte])
137
+ out_file.close()
111
138
  ```
112
139
 
113
140
  ```python
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyTurboJPEG
3
- Version: 1.7.7
3
+ Version: 1.8.2
4
4
  Summary: A Python wrapper of libjpeg-turbo for decoding and encoding JPEG image.
5
5
  Home-page: https://github.com/lilohuang/PyTurboJPEG
6
6
  Author: Lilo Huang
@@ -108,6 +108,33 @@ in_file.close()
108
108
  out_file = open('lossless_cropped_output.jpg', 'wb')
109
109
  out_file.write(jpeg.crop(open('input.jpg', 'rb').read(), 8, 8, 320, 240))
110
110
  out_file.close()
111
+
112
+ # in-place decoding input.jpg to BGR array
113
+ # here I use a 640x480 example (in practise, read the dimensions)
114
+ in_file = open('input.jpg', 'rb')
115
+ img_array = np.empty((640, 480, 3), dtype=np.uint8)
116
+ result = jpeg.decode(in_file.read(), dst=img_array)
117
+ in_file.close()
118
+
119
+ # return value is the img_array argument value
120
+ id(result) == id(img_array)
121
+ # True
122
+
123
+ # Optional: display the in-place array
124
+ # cv2.imshow('img_array', img_array)
125
+ # cv2.waitKey(0)
126
+
127
+ # in-place encoding with default settings.
128
+ buffer_size = jpeg.buffer_size(img_array)
129
+ dest_buf = bytearray(buffer_size)
130
+ result, n_byte = jpeg.encode(img_array, dst=dest_buf)
131
+
132
+ # return value is the dest_buf argument value
133
+ id(result) == id(dest_buf)
134
+
135
+ out_file = open('output.jpg', 'wb')
136
+ out_file.write(dest_buf[:n_byte])
137
+ out_file.close()
111
138
  ```
112
139
 
113
140
  ```python
@@ -96,6 +96,33 @@ in_file.close()
96
96
  out_file = open('lossless_cropped_output.jpg', 'wb')
97
97
  out_file.write(jpeg.crop(open('input.jpg', 'rb').read(), 8, 8, 320, 240))
98
98
  out_file.close()
99
+
100
+ # in-place decoding input.jpg to BGR array
101
+ # here I use a 640x480 example (in practise, read the dimensions)
102
+ in_file = open('input.jpg', 'rb')
103
+ img_array = np.empty((640, 480, 3), dtype=np.uint8)
104
+ result = jpeg.decode(in_file.read(), dst=img_array)
105
+ in_file.close()
106
+
107
+ # return value is the img_array argument value
108
+ id(result) == id(img_array)
109
+ # True
110
+
111
+ # Optional: display the in-place array
112
+ # cv2.imshow('img_array', img_array)
113
+ # cv2.waitKey(0)
114
+
115
+ # in-place encoding with default settings.
116
+ buffer_size = jpeg.buffer_size(img_array)
117
+ dest_buf = bytearray(buffer_size)
118
+ result, n_byte = jpeg.encode(img_array, dst=dest_buf)
119
+
120
+ # return value is the dest_buf argument value
121
+ id(result) == id(dest_buf)
122
+
123
+ out_file = open('output.jpg', 'wb')
124
+ out_file.write(dest_buf[:n_byte])
125
+ out_file.close()
99
126
  ```
100
127
 
101
128
  ```python
@@ -2,7 +2,7 @@ import io
2
2
  from setuptools import setup, find_packages
3
3
  setup(
4
4
  name='PyTurboJPEG',
5
- version='1.7.7',
5
+ version='1.8.2',
6
6
  description='A Python wrapper of libjpeg-turbo for decoding and encoding JPEG image.',
7
7
  author='Lilo Huang',
8
8
  author_email='kuso.cc@gmail.com',
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # PyTurboJPEG - A Python wrapper of libjpeg-turbo for decoding and encoding JPEG image.
4
4
  #
5
- # Copyright (c) 2018-2024, Lilo Huang. All rights reserved.
5
+ # Copyright (c) 2018-2025, Lilo Huang. All rights reserved.
6
6
  #
7
7
  # Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  # of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
23
23
  # SOFTWARE.
24
24
 
25
25
  __author__ = 'Lilo Huang <kuso.cc@gmail.com>'
26
- __version__ = '1.7.7'
26
+ __version__ = '1.8.2'
27
27
 
28
28
  from ctypes import *
29
29
  from ctypes.util import find_library
@@ -408,7 +408,7 @@ class TurboJPEG(object):
408
408
  finally:
409
409
  self.__destroy(handle)
410
410
 
411
- def decode(self, jpeg_buf, pixel_format=TJPF_BGR, scaling_factor=None, flags=0):
411
+ def decode(self, jpeg_buf, pixel_format=TJPF_BGR, scaling_factor=None, flags=0, dst=None):
412
412
  """decodes JPEG memory buffer to numpy array."""
413
413
  handle = self.__init_decompress()
414
414
  try:
@@ -416,9 +416,14 @@ class TurboJPEG(object):
416
416
  src_addr = self.__getaddr(jpeg_array)
417
417
  scaled_width, scaled_height, _, _ = \
418
418
  self.__get_header_and_dimensions(handle, jpeg_array.size, src_addr, scaling_factor)
419
- img_array = np.empty(
420
- [scaled_height, scaled_width, tjPixelSize[pixel_format]],
421
- dtype=np.uint8)
419
+ if ((type(dst) == np.ndarray) and
420
+ (dst.shape == (scaled_height, scaled_width, tjPixelSize[pixel_format])) and
421
+ (dst.dtype == np.uint8)):
422
+ img_array = dst
423
+ else:
424
+ img_array = np.empty(
425
+ [scaled_height, scaled_width, tjPixelSize[pixel_format]],
426
+ dtype=np.uint8)
422
427
  dest_addr = self.__getaddr(img_array)
423
428
  status = self.__decompress(
424
429
  handle, src_addr, jpeg_array.size, dest_addr, scaled_width,
@@ -486,13 +491,22 @@ class TurboJPEG(object):
486
491
  finally:
487
492
  self.__destroy(handle)
488
493
 
489
- def encode(self, img_array, quality=85, pixel_format=TJPF_BGR, jpeg_subsample=TJSAMP_422, flags=0):
494
+ def encode(self, img_array, quality=85, pixel_format=TJPF_BGR, jpeg_subsample=TJSAMP_422, flags=0, dst=None):
490
495
  """encodes numpy array to JPEG memory buffer."""
491
496
  handle = self.__init_compress()
492
497
  try:
493
- jpeg_buf = c_void_p()
494
- jpeg_size = c_ulong()
495
498
  img_array = np.ascontiguousarray(img_array)
499
+ if dst is not None and not self.__is_buffer(dst):
500
+ raise TypeError('\'dst\' argument must support buffer protocol')
501
+ if (dst is not None and
502
+ (len(dst) >= self.buffer_size(img_array, jpeg_subsample))):
503
+ dst_array = np.frombuffer(dst, dtype=np.uint8)
504
+ jpeg_buf = dst_array.ctypes.data_as(c_void_p)
505
+ jpeg_size = c_ulong(len(dst))
506
+ else:
507
+ dst_array = None
508
+ jpeg_buf = c_void_p()
509
+ jpeg_size = c_ulong()
496
510
  height, width = img_array.shape[:2]
497
511
  channel = tjPixelSize[pixel_format]
498
512
  if channel > 1 and (len(img_array.shape) < 3 or img_array.shape[2] != channel):
@@ -503,10 +517,12 @@ class TurboJPEG(object):
503
517
  byref(jpeg_buf), byref(jpeg_size), jpeg_subsample, quality, flags)
504
518
  if status != 0:
505
519
  self.__report_error(handle)
506
- dest_buf = create_string_buffer(jpeg_size.value)
507
- memmove(dest_buf, jpeg_buf.value, jpeg_size.value)
508
- self.__free(jpeg_buf)
509
- return dest_buf.raw
520
+ if dst_array is None or jpeg_buf.value != dst_array.ctypes.data:
521
+ result = self.__copy_from_buffer(jpeg_buf.value, jpeg_size.value)
522
+ self.__free(jpeg_buf)
523
+ else:
524
+ result = dst
525
+ return result if dst is None else (result, jpeg_size.value)
510
526
  finally:
511
527
  self.__destroy(handle)
512
528
 
@@ -539,7 +555,7 @@ class TurboJPEG(object):
539
555
  scaled_width, scaled_height, jpeg_subsample, _ = self.__get_header_and_dimensions(
540
556
  handle, jpeg_array.size, src_addr, scaling_factor)
541
557
  buffer_YUV_size = self.__buffer_size_YUV2(
542
- scaled_height, 4, scaled_width, jpeg_subsample)
558
+ scaled_width, 4, scaled_height, jpeg_subsample)
543
559
  img_array = np.empty([buffer_YUV_size])
544
560
  dest_addr = self.__getaddr(img_array)
545
561
  status = self.__decompressToYUV2(
@@ -680,6 +696,12 @@ class TurboJPEG(object):
680
696
  finally:
681
697
  self.__destroy(handle)
682
698
 
699
+ def buffer_size(self, img_array, jpeg_subsample=TJSAMP_422):
700
+ """Get maximum number of bytes of compressed jpeg data"""
701
+ img_array = np.ascontiguousarray(img_array)
702
+ height, width = img_array.shape[:2]
703
+ return self.__buffer_size(width, height, jpeg_subsample)
704
+
683
705
  def __do_transform(self, handle, src_buf, src_size, number_of_transforms, transforms):
684
706
  """Do transform.
685
707
 
@@ -774,16 +796,22 @@ class TurboJPEG(object):
774
796
  return scaled_width, scaled_height, jpeg_subsample, jpeg_colorspace
775
797
 
776
798
  def __axis_to_image_boundaries(self, a, b, img_boundary, preserve, mcuBlock):
777
- img_b = img_boundary - (img_boundary % mcuBlock)
778
- delta_a = a % mcuBlock
779
- if a > img_b:
780
- a = img_b
799
+ if preserve:
800
+ original_a = a
801
+ a = int(math.ceil(float(original_a) / mcuBlock) * mcuBlock)
802
+ b -= (a - original_a)
803
+ if (a + b) > img_boundary:
804
+ b = img_boundary - a
781
805
  else:
782
- a = a - delta_a
783
- if not preserve:
806
+ img_b = img_boundary - (img_boundary % mcuBlock)
807
+ delta_a = a % mcuBlock
808
+ if a > img_b:
809
+ a = img_b
810
+ else:
811
+ a = a - delta_a
784
812
  b = b + delta_a
785
- if (a + b) > img_b:
786
- b = img_b - a
813
+ if (a + b) > img_b:
814
+ b = img_b - a
787
815
  return a, b
788
816
 
789
817
  @staticmethod
@@ -974,6 +1002,14 @@ class TurboJPEG(object):
974
1002
  """returns the memory address for a given ndarray"""
975
1003
  return cast(nda.__array_interface__['data'][0], POINTER(c_ubyte))
976
1004
 
1005
+ def __is_buffer(self, x):
1006
+ result = True
1007
+ try:
1008
+ memoryview(x)
1009
+ except Exception:
1010
+ result = False
1011
+ return result
1012
+
977
1013
  @property
978
1014
  def scaling_factors(self):
979
1015
  return self.__scaling_factors
File without changes