Glymur 0.13.6__py3-none-any.whl → 0.13.8__py3-none-any.whl

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.
glymur/jp2k.py CHANGED
@@ -6,6 +6,7 @@ Copyright 2013 John Evans
6
6
 
7
7
  License: MIT
8
8
  """
9
+
9
10
  # Standard library imports...
10
11
  from __future__ import annotations
11
12
  from collections import Counter
@@ -26,9 +27,13 @@ import glymur
26
27
  from . import core, version, get_option
27
28
  from .jp2kr import Jp2kr
28
29
  from .jp2box import (
29
- JPEG2000SignatureBox, FileTypeBox, JP2HeaderBox,
30
- ColourSpecificationBox, ContiguousCodestreamBox, ImageHeaderBox,
31
- InvalidJp2kError
30
+ ColourSpecificationBox,
31
+ ContiguousCodestreamBox,
32
+ FileTypeBox,
33
+ ImageHeaderBox,
34
+ InvalidJp2kError,
35
+ JP2HeaderBox,
36
+ JPEG2000SignatureBox,
32
37
  )
33
38
  from .lib import openjp2 as opj2
34
39
 
@@ -171,15 +176,15 @@ class Jp2k(Jp2kr):
171
176
  self._shape = shape
172
177
  elif data is not None:
173
178
  self._shape = data.shape
174
- elif not hasattr(self, 'shape'):
179
+ elif not hasattr(self, "shape"):
175
180
  # We must be writing via slicing.
176
181
  # Must be determined when writing.
177
182
  self._shape = None
178
183
 
179
- if not hasattr(self, '_codec_format'):
184
+ if not hasattr(self, "_codec_format"):
180
185
  # Only set codec format if the superclass has not done so, i.e.
181
186
  # we are writing instead of reading.
182
- if self.filename[-4:].endswith(('.jp2', '.JP2', '.jpx', 'JPX')):
187
+ if self.filename[-4:].endswith((".jp2", ".JP2", ".jpx", "JPX")):
183
188
  self._codec_format = opj2.CODEC_JP2
184
189
  else:
185
190
  self._codec_format = opj2.CODEC_J2K
@@ -228,25 +233,27 @@ class Jp2k(Jp2kr):
228
233
  header box if we were so instructed. This requires a wrapping
229
234
  operation.
230
235
  """
231
- jp2h = next(filter(lambda x: x.box_id == 'jp2h', self.box), None)
236
+ jp2h = next(filter(lambda x: x.box_id == "jp2h", self.box), None)
232
237
 
233
238
  extra_boxes = []
234
239
  if self._capture_resolution is not None:
235
240
  resc = glymur.jp2box.CaptureResolutionBox(
236
- self._capture_resolution[0], self._capture_resolution[1],
241
+ self._capture_resolution[0],
242
+ self._capture_resolution[1],
237
243
  )
238
244
  extra_boxes.append(resc)
239
245
 
240
246
  if self._display_resolution is not None:
241
247
  resd = glymur.jp2box.DisplayResolutionBox(
242
- self._display_resolution[0], self._display_resolution[1],
248
+ self._display_resolution[0],
249
+ self._display_resolution[1],
243
250
  )
244
251
  extra_boxes.append(resd)
245
252
 
246
253
  rbox = glymur.jp2box.ResolutionBox(extra_boxes)
247
254
  jp2h.box.append(rbox)
248
255
 
249
- temp_filename = self.filename + '.tmp'
256
+ temp_filename = self.filename + ".tmp"
250
257
  self.wrap(temp_filename, boxes=self.box)
251
258
  shutil.move(temp_filename, self.filename)
252
259
  self.parse(force=True)
@@ -254,18 +261,23 @@ class Jp2k(Jp2kr):
254
261
  def _validate_kwargs(self):
255
262
  """Validate keyword parameters passed to the constructor."""
256
263
  non_cinema_args = (
257
- self._mct, self._cratios, self._psnr, self._irreversible,
258
- self._cbsize, self._eph, self._grid_offset, self._modesw,
259
- self._prog, self._psizes, self._sop, self._subsam
264
+ self._mct,
265
+ self._cratios,
266
+ self._psnr,
267
+ self._irreversible,
268
+ self._cbsize,
269
+ self._eph,
270
+ self._grid_offset,
271
+ self._modesw,
272
+ self._prog,
273
+ self._psizes,
274
+ self._sop,
275
+ self._subsam,
260
276
  )
261
- if (
262
- (self._cinema2k or self._cinema4k)
263
- and not all([arg is None or not arg for arg in non_cinema_args])
277
+ if (self._cinema2k or self._cinema4k) and not all(
278
+ [arg is None or not arg for arg in non_cinema_args]
264
279
  ):
265
- msg = (
266
- "Cannot specify cinema2k/cinema4k along with any other "
267
- "options."
268
- )
280
+ msg = "Do not specify cinema2k/cinema4k along with other options."
269
281
  raise InvalidJp2kError(msg)
270
282
 
271
283
  if self._psnr is not None:
@@ -295,7 +307,7 @@ class Jp2k(Jp2kr):
295
307
  self._codec_format == opj2.CODEC_J2K
296
308
  and self._colorspace is not None
297
309
  ):
298
- msg = 'Do not specify a colorspace when writing a raw codestream.'
310
+ msg = "Do not specify a colorspace when writing a raw codestream."
299
311
  raise InvalidJp2kError(msg)
300
312
 
301
313
  if (
@@ -304,8 +316,8 @@ class Jp2k(Jp2kr):
304
316
  and self._display_resolution is not None
305
317
  ):
306
318
  msg = (
307
- 'Do not specify capture/display resolution when writing a raw '
308
- 'codestream.'
319
+ "Do not specify capture/display resolution when writing a raw "
320
+ "codestream."
309
321
  )
310
322
  raise InvalidJp2kError(msg)
311
323
 
@@ -328,9 +340,9 @@ class Jp2k(Jp2kr):
328
340
 
329
341
  if self.shape[:2] == self.tilesize:
330
342
  msg = (
331
- 'Do not write an image tile-by-tile '
332
- 'if there is only one tile in the first place. '
333
- 'See issue #586'
343
+ "Do not write an image tile-by-tile "
344
+ "if there is only one tile in the first place. "
345
+ "See issue #586"
334
346
  )
335
347
  raise RuntimeError(msg)
336
348
 
@@ -352,9 +364,9 @@ class Jp2k(Jp2kr):
352
364
  # Cinema modes imply MCT.
353
365
  self._cparams.tcp_mct = 1
354
366
 
355
- if cinema_mode == 'cinema2k':
367
+ if cinema_mode == "cinema2k":
356
368
  if fps not in [24, 48]:
357
- msg = 'Cinema2K frame rate must be either 24 or 48.'
369
+ msg = "Cinema2K frame rate must be either 24 or 48."
358
370
  raise ValueError(msg)
359
371
 
360
372
  if fps == 24:
@@ -384,7 +396,7 @@ class Jp2k(Jp2kr):
384
396
 
385
397
  outfile = self.filename.encode()
386
398
  num_pad_bytes = opj2.PATH_LEN - len(outfile)
387
- outfile += b'0' * num_pad_bytes
399
+ outfile += b"0" * num_pad_bytes
388
400
  cparams.outfile = outfile
389
401
 
390
402
  cparams.codec_fmt = self._codec_format
@@ -394,11 +406,11 @@ class Jp2k(Jp2kr):
394
406
  if self._cinema2k:
395
407
  # cinema2k is an integer, so this test is "truthy"
396
408
  self._cparams = cparams
397
- self._set_cinema_params('cinema2k', self._cinema2k)
409
+ self._set_cinema_params("cinema2k", self._cinema2k)
398
410
 
399
411
  if self._cinema4k:
400
412
  self._cparams = cparams
401
- self._set_cinema_params('cinema4k', self._cinema4k)
413
+ self._set_cinema_params("cinema4k", self._cinema4k)
402
414
 
403
415
  if self._cbsize is not None:
404
416
  cparams.cblockw_init = self._cbsize[1]
@@ -491,14 +503,14 @@ class Jp2k(Jp2kr):
491
503
  This method can only be used to create JPEG 2000 images that can fit
492
504
  in memory.
493
505
  """
494
- if version.openjpeg_version < '2.3.0':
506
+ if version.openjpeg_version < "2.3.0":
495
507
  msg = (
496
508
  "You must have at least version 2.3.0 of OpenJPEG in order to "
497
509
  "write images."
498
510
  )
499
511
  raise RuntimeError(msg)
500
512
 
501
- if hasattr(self, '_cparams'):
513
+ if hasattr(self, "_cparams"):
502
514
  msg = (
503
515
  "You cannot write image data to a JPEG 2000 file "
504
516
  "that already exists."
@@ -540,10 +552,9 @@ class Jp2k(Jp2kr):
540
552
  f"and width dimensions must be larger than 4 pixels."
541
553
  )
542
554
  raise InvalidJp2kError(msg)
543
- if (
544
- np.log2(height) != np.floor(np.log2(height))
545
- or np.log2(width) != np.floor(np.log2(width))
546
- ):
555
+ if np.log2(height) != np.floor(np.log2(height)) or np.log2(
556
+ width
557
+ ) != np.floor(np.log2(width)):
547
558
  msg = (
548
559
  f"Bad code block size ({height} x {width}). "
549
560
  f"The dimensions must be powers of 2."
@@ -585,15 +596,13 @@ class Jp2k(Jp2kr):
585
596
  raise InvalidJp2kError(msg)
586
597
 
587
598
  def _validate_image_rank(self, img_array):
588
- """Images must be either 2D or 3D.
589
- """
599
+ """Images must be either 2D or 3D."""
590
600
  if img_array.ndim == 1 or img_array.ndim > 3:
591
601
  msg = f"{img_array.ndim}D imagery is not allowed."
592
602
  raise InvalidJp2kError(msg)
593
603
 
594
604
  def _validate_image_datatype(self, img_array):
595
- """Only uint8 and uint16 images are currently supported.
596
- """
605
+ """Only uint8 and uint16 images are currently supported."""
597
606
  if img_array.dtype != np.uint8 and img_array.dtype != np.uint16:
598
607
  msg = (
599
608
  "Only uint8 and uint16 datatypes are currently supported when "
@@ -631,20 +640,20 @@ class Jp2k(Jp2kr):
631
640
  # Anything else must be RGB, right?
632
641
  self._colorspace = opj2.CLRSPC_SRGB
633
642
  else:
634
- if self._colorspace.lower() not in ('rgb', 'grey', 'gray'):
643
+ if self._colorspace.lower() not in ("rgb", "grey", "gray"):
635
644
  msg = f'Invalid colorspace "{self._colorspace}".'
636
645
  raise InvalidJp2kError(msg)
637
- elif self._colorspace.lower() == 'rgb' and self.shape[2] < 3:
638
- msg = 'RGB colorspace requires at least 3 components.'
646
+ elif self._colorspace.lower() == "rgb" and self.shape[2] < 3:
647
+ msg = "RGB colorspace requires at least 3 components."
639
648
  raise InvalidJp2kError(msg)
640
649
 
641
650
  # Turn the colorspace from a string to the enumerated value that
642
651
  # the library expects.
643
652
  COLORSPACE_MAP = {
644
- 'rgb': opj2.CLRSPC_SRGB,
645
- 'gray': opj2.CLRSPC_GRAY,
646
- 'grey': opj2.CLRSPC_GRAY,
647
- 'ycc': opj2.CLRSPC_YCC
653
+ "rgb": opj2.CLRSPC_SRGB,
654
+ "gray": opj2.CLRSPC_GRAY,
655
+ "grey": opj2.CLRSPC_GRAY,
656
+ "ycc": opj2.CLRSPC_YCC,
648
657
  }
649
658
 
650
659
  self._colorspace = COLORSPACE_MAP[self._colorspace.lower()]
@@ -679,14 +688,14 @@ class Jp2k(Jp2kr):
679
688
 
680
689
  strm = opj2.stream_create_default_file_stream(self.filename, False)
681
690
 
682
- num_threads = get_option('lib.num_threads')
683
- if version.openjpeg_version >= '2.4.0':
691
+ num_threads = get_option("lib.num_threads")
692
+ if version.openjpeg_version >= "2.4.0":
684
693
  opj2.codec_set_threads(codec, num_threads)
685
694
  elif num_threads > 1:
686
695
  msg = (
687
- f'Threaded encoding is not supported in library versions '
688
- f'prior to 2.4.0. Your version is '
689
- f'{version.openjpeg_version}.'
696
+ f"Threaded encoding is not supported in library versions "
697
+ f"prior to 2.4.0. Your version is "
698
+ f"{version.openjpeg_version}."
690
699
  )
691
700
  warnings.warn(msg, UserWarning)
692
701
 
@@ -697,7 +706,8 @@ class Jp2k(Jp2kr):
697
706
  opj2.end_compress(codec, strm)
698
707
 
699
708
  def append(self, box):
700
- """Append a metadata box to the JP2 file. This will not result in a
709
+ """
710
+ Append a metadata box to the JP2 file. This will not result in a
701
711
  file-copy operation. Only XML UUID (XMP), or ASOC boxes can be
702
712
  appended at this time.
703
713
 
@@ -710,14 +720,11 @@ class Jp2k(Jp2kr):
710
720
  msg = "You cannot append to a J2K file (raw codestream)."
711
721
  raise RuntimeError(msg)
712
722
 
713
- box_is_asoc = box.box_id == 'asoc'
714
- box_is_xml = box.box_id == 'xml '
715
- box_is_xmp = (
716
- box.box_id == 'uuid'
717
- and (
718
- box.uuid == UUID('be7acfcb-97a9-42e8-9c71-999491e3afac')
719
- or box.uuid == UUID('b14bf8bd-083d-4b43-a5ae-8cd7d5a6ce03')
720
- )
723
+ box_is_asoc = box.box_id == "asoc"
724
+ box_is_xml = box.box_id == "xml "
725
+ box_is_xmp = box.box_id == "uuid" and (
726
+ box.uuid == UUID("be7acfcb-97a9-42e8-9c71-999491e3afac")
727
+ or box.uuid == UUID("b14bf8bd-083d-4b43-a5ae-8cd7d5a6ce03")
721
728
  )
722
729
  if not (box_is_asoc or box_is_xml or box_is_xmp):
723
730
  msg = (
@@ -728,27 +735,28 @@ class Jp2k(Jp2kr):
728
735
 
729
736
  # Check the last box. If the length field is zero, then rewrite
730
737
  # the length field to reflect the true length of the box.
731
- with self.path.open('rb') as ifile:
738
+ with self.path.open("rb") as ifile:
732
739
  offset = self.box[-1].offset
733
740
  ifile.seek(offset)
734
741
  read_buffer = ifile.read(4)
735
- box_length, = struct.unpack('>I', read_buffer)
742
+ (box_length,) = struct.unpack(">I", read_buffer)
736
743
  if box_length == 0:
737
744
  # Reopen the file in write mode and rewrite the length field.
738
745
  true_box_length = self.path.stat().st_size - offset
739
- with self.path.open('r+b') as ofile:
746
+ with self.path.open("r+b") as ofile:
740
747
  ofile.seek(offset)
741
- write_buffer = struct.pack('>I', true_box_length)
748
+ write_buffer = struct.pack(">I", true_box_length)
742
749
  ofile.write(write_buffer)
743
750
 
744
751
  # Can now safely append the box.
745
- with self.path.open('ab') as ofile:
752
+ with self.path.open("ab") as ofile:
746
753
  box.write(ofile)
747
754
 
748
755
  self.parse(force=True)
749
756
 
750
757
  def wrap(self, filename, boxes=None):
751
- """Create a new JP2/JPX file wrapped in a new set of JP2 boxes.
758
+ """
759
+ Create a new JP2/JPX file wrapped in a new set of JP2 boxes.
752
760
 
753
761
  This method is primarily aimed at wrapping a raw codestream in a set of
754
762
  of JP2 boxes (turning it into a JP2 file instead of just a raw
@@ -776,9 +784,9 @@ class Jp2k(Jp2kr):
776
784
 
777
785
  self._validate_jp2_box_sequence(boxes)
778
786
 
779
- with open(filename, 'wb') as ofile:
787
+ with open(filename, "wb") as ofile:
780
788
  for box in boxes:
781
- if box.box_id != 'jp2c':
789
+ if box.box_id != "jp2c":
782
790
  box.write(ofile)
783
791
  else:
784
792
  self._write_wrapped_codestream(ofile, box)
@@ -794,9 +802,9 @@ class Jp2k(Jp2kr):
794
802
  if len(self.box) == 0:
795
803
  # Yes, just write the codestream box header plus all
796
804
  # of myself out to file.
797
- ofile.write(struct.pack('>I', self.length + 8))
798
- ofile.write(b'jp2c')
799
- with open(self.filename, 'rb') as ifile:
805
+ ofile.write(struct.pack(">I", self.length + 8))
806
+ ofile.write(b"jp2c")
807
+ with open(self.filename, "rb") as ifile:
800
808
  ofile.write(ifile.read())
801
809
  return
802
810
 
@@ -804,7 +812,7 @@ class Jp2k(Jp2kr):
804
812
  # actually starts.
805
813
  offset = box.offset
806
814
  if offset == -1:
807
- if self.box[1].brand == 'jpx ':
815
+ if self.box[1].brand == "jpx ":
808
816
  msg = (
809
817
  "The codestream box must have its offset and length "
810
818
  "attributes fully specified if the file type brand is JPX."
@@ -812,17 +820,17 @@ class Jp2k(Jp2kr):
812
820
  raise InvalidJp2kError(msg)
813
821
 
814
822
  # Find the first codestream in the file.
815
- jp2c = [_box for _box in self.box if _box.box_id == 'jp2c']
823
+ jp2c = [_box for _box in self.box if _box.box_id == "jp2c"]
816
824
  offset = jp2c[0].offset
817
825
 
818
826
  # Ready to write the codestream.
819
- with open(self.filename, 'rb') as ifile:
827
+ with open(self.filename, "rb") as ifile:
820
828
  ifile.seek(offset)
821
829
 
822
830
  # Verify that the specified codestream is right.
823
831
  read_buffer = ifile.read(8)
824
- L, T = struct.unpack_from('>I4s', read_buffer, 0)
825
- if T != b'jp2c':
832
+ L, T = struct.unpack_from(">I4s", read_buffer, 0)
833
+ if T != b"jp2c":
826
834
  msg = "Unable to locate the specified codestream."
827
835
  raise InvalidJp2kError(msg)
828
836
  if L == 0:
@@ -833,7 +841,7 @@ class Jp2k(Jp2kr):
833
841
  elif L == 1:
834
842
  # The length of the box is in the XL field, a 64-bit value.
835
843
  read_buffer = ifile.read(8)
836
- L, = struct.unpack('>Q', read_buffer)
844
+ (L,) = struct.unpack(">Q", read_buffer)
837
845
 
838
846
  ifile.seek(offset)
839
847
  read_buffer = ifile.read(L)
@@ -846,7 +854,7 @@ class Jp2k(Jp2kr):
846
854
  JPEG2000SignatureBox(),
847
855
  FileTypeBox(),
848
856
  JP2HeaderBox(),
849
- ContiguousCodestreamBox()
857
+ ContiguousCodestreamBox(),
850
858
  ]
851
859
  height = self.codestream.segment[1].ysiz
852
860
  width = self.codestream.segment[1].xsiz
@@ -860,14 +868,14 @@ class Jp2k(Jp2kr):
860
868
  else:
861
869
  # Take whatever the first jp2 header / color specification
862
870
  # says.
863
- jp2hs = [box for box in self.box if box.box_id == 'jp2h']
871
+ jp2hs = [box for box in self.box if box.box_id == "jp2h"]
864
872
  colorspace = jp2hs[0].box[1].colorspace
865
873
 
866
874
  boxes[2].box = [
867
875
  ImageHeaderBox(
868
876
  height=height, width=width, num_components=num_components
869
877
  ),
870
- ColourSpecificationBox(colorspace=colorspace)
878
+ ColourSpecificationBox(colorspace=colorspace),
871
879
  ]
872
880
 
873
881
  return boxes
@@ -1011,8 +1019,10 @@ class Jp2k(Jp2kr):
1011
1019
 
1012
1020
  # Stage the image data to the openjpeg data structure.
1013
1021
  for k in range(0, num_comps):
1014
- if self._cparams.rsiz in (core.OPJ_PROFILE_CINEMA_2K,
1015
- core.OPJ_PROFILE_CINEMA_4K):
1022
+ if self._cparams.rsiz in (
1023
+ core.OPJ_PROFILE_CINEMA_2K,
1024
+ core.OPJ_PROFILE_CINEMA_4K,
1025
+ ):
1016
1026
  image.contents.comps[k].prec = 12
1017
1027
  image.contents.comps[k].bpp = 12
1018
1028
 
@@ -1064,15 +1074,29 @@ class Jp2k(Jp2kr):
1064
1074
  This is non-exhaustive.
1065
1075
  """
1066
1076
  JP2_IDS = [
1067
- 'colr', 'cdef', 'cmap', 'jp2c', 'ftyp', 'ihdr', 'jp2h', 'jP ',
1068
- 'pclr', 'res ', 'resc', 'resd', 'xml ', 'ulst', 'uinf', 'url ',
1069
- 'uuid'
1077
+ "colr",
1078
+ "cdef",
1079
+ "cmap",
1080
+ "jp2c",
1081
+ "ftyp",
1082
+ "ihdr",
1083
+ "jp2h",
1084
+ "jP ",
1085
+ "pclr",
1086
+ "res ",
1087
+ "resc",
1088
+ "resd",
1089
+ "xml ",
1090
+ "ulst",
1091
+ "uinf",
1092
+ "url ",
1093
+ "uuid",
1070
1094
  ]
1071
1095
 
1072
1096
  self._validate_signature_compatibility(boxes)
1073
1097
  self._validate_jp2h(boxes)
1074
1098
  self._validate_jp2c(boxes)
1075
- if boxes[1].brand == 'jpx ':
1099
+ if boxes[1].brand == "jpx ":
1076
1100
  self._validate_jpx_box_sequence(boxes)
1077
1101
  else:
1078
1102
  # Validate the JP2 box IDs.
@@ -1089,8 +1113,8 @@ class Jp2k(Jp2kr):
1089
1113
 
1090
1114
  def _validate_jp2_colr(self, boxes):
1091
1115
  """Validate JP2 requirements on colour specification boxes."""
1092
- jp2h = next(filter(lambda x: x.box_id == 'jp2h', boxes), None)
1093
- for colr in [box for box in jp2h.box if box.box_id == 'colr']:
1116
+ jp2h = next(filter(lambda x: x.box_id == "jp2h", boxes), None)
1117
+ for colr in [box for box in jp2h.box if box.box_id == "colr"]:
1094
1118
  if colr.approximation != 0:
1095
1119
  msg = (
1096
1120
  "A JP2 colr box cannot have a non-zero approximation "
@@ -1109,7 +1133,7 @@ class Jp2k(Jp2kr):
1109
1133
  """Validate the file signature and compatibility status."""
1110
1134
  # Check for a bad sequence of boxes.
1111
1135
  # 1st two boxes must be 'jP ' and 'ftyp'
1112
- if boxes[0].box_id != 'jP ' or boxes[1].box_id != 'ftyp':
1136
+ if boxes[0].box_id != "jP " or boxes[1].box_id != "ftyp":
1113
1137
  msg = (
1114
1138
  "The first box must be the signature box and the second must "
1115
1139
  "be the file type box."
@@ -1117,7 +1141,7 @@ class Jp2k(Jp2kr):
1117
1141
  raise InvalidJp2kError(msg)
1118
1142
 
1119
1143
  # The compatibility list must contain at a minimum 'jp2 '.
1120
- if 'jp2 ' not in boxes[1].compatibility_list:
1144
+ if "jp2 " not in boxes[1].compatibility_list:
1121
1145
  msg = "The ftyp box must contain 'jp2 ' in the compatibility list."
1122
1146
  raise InvalidJp2kError(msg)
1123
1147
 
@@ -1125,11 +1149,11 @@ class Jp2k(Jp2kr):
1125
1149
  """Validate the codestream box in relation to other boxes."""
1126
1150
  # jp2c must be preceeded by jp2h
1127
1151
  jp2h_idx, _ = next(
1128
- filter(lambda x: x[1].box_id == 'jp2h', enumerate(boxes)),
1152
+ filter(lambda x: x[1].box_id == "jp2h", enumerate(boxes)),
1129
1153
  (None, None)
1130
1154
  )
1131
1155
  jp2c_idx, _ = next(
1132
- filter(lambda x: x[1].box_id == 'jp2c', enumerate(boxes)),
1156
+ filter(lambda x: x[1].box_id == "jp2c", enumerate(boxes)),
1133
1157
  (None, None)
1134
1158
  )
1135
1159
  if jp2c_idx is None:
@@ -1145,9 +1169,9 @@ class Jp2k(Jp2kr):
1145
1169
 
1146
1170
  def _validate_jp2h(self, boxes):
1147
1171
  """Validate the JP2 Header box."""
1148
- self._check_jp2h_child_boxes(boxes, 'top-level')
1172
+ self._check_jp2h_child_boxes(boxes, "top-level")
1149
1173
 
1150
- jp2h = next(filter(lambda x: x.box_id == 'jp2h', boxes), None)
1174
+ jp2h = next(filter(lambda x: x.box_id == "jp2h", boxes), None)
1151
1175
 
1152
1176
  # 1st jp2 header box cannot be empty.
1153
1177
  if len(jp2h.box) == 0:
@@ -1155,7 +1179,7 @@ class Jp2k(Jp2kr):
1155
1179
  raise InvalidJp2kError(msg)
1156
1180
 
1157
1181
  # 1st jp2 header box must be ihdr
1158
- if jp2h.box[0].box_id != 'ihdr':
1182
+ if jp2h.box[0].box_id != "ihdr":
1159
1183
  msg = (
1160
1184
  "The first box in the jp2 header box must be the image header "
1161
1185
  "box."
@@ -1163,7 +1187,7 @@ class Jp2k(Jp2kr):
1163
1187
  raise InvalidJp2kError(msg)
1164
1188
 
1165
1189
  # colr must be present in jp2 header box.
1166
- colr = next(filter(lambda x: x.box_id == 'colr', jp2h.box), None)
1190
+ colr = next(filter(lambda x: x.box_id == "colr", jp2h.box), None)
1167
1191
  if colr is None:
1168
1192
  msg = "The jp2 header box must contain a color definition box."
1169
1193
  raise InvalidJp2kError(msg)
@@ -1173,36 +1197,44 @@ class Jp2k(Jp2kr):
1173
1197
  def _validate_channel_definition(self, jp2h, colr):
1174
1198
  """Validate the channel definition box."""
1175
1199
  cdef_lst = [
1176
- idx for (idx, box) in enumerate(jp2h.box) if box.box_id == 'cdef'
1200
+ idx for (idx, box) in enumerate(jp2h.box) if box.box_id == "cdef"
1177
1201
  ]
1178
1202
  if len(cdef_lst) > 1:
1179
- msg = ("Only one channel definition box is allowed in the "
1180
- "JP2 header.")
1203
+ msg = (
1204
+ "Only one channel definition box is allowed in the "
1205
+ "JP2 header."
1206
+ )
1181
1207
  raise InvalidJp2kError(msg)
1182
1208
  elif len(cdef_lst) == 1:
1183
1209
  cdef = jp2h.box[cdef_lst[0]]
1184
1210
  if colr.colorspace == core.SRGB:
1185
- if any([
1186
- chan + 1 not in cdef.association
1187
- or cdef.channel_type[chan] != 0
1188
- for chan in [0, 1, 2]
1189
- ]):
1190
- msg = ("All color channels must be defined in the "
1191
- "channel definition box.")
1211
+ if any(
1212
+ [
1213
+ chan + 1 not in cdef.association
1214
+ or cdef.channel_type[chan] != 0
1215
+ for chan in [0, 1, 2]
1216
+ ]
1217
+ ):
1218
+ msg = (
1219
+ "All color channels must be defined in the "
1220
+ "channel definition box."
1221
+ )
1192
1222
  raise InvalidJp2kError(msg)
1193
1223
  elif colr.colorspace == core.GREYSCALE:
1194
1224
  if 0 not in cdef.channel_type:
1195
- msg = ("All color channels must be defined in the "
1196
- "channel definition box.")
1225
+ msg = (
1226
+ "All color channels must be defined in the "
1227
+ "channel definition box."
1228
+ )
1197
1229
  raise InvalidJp2kError(msg)
1198
1230
 
1199
1231
  def _check_jp2h_child_boxes(self, boxes, parent_box_name):
1200
1232
  """Certain boxes can only reside in the JP2 header."""
1201
- JP2H_CHILDREN = set(['bpcc', 'cdef', 'cmap', 'ihdr', 'pclr'])
1233
+ JP2H_CHILDREN = set(["bpcc", "cdef", "cmap", "ihdr", "pclr"])
1202
1234
 
1203
1235
  box_ids = set([box.box_id for box in boxes])
1204
1236
  intersection = box_ids.intersection(JP2H_CHILDREN)
1205
- if len(intersection) > 0 and parent_box_name not in ['jp2h', 'jpch']:
1237
+ if len(intersection) > 0 and parent_box_name not in ["jp2h", "jpch"]:
1206
1238
  msg = (
1207
1239
  f"A {list(intersection)[0]} box can only be nested in a JP2 "
1208
1240
  f"header box."
@@ -1211,7 +1243,7 @@ class Jp2k(Jp2kr):
1211
1243
 
1212
1244
  # Recursively check any contained superboxes.
1213
1245
  for box in boxes:
1214
- if hasattr(box, 'box'):
1246
+ if hasattr(box, "box"):
1215
1247
  self._check_jp2h_child_boxes(box.box, box.box_id)
1216
1248
 
1217
1249
  def _collect_box_count(self, boxes):
@@ -1220,7 +1252,7 @@ class Jp2k(Jp2kr):
1220
1252
 
1221
1253
  # Add the counts in the superboxes.
1222
1254
  for box in boxes:
1223
- if hasattr(box, 'box'):
1255
+ if hasattr(box, "box"):
1224
1256
  count.update(self._collect_box_count(box.box))
1225
1257
 
1226
1258
  return count
@@ -1229,7 +1261,7 @@ class Jp2k(Jp2kr):
1229
1261
  """Several boxes can only occur at the top level."""
1230
1262
  # We are only looking at the boxes contained in a superbox, so if any
1231
1263
  # of the blacklisted boxes show up here, it's an error.
1232
- TOP_LEVEL_ONLY_BOXES = set(['dtbl'])
1264
+ TOP_LEVEL_ONLY_BOXES = set(["dtbl"])
1233
1265
  box_ids = set([box.box_id for box in boxes])
1234
1266
  intersection = box_ids.intersection(TOP_LEVEL_ONLY_BOXES)
1235
1267
  if len(intersection) > 0:
@@ -1241,22 +1273,24 @@ class Jp2k(Jp2kr):
1241
1273
 
1242
1274
  # Recursively check any contained superboxes.
1243
1275
  for box in boxes:
1244
- if hasattr(box, 'box'):
1276
+ if hasattr(box, "box"):
1245
1277
  self._check_superbox_for_top_levels(box.box)
1246
1278
 
1247
1279
  def _validate_top_level(self, boxes):
1248
1280
  """Several boxes can only occur at the top level."""
1249
1281
  # Add the counts in the superboxes.
1250
1282
  for box in boxes:
1251
- if hasattr(box, 'box'):
1283
+ if hasattr(box, "box"):
1252
1284
  self._check_superbox_for_top_levels(box.box)
1253
1285
 
1254
1286
  count = self._collect_box_count(boxes)
1255
1287
 
1256
1288
  # If there is one data reference box, then there must also be one ftbl.
1257
- if 'dtbl' in count and 'ftbl' not in count:
1258
- msg = ('The presence of a data reference box requires the '
1259
- 'presence of a fragment table box as well.')
1289
+ if "dtbl" in count and "ftbl" not in count:
1290
+ msg = (
1291
+ "The presence of a data reference box requires the "
1292
+ "presence of a fragment table box as well."
1293
+ )
1260
1294
  raise InvalidJp2kError(msg)
1261
1295
 
1262
1296
  def _validate_singletons(self, boxes):
@@ -1264,24 +1298,24 @@ class Jp2k(Jp2kr):
1264
1298
  count = self._collect_box_count(boxes)
1265
1299
  # Which boxes occur more than once?
1266
1300
  multiples = [box_id for box_id, bcount in count.items() if bcount > 1]
1267
- if 'dtbl' in multiples:
1268
- raise InvalidJp2kError('There can only be one dtbl box in a file.')
1301
+ if "dtbl" in multiples:
1302
+ raise InvalidJp2kError("There can only be one dtbl box in a file.")
1269
1303
 
1270
1304
  def _validate_jpx_compatibility(self, boxes, compatibility_list):
1271
1305
  """If there is a JPX box then the compatibility list must also contain
1272
1306
  'jpx '.
1273
1307
  """
1274
- JPX_IDS = ['asoc', 'nlst']
1308
+ JPX_IDS = ["asoc", "nlst"]
1275
1309
  jpx_cl = set(compatibility_list)
1276
1310
  for box in boxes:
1277
1311
  if box.box_id in JPX_IDS:
1278
- if len(set(['jpx ', 'jpxb']).intersection(jpx_cl)) == 0:
1312
+ if len(set(["jpx ", "jpxb"]).intersection(jpx_cl)) == 0:
1279
1313
  msg = (
1280
1314
  "A JPX box requires that either 'jpx ' or 'jpxb' be "
1281
1315
  "present in the ftype compatibility list."
1282
1316
  )
1283
1317
  raise InvalidJp2kError(msg)
1284
- if hasattr(box, 'box') != 0:
1318
+ if hasattr(box, "box") != 0:
1285
1319
  # Same set of checks on any child boxes.
1286
1320
  self._validate_jpx_compatibility(box.box, compatibility_list)
1287
1321
 
@@ -1290,16 +1324,15 @@ class Jp2k(Jp2kr):
1290
1324
  compositing layer header boxes.
1291
1325
  """
1292
1326
  for box in boxes:
1293
- if box.box_id != 'asoc':
1294
- if hasattr(box, 'box'):
1295
- for boxi in box.box:
1296
- if boxi.box_id == 'lbl ':
1297
- msg = (
1298
- f"A label box cannot be nested inside a "
1299
- f"{box.box_id} box."
1300
- )
1301
- raise InvalidJp2kError(msg)
1302
- # Same set of checks on any child boxes.
1327
+ if box.box_id != "asoc" and hasattr(box, "box"):
1328
+ for boxi in box.box:
1329
+ if boxi.box_id == "lbl ":
1330
+ msg = (
1331
+ f"A label box cannot be nested inside a "
1332
+ f"{box.box_id} box."
1333
+ )
1334
+ raise InvalidJp2kError(msg)
1335
+ # Same set of checks on any child boxes.
1303
1336
  self._validate_label(box.box)
1304
1337
 
1305
1338
 
@@ -1348,9 +1381,11 @@ class _TileWriter(object):
1348
1381
  """Write image data to a JP2/JPX/J2k file. Intended usage of the
1349
1382
  various parameters follows that of OpenJPEG's opj_compress utility.
1350
1383
  """
1351
- if version.openjpeg_version < '2.3.0':
1352
- msg = ("You must have at least version 2.3.0 of OpenJPEG "
1353
- "in order to write images.")
1384
+ if version.openjpeg_version < "2.3.0":
1385
+ msg = (
1386
+ "You must have at least version 2.3.0 of OpenJPEG "
1387
+ "in order to write images."
1388
+ )
1354
1389
  raise RuntimeError(msg)
1355
1390
 
1356
1391
  if not isinstance(index, slice):
@@ -1368,7 +1403,7 @@ class _TileWriter(object):
1368
1403
  self.codec,
1369
1404
  self.tile_index,
1370
1405
  _set_planar_pixel_order(img_array),
1371
- self.stream
1406
+ self.stream,
1372
1407
  )
1373
1408
  except glymur.lib.openjp2.OpenJPEGLibraryError as e:
1374
1409
  # properly dispose of these resources
@@ -1386,8 +1421,7 @@ class _TileWriter(object):
1386
1421
  opj2.destroy_codec(self.codec)
1387
1422
 
1388
1423
  def setup_first_tile(self, img_array):
1389
- """Only do these things for the first tile.
1390
- """
1424
+ """Only do these things for the first tile."""
1391
1425
  self.jp2k._determine_colorspace()
1392
1426
  self.jp2k._populate_cparams(img_array)
1393
1427
  self.jp2k._populate_comptparms(img_array)
@@ -1408,9 +1442,10 @@ class _TileWriter(object):
1408
1442
  )
1409
1443
 
1410
1444
  self.jp2k._populate_image_struct(
1411
- self.image, img_array,
1445
+ self.image,
1446
+ img_array,
1412
1447
  tile_x_factor=self.num_tile_cols,
1413
- tile_y_factor=self.num_tile_rows
1448
+ tile_y_factor=self.num_tile_rows,
1414
1449
  )
1415
1450
  self.image.contents.x1 = self.jp2k.shape[1]
1416
1451
  self.image.contents.y1 = self.jp2k.shape[0]
@@ -1421,17 +1456,18 @@ class _TileWriter(object):
1421
1456
  opj2.encoder_set_extra_options(self.codec, plt=self.jp2k._plt)
1422
1457
 
1423
1458
  self.stream = opj2.stream_create_default_file_stream(
1424
- self.jp2k.filename, False
1459
+ self.jp2k.filename,
1460
+ False
1425
1461
  )
1426
1462
 
1427
- num_threads = get_option('lib.num_threads')
1428
- if version.openjpeg_version >= '2.4.0':
1463
+ num_threads = get_option("lib.num_threads")
1464
+ if version.openjpeg_version >= "2.4.0":
1429
1465
  opj2.codec_set_threads(self.codec, num_threads)
1430
1466
  elif num_threads > 1:
1431
1467
  msg = (
1432
- f'Threaded encoding is not supported in library versions '
1433
- f'prior to 2.4.0. Your version is '
1434
- f'{version.openjpeg_version}.'
1468
+ f"Threaded encoding is not supported in library versions "
1469
+ f"prior to 2.4.0. Your version is "
1470
+ f"{version.openjpeg_version}."
1435
1471
  )
1436
1472
  warnings.warn(msg, UserWarning)
1437
1473