Glymur 0.13.8__py3-none-any.whl → 0.14.0.post1__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/tiff.py CHANGED
@@ -1,13 +1,10 @@
1
1
  # standard library imports
2
2
  from __future__ import annotations
3
- import io
4
3
  import logging
5
4
  import pathlib
6
5
  import shutil
7
- import struct
8
6
  import sys
9
7
  from typing import List, Tuple
10
- from uuid import UUID
11
8
  import warnings
12
9
 
13
10
  # 3rd party library imports
@@ -15,21 +12,16 @@ import numpy as np
15
12
 
16
13
  # local imports
17
14
  from glymur import Jp2k, set_option
18
- from glymur.core import SRGB, RESTRICTED_ICC_PROFILE
15
+ from glymur.core import SRGB
16
+ from ._core_converter import _2JP2Converter
19
17
  from .lib import tiff as libtiff
20
- from .lib.tiff import DATATYPE2FMT
21
18
  from . import jp2box
22
19
 
23
20
  # we need a lower case mapping from the tag name to the tag number
24
21
  TAGNAME2NUM = {k.lower(): v["number"] for k, v in libtiff.TAGS.items()}
25
22
 
26
23
 
27
- # Mnemonics for the two TIFF format version numbers.
28
- _TIFF = 42
29
- _BIGTIFF = 43
30
-
31
-
32
- class Tiff2Jp2k(object):
24
+ class Tiff2Jp2k(_2JP2Converter):
33
25
  """
34
26
  Transform a TIFF image into a JP2 image.
35
27
 
@@ -45,7 +37,7 @@ class Tiff2Jp2k(object):
45
37
  Dimensions of the image.
46
38
  jp2 : JP2K object
47
39
  Write to this JPEG2000 file
48
- jp2_filename : path
40
+ jp2_path : path
49
41
  Path to JPEG 2000 file to be written.
50
42
  jp2_kwargs : dict
51
43
  Keyword arguments to pass along to the Jp2k constructor.
@@ -55,7 +47,7 @@ class Tiff2Jp2k(object):
55
47
  The number of rows per strip in the TIFF.
56
48
  spp : int
57
49
  Samples Per Pixel TIFF tag value
58
- tiff_filename : path
50
+ tiff_path : path
59
51
  Path to TIFF file.
60
52
  tilesize : tuple
61
53
  The dimensions of a tile in the JP2K file.
@@ -69,8 +61,8 @@ class Tiff2Jp2k(object):
69
61
 
70
62
  def __init__(
71
63
  self,
72
- tiff_filename: pathlib.Path,
73
- jp2_filename: pathlib.Path,
64
+ tiff_path: pathlib.Path,
65
+ jp2_path: pathlib.Path,
74
66
  create_exif_uuid: bool = True,
75
67
  create_xmp_uuid: bool = True,
76
68
  exclude_tags: List[int | str] | None = None,
@@ -105,16 +97,25 @@ class Tiff2Jp2k(object):
105
97
  verbosity : int
106
98
  Set the level of logging, i.e. WARNING, INFO, etc.
107
99
  """
100
+ super().__init__(
101
+ create_exif_uuid, create_xmp_uuid, include_icc_profile, tilesize,
102
+ verbosity
103
+ )
108
104
 
109
- self.tiff_filename = tiff_filename
110
- if not self.tiff_filename.exists():
111
- raise FileNotFoundError(f"{tiff_filename} does not exist")
105
+ self.tiff_path = pathlib.Path(tiff_path)
106
+ if not self.tiff_path.exists():
107
+ raise FileNotFoundError(f"{tiff_path} does not exist")
108
+
109
+ self.jp2_path = pathlib.Path(jp2_path)
110
+ if self.jp2_path.exists():
111
+ msg = (
112
+ f'{str(self.jp2_path)} already exists, ',
113
+ 'please delete if you wish to overwrite.'
114
+ )
115
+ raise FileExistsError(msg)
112
116
 
113
- self.jp2_filename = jp2_filename
114
- self.tilesize = tilesize
115
117
  self.create_exif_uuid = create_exif_uuid
116
118
  self.create_xmp_uuid = create_xmp_uuid
117
- self.include_icc_profile = include_icc_profile
118
119
 
119
120
  if exclude_tags is None:
120
121
  exclude_tags = []
@@ -126,9 +127,6 @@ class Tiff2Jp2k(object):
126
127
  # Assume that there is no ColorMap tag until we know otherwise.
127
128
  self._colormap = None
128
129
 
129
- # Assume that there is no ICC profile tag until we know otherwise.
130
- self.icc_profile = None
131
-
132
130
  # Assume no XML_PACKET tag until we know otherwise.
133
131
  self.xmp_data = None
134
132
 
@@ -188,16 +186,9 @@ class Tiff2Jp2k(object):
188
186
 
189
187
  return lst
190
188
 
191
- def setup_logging(self, verbosity):
192
- self.logger = logging.getLogger("tiff2jp2")
193
- self.logger.setLevel(verbosity)
194
- ch = logging.StreamHandler()
195
- ch.setLevel(verbosity)
196
- self.logger.addHandler(ch)
197
-
198
189
  def __enter__(self):
199
190
  """The Tiff2Jp2k must be used with a context manager."""
200
- self.tiff_fp = libtiff.open(self.tiff_filename)
191
+ self.tiff_fp = libtiff.open(str(self.tiff_path))
201
192
  return self
202
193
 
203
194
  def __exit__(self, exc_type, exc_value, exc_traceback):
@@ -249,43 +240,11 @@ class Tiff2Jp2k(object):
249
240
  colr = [box for box in jp2h.box if box.box_id == "colr"][0]
250
241
  colr.colorspace = SRGB
251
242
 
252
- temp_filename = str(self.jp2_filename) + ".tmp"
243
+ temp_filename = str(self.jp2_path) + ".tmp"
253
244
  self.jp2.wrap(temp_filename, boxes=self.jp2.box)
254
- shutil.move(temp_filename, self.jp2_filename)
245
+ shutil.move(temp_filename, self.jp2_path)
255
246
  self.jp2.parse()
256
247
 
257
- def rewrap_for_icc_profile(self):
258
- """Consume a TIFF ICC profile, if one is there."""
259
- if self.icc_profile is None and self.include_icc_profile:
260
- self.logger.warning("No ICC profile was found.")
261
-
262
- if self.icc_profile is None or not self.include_icc_profile:
263
- return
264
-
265
- self.logger.info(
266
- "Consuming an ICC profile into JP2 color specification box."
267
- )
268
-
269
- colr = jp2box.ColourSpecificationBox(
270
- method=RESTRICTED_ICC_PROFILE,
271
- precedence=0,
272
- icc_profile=self.icc_profile
273
- )
274
-
275
- # construct the new set of JP2 boxes, insert the color specification
276
- # box with the ICC profile
277
- jp2 = Jp2k(self.jp2_filename)
278
- boxes = jp2.box
279
- boxes[2].box = [boxes[2].box[0], colr]
280
-
281
- # re-wrap the codestream, involves a file copy
282
- tmp_filename = str(self.jp2_filename) + ".tmp"
283
-
284
- with open(tmp_filename, mode="wb") as tfile:
285
- jp2.wrap(tfile.name, boxes=boxes)
286
-
287
- shutil.move(tmp_filename, self.jp2_filename)
288
-
289
248
  def append_extra_jp2_boxes(self):
290
249
  """Copy over the TIFF IFD. Place it in a UUID box. Append to the JPEG
291
250
  2000 file.
@@ -293,69 +252,13 @@ class Tiff2Jp2k(object):
293
252
  self.append_exif_uuid_box()
294
253
  self.append_xmp_uuid_box()
295
254
 
296
- def append_exif_uuid_box(self):
297
- """Append an EXIF UUID box onto the end of the JPEG 2000 file. It will
298
- contain metadata from the TIFF IFD.
299
- """
300
- if not self.create_exif_uuid:
301
- return
302
-
303
- # create a bytesio object for the IFD
304
- b = io.BytesIO()
305
-
306
- # write this 32-bit header into the UUID, no matter if we had bigtiff
307
- # or regular tiff or big endian
308
- data = struct.pack("<BBHI", 73, 73, 42, 8)
309
- b.write(data)
310
-
311
- self._write_ifd(b, self.tags)
312
-
313
- # create the Exif UUID
314
- if self.found_geotiff_tags:
315
- # geotiff UUID
316
- the_uuid = UUID("b14bf8bd-083d-4b43-a5ae-8cd7d5a6ce03")
317
- payload = b.getvalue()
318
- else:
319
- # Make it an exif UUID.
320
- the_uuid = UUID(bytes=b"JpgTiffExif->JP2")
321
- payload = b"EXIF\0\0" + b.getvalue()
322
-
323
- # the length of the box is the length of the payload plus 8 bytes
324
- # to store the length of the box and the box ID
325
- box_length = len(payload) + 8
326
-
327
- uuid_box = jp2box.UUIDBox(the_uuid, payload, box_length)
328
- with open(self.jp2_filename, mode="ab") as f:
329
- uuid_box.write(f)
330
-
331
- self.jp2.finalize(force_parse=True)
332
-
333
- def append_xmp_uuid_box(self):
334
- """Append an XMP UUID box onto the end of the JPEG 2000 file if there
335
- was an XMP tag in the TIFF IFD.
336
- """
337
-
338
- if self.xmp_data is None:
339
- return
340
-
341
- if not self.create_xmp_uuid:
342
- return
343
-
344
- # create the XMP UUID
345
- the_uuid = jp2box.UUID("be7acfcb-97a9-42e8-9c71-999491e3afac")
346
- payload = bytes(self.xmp_data)
347
- box_length = len(payload) + 8
348
- uuid_box = jp2box.UUIDBox(the_uuid, payload, box_length)
349
- with open(self.jp2_filename, mode="ab") as f:
350
- uuid_box.write(f)
351
-
352
255
  def get_main_ifd(self):
353
256
  """Read all the tags in the main IFD. We do it this way because of the
354
257
  difficulty in using TIFFGetFieldDefaulted when the datatype of a tag
355
258
  can differ.
356
259
  """
357
260
 
358
- with open(self.tiff_filename, "rb") as tfp:
261
+ with self.tiff_path.open(mode="rb") as tfp:
359
262
 
360
263
  self.read_tiff_header(tfp)
361
264
 
@@ -372,19 +275,11 @@ class Tiff2Jp2k(object):
372
275
  if 700 in self.tags:
373
276
 
374
277
  # XMLPacket
375
- self.xmp_data = self.tags[700]["payload"]
278
+ self.xmp_data = bytes(self.tags[700]["payload"])
376
279
 
377
280
  else:
378
281
  self.xmp_data = None
379
282
 
380
- if 34665 in self.tags:
381
- # we have an EXIF IFD
382
- offset = self.tags[34665]["payload"][0]
383
- tfp.seek(offset)
384
- exif_ifd = self.read_ifd(tfp)
385
-
386
- self.tags[34665]["payload"] = exif_ifd
387
-
388
283
  if 34675 in self.tags:
389
284
  # ICC profile
390
285
  self.icc_profile = bytes(self.tags[34675]["payload"])
@@ -392,232 +287,6 @@ class Tiff2Jp2k(object):
392
287
  else:
393
288
  self.icc_profile = None
394
289
 
395
- def read_ifd(self, tfp):
396
- """Process either the main IFD or an Exif IFD
397
-
398
- Parameters
399
- ----------
400
- tfp : file-like
401
- FILE pointer for TIFF
402
-
403
- Returns
404
- -------
405
- dictionary of the TIFF IFD
406
- """
407
-
408
- self.found_geotiff_tags = False
409
-
410
- tag_length = 20 if self.version == _BIGTIFF else 12
411
-
412
- # how many tags?
413
- if self.version == _BIGTIFF:
414
- buffer = tfp.read(8)
415
- (num_tags,) = struct.unpack(self.endian + "Q", buffer)
416
- else:
417
- buffer = tfp.read(2)
418
- (num_tags,) = struct.unpack(self.endian + "H", buffer)
419
-
420
- # Ok, so now we have the IFD main body, but following that we have
421
- # the tag payloads that cannot fit into 4 bytes.
422
-
423
- # the IFD main body in the TIFF. As it might be big endian, we
424
- # cannot just process it as one big chunk.
425
- buffer = tfp.read(num_tags * tag_length)
426
-
427
- if self.version == _BIGTIFF:
428
- tag_format_str = self.endian + "HHQQ"
429
- tag_payload_offset = 12
430
- max_tag_payload_length = 8
431
- else:
432
- tag_format_str = self.endian + "HHII"
433
- tag_payload_offset = 8
434
- max_tag_payload_length = 4
435
-
436
- tags = {}
437
-
438
- for idx in range(num_tags):
439
-
440
- self.logger.debug(f"tag #: {idx}")
441
-
442
- tag_data = buffer[idx * tag_length:(idx + 1) * tag_length]
443
-
444
- tag, dtype, nvalues, offset = struct.unpack(
445
- tag_format_str, tag_data
446
- ) # noqa : E501
447
-
448
- if tag == 34735:
449
- self.found_geotiff_tags = True
450
-
451
- payload_length = DATATYPE2FMT[dtype]["nbytes"] * nvalues
452
-
453
- if payload_length > max_tag_payload_length:
454
- # the payload does not fit into the tag entry, so use the
455
- # offset to seek to that position
456
- current_position = tfp.tell()
457
- tfp.seek(offset)
458
- payload_buffer = tfp.read(payload_length)
459
- tfp.seek(current_position)
460
-
461
- # read the payload from the TIFF
462
- payload_format = DATATYPE2FMT[dtype]["format"] * nvalues
463
- payload = struct.unpack(
464
- self.endian + payload_format,
465
- payload_buffer
466
- )
467
-
468
- else:
469
- # the payload DOES fit into the TIFF tag entry
470
- payload_buffer = tag_data[tag_payload_offset:]
471
-
472
- # read ALL of the payload buffer
473
- fmt = DATATYPE2FMT[dtype]["format"]
474
- nelts = max_tag_payload_length / DATATYPE2FMT[dtype]["nbytes"]
475
- num_items = int(nelts)
476
- payload_format = self.endian + fmt * num_items
477
- payload = struct.unpack(payload_format, payload_buffer)
478
-
479
- # Extract the actual payload. Two things going
480
- # on here. First of all, not all of the items may
481
- # be used. For example, if the payload length is
482
- # 4 bytes but the format string was HHH, the that
483
- # last 16 bit value is not wanted, so we should
484
- # discard it. Second thing is that the signed and
485
- # unsigned rational datatypes effectively have twice
486
- # the number of values so we need to account for that.
487
- if dtype in [5, 10]:
488
- payload = payload[: 2 * nvalues]
489
- else:
490
- payload = payload[:nvalues]
491
-
492
- tags[tag] = {"dtype": dtype, "nvalues": nvalues, "payload": payload}
493
-
494
- return tags
495
-
496
- def _write_ifd(self, b, tags):
497
- """Write the IFD out to the UUIDBox. We will always write IFDs
498
- for 32-bit TIFFs, i.e. 12 byte tags, meaning just 4 bytes within
499
- the tag for the tag data
500
- """
501
-
502
- little_tiff_tag_length = 12
503
- max_tag_payload_length = 4
504
-
505
- # exclude any unwanted tags
506
- if self.exclude_tags is not None:
507
- for tag in self.exclude_tags:
508
- if tag in tags:
509
- tags.pop(tag)
510
-
511
- num_tags = len(tags)
512
- write_buffer = struct.pack("<H", num_tags)
513
- b.write(write_buffer)
514
-
515
- # Ok, so now we have the IFD main body, but following that we have
516
- # the tag payloads that cannot fit into 4 bytes.
517
-
518
- ifd_start_loc = b.tell()
519
- after_ifd_position = ifd_start_loc + num_tags * little_tiff_tag_length
520
-
521
- for idx, tag in enumerate(tags):
522
-
523
- tag_offset = ifd_start_loc + idx * little_tiff_tag_length
524
- self.logger.debug(f"tag #: {tag}, writing to {tag_offset}")
525
- self.logger.debug(f"tag #: {tag}, after IFD {after_ifd_position}")
526
-
527
- b.seek(tag_offset)
528
-
529
- dtype = tags[tag]["dtype"]
530
- nvalues = tags[tag]["nvalues"]
531
- payload = tags[tag]["payload"]
532
-
533
- payload_length = DATATYPE2FMT[dtype]["nbytes"] * nvalues
534
-
535
- if payload_length > max_tag_payload_length:
536
- # the payload does not fit into the tag entry
537
-
538
- # read the payload from the TIFF
539
- payload_format = DATATYPE2FMT[dtype]["format"] * nvalues
540
-
541
- # write the tag entry to the UUID
542
- new_offset = after_ifd_position
543
- buffer = struct.pack("<HHII", tag, dtype, nvalues, new_offset)
544
- b.write(buffer)
545
-
546
- # now write the payload at the outlying position and then come
547
- # back to the same position in the file stream
548
- cpos = b.tell()
549
- b.seek(new_offset)
550
-
551
- format = "<" + DATATYPE2FMT[dtype]["format"] * nvalues
552
- buffer = struct.pack(format, *payload)
553
- b.write(buffer)
554
-
555
- # keep track of the next position to write out-of-IFD data
556
- after_ifd_position = b.tell()
557
- b.seek(cpos)
558
-
559
- else:
560
-
561
- # the payload DOES fit into the TIFF tag entry
562
- # write the tag metadata
563
- buffer = struct.pack("<HHI", tag, dtype, nvalues)
564
- b.write(buffer)
565
-
566
- payload_format = DATATYPE2FMT[dtype]["format"] * nvalues
567
-
568
- # we may need to alter the output format
569
- if payload_format in ["H", "B", "I"]:
570
- # just write it as an integer
571
- payload_format = "I"
572
-
573
- if tag == 34665:
574
- # special case for an EXIF IFD
575
- buffer = struct.pack("<I", after_ifd_position)
576
- b.write(buffer)
577
- b.seek(after_ifd_position)
578
- after_ifd_position = self._write_ifd(b, payload)
579
-
580
- else:
581
- # write a normal tag
582
- buffer = struct.pack("<" + payload_format, *payload)
583
- b.write(buffer)
584
-
585
- return after_ifd_position
586
-
587
- def read_tiff_header(self, tfp):
588
- """Get the endian-ness of the TIFF, seek to the main IFD"""
589
-
590
- buffer = tfp.read(4)
591
- data = struct.unpack("BB", buffer[:2])
592
-
593
- # big endian or little endian?
594
- if data[0] == 73 and data[1] == 73:
595
- # little endian
596
- self.endian = "<"
597
- elif data[0] == 77 and data[1] == 77:
598
- # big endian
599
- self.endian = ">"
600
- # no other option is possible, libtiff.open would have errored out
601
- # else:
602
- # msg = (
603
- # f"The byte order indication in the TIFF header "
604
- # f"({data}) is invalid. It should be either "
605
- # f"{bytes([73, 73])} or {bytes([77, 77])}."
606
- # )
607
- # raise RuntimeError(msg)
608
-
609
- # version number and offset to the first IFD
610
- (version,) = struct.unpack(self.endian + "H", buffer[2:4])
611
- self.version = _TIFF if version == 42 else _BIGTIFF
612
-
613
- if self.version == _BIGTIFF:
614
- buffer = tfp.read(12)
615
- _, _, offset = struct.unpack(self.endian + "HHQ", buffer)
616
- else:
617
- buffer = tfp.read(4)
618
- (offset,) = struct.unpack(self.endian + "I", buffer)
619
- tfp.seek(offset)
620
-
621
290
  def get_tag_value(self, tagnum):
622
291
  """Return the value associated with the tag. Some tags are not
623
292
  actually written into the IFD, but are instead "defaulted".
@@ -703,7 +372,7 @@ class Tiff2Jp2k(object):
703
372
  shape = (self.imageheight, self.imagewidth, self.spp)
704
373
 
705
374
  self.jp2 = Jp2k(
706
- self.jp2_filename,
375
+ self.jp2_path,
707
376
  shape=shape,
708
377
  tilesize=self.tilesize,
709
378
  **self.jp2_kwargs
glymur/version.py CHANGED
@@ -20,7 +20,7 @@ from .lib import tiff
20
20
 
21
21
  # Do not change the format of this next line! Doing so risks breaking
22
22
  # setup.py
23
- version = "0.13.8"
23
+ version = "0.14.0post1"
24
24
 
25
25
  version_tuple = parse(version).release
26
26
 
@@ -1,12 +1,11 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: Glymur
3
- Version: 0.13.8
3
+ Version: 0.14.0.post1
4
4
  Home-page: https://github.com/quintusdias/glymur
5
5
  Author: 'John Evans'
6
6
  Author-email: "John Evans" <jevans667cc@proton.me>
7
7
  License: 'MIT'
8
8
  Classifier: Programming Language :: Python
9
- Classifier: Programming Language :: Python :: 3.10
10
9
  Classifier: Programming Language :: Python :: 3.11
11
10
  Classifier: Programming Language :: Python :: 3.12
12
11
  Classifier: Programming Language :: Python :: 3.13
@@ -20,11 +19,13 @@ Description-Content-Type: text/markdown
20
19
  License-File: LICENSE.txt
21
20
  Requires-Dist: numpy
22
21
  Requires-Dist: lxml
22
+ Requires-Dist: imageio
23
23
  Requires-Dist: packaging
24
24
  Provides-Extra: test
25
25
  Requires-Dist: pytest; extra == "test"
26
26
  Requires-Dist: pillow; extra == "test"
27
27
  Requires-Dist: scikit-image; extra == "test"
28
+ Dynamic: license-file
28
29
 
29
30
 
30
31
  **glymur** contains a Python interface to the OpenJPEG library which
@@ -0,0 +1,27 @@
1
+ glymur/__init__.py,sha256=8kFoLkxAFhVEsgR0WCEaF0iXE5GZSp47nPlheGMpP-c,625
2
+ glymur/_core_converter.py,sha256=sfb0EOjSY2RFI4qhmz5t2UlsP68pibcyCieJTAMMFRc,13012
3
+ glymur/_iccprofile.py,sha256=v0nOhJuZsKViBUYCf8TWVJvs1k0vC9PGYdbkEIfGuI4,4156
4
+ glymur/codestream.py,sha256=wzRI8S5dlNfg6RqrSV7r5a4Rr2cDfk0n7CvytonBmHk,62680
5
+ glymur/command_line.py,sha256=3Wngx3wfAvP2PEf4-XRbmm43Bz8zywIL3Gd-6k-wMvY,11485
6
+ glymur/config.py,sha256=lVunNA-A475BX27L_qmrec_lm1InzHuL4_jkG8v_1FA,4140
7
+ glymur/core.py,sha256=O07TfaRW2YmurkFMiurl0DkDSGB0slDAAzP83K1HPFA,3613
8
+ glymur/jp2box.py,sha256=eSu9D_Lisawp4Z3UOxNLGVjDgTTn59s_XNkqTFYOg9Y,113829
9
+ glymur/jp2k.py,sha256=TmlfUsrRGcTD8gh-CxEUdc65tCSo2s0MGXzWShb01BQ,53888
10
+ glymur/jp2kr.py,sha256=DK4AQSc_30C1ZDAnxZubmZ6HBE1OwFj3VKpRg48wkVw,33143
11
+ glymur/jpeg.py,sha256=J8BBcQnVd9EVKlLE8f1uhOhHc9RiDJZkw5-Ul1UJr4Q,5507
12
+ glymur/options.py,sha256=TZApl6r_qCERHSIcTdM0iGvYuQLrZMbOtyFJB7XkvK0,4413
13
+ glymur/tiff.py,sha256=5oBeNwaMgojb0mfZJpk86WYHdrR04QRdfW2QDX1I7CU,29550
14
+ glymur/version.py,sha256=BhHULLp19YuFJ3c4C_vJcgRJbihjEzIHuIdAXAA9j2U,986
15
+ glymur/data/__init__.py,sha256=n2KZrHV15it7Wu4YCaBLXui1ZleQ30dnZ92dyP6q05k,955
16
+ glymur/data/goodstuff.j2k,sha256=xKQG68KMu33gYjRUDTQvam1Cue2tdio85rNp5J-rYZE,115220
17
+ glymur/data/heliov.jpx,sha256=KXnYdBZgl25jcGLu-m-QfhuP9pqUXV0Hp9HHEdJqr34,1399071
18
+ glymur/data/nemo.jp2,sha256=yJ1NkTEwU0B_gBtAiA1c5hxtGYSJtJgq6cHC2IHpj70,1132373
19
+ glymur/lib/__init__.py,sha256=JnM9oPfcZhBDLKo7_yLS-lIRQ1wXb1N9hKKQ-G7vYVk,127
20
+ glymur/lib/openjp2.py,sha256=0UWPp2mto8G43yRUhGfpcS1RV6l3ac1YQrlVyBhxvjs,44064
21
+ glymur/lib/tiff.py,sha256=Kf9VK7jD82SdbYVqOAOM4mQNfL2e8CHijls9Ks4gNdM,53336
22
+ glymur-0.14.0.post1.dist-info/licenses/LICENSE.txt,sha256=G9pvBgkJdPTtZqQmoRyIgAydtic1ZwWtOWBea9VMW7I,1077
23
+ glymur-0.14.0.post1.dist-info/METADATA,sha256=orxhgTmLjn6E0imR3O40ZZzp_evCDk2UV2ZnP3ehArU,1114
24
+ glymur-0.14.0.post1.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
25
+ glymur-0.14.0.post1.dist-info/entry_points.txt,sha256=v_9O2V_6M5ir6_nYmtkpgY9QvN1H-CMVg6tKqcUN4v0,133
26
+ glymur-0.14.0.post1.dist-info/top_level.txt,sha256=D0SvtBUoPxOs40OTRW3l-kjGFHM6VrXS8yZPK5Fx2wY,7
27
+ glymur-0.14.0.post1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (77.0.3)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,3 +1,4 @@
1
1
  [console_scripts]
2
2
  jp2dump = glymur.command_line:main
3
+ jpeg2jp2 = glymur.command_line:jpeg2jp2
3
4
  tiff2jp2 = glymur.command_line:tiff2jp2
@@ -1,25 +0,0 @@
1
- glymur/__init__.py,sha256=k14IfdaYuTWXSpAIDR3LVDtXt9XKjr-ZSNXCyu8pQko,586
2
- glymur/_iccprofile.py,sha256=v0nOhJuZsKViBUYCf8TWVJvs1k0vC9PGYdbkEIfGuI4,4156
3
- glymur/codestream.py,sha256=wzRI8S5dlNfg6RqrSV7r5a4Rr2cDfk0n7CvytonBmHk,62680
4
- glymur/command_line.py,sha256=jm-6dD2jcU_G7mJAJ0U5sanfG9kRy-j0-G3eSN_Ieek,7476
5
- glymur/config.py,sha256=lVunNA-A475BX27L_qmrec_lm1InzHuL4_jkG8v_1FA,4140
6
- glymur/core.py,sha256=O07TfaRW2YmurkFMiurl0DkDSGB0slDAAzP83K1HPFA,3613
7
- glymur/jp2box.py,sha256=qd__DSllhzvv3YdJ6jCEHyPWtqLoUUIdmZ5h9WTH0M8,113345
8
- glymur/jp2k.py,sha256=TmlfUsrRGcTD8gh-CxEUdc65tCSo2s0MGXzWShb01BQ,53888
9
- glymur/jp2kr.py,sha256=DK4AQSc_30C1ZDAnxZubmZ6HBE1OwFj3VKpRg48wkVw,33143
10
- glymur/options.py,sha256=TZApl6r_qCERHSIcTdM0iGvYuQLrZMbOtyFJB7XkvK0,4413
11
- glymur/tiff.py,sha256=O7vodg--mEPHM2PQzb1ZnBTwQO7RfEgB4SqZM5ftuOo,41153
12
- glymur/version.py,sha256=COjDoXQsY65BVg7DEFu2PXfyDUw6PDOoZEVk4MDpeBs,981
13
- glymur/data/__init__.py,sha256=n2KZrHV15it7Wu4YCaBLXui1ZleQ30dnZ92dyP6q05k,955
14
- glymur/data/goodstuff.j2k,sha256=xKQG68KMu33gYjRUDTQvam1Cue2tdio85rNp5J-rYZE,115220
15
- glymur/data/heliov.jpx,sha256=KXnYdBZgl25jcGLu-m-QfhuP9pqUXV0Hp9HHEdJqr34,1399071
16
- glymur/data/nemo.jp2,sha256=yJ1NkTEwU0B_gBtAiA1c5hxtGYSJtJgq6cHC2IHpj70,1132373
17
- glymur/lib/__init__.py,sha256=JnM9oPfcZhBDLKo7_yLS-lIRQ1wXb1N9hKKQ-G7vYVk,127
18
- glymur/lib/openjp2.py,sha256=0UWPp2mto8G43yRUhGfpcS1RV6l3ac1YQrlVyBhxvjs,44064
19
- glymur/lib/tiff.py,sha256=75acs7v_CsfhQL7xWtnMa8zllrOkFeXZG8vmvfYDIRs,50564
20
- Glymur-0.13.8.dist-info/LICENSE.txt,sha256=G9pvBgkJdPTtZqQmoRyIgAydtic1ZwWtOWBea9VMW7I,1077
21
- Glymur-0.13.8.dist-info/METADATA,sha256=9qiTUBH6lEqByyQISEfJZpqt6_xNWu4i_d6Q5tt_fSg,1114
22
- Glymur-0.13.8.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
23
- Glymur-0.13.8.dist-info/entry_points.txt,sha256=inzxpDbDDfIxtdXpCncAHdAdwJfjtXt3xKvIOsuZsG8,93
24
- Glymur-0.13.8.dist-info/top_level.txt,sha256=D0SvtBUoPxOs40OTRW3l-kjGFHM6VrXS8yZPK5Fx2wY,7
25
- Glymur-0.13.8.dist-info/RECORD,,