large-image-converter 1.29.7.dev20__py3-none-any.whl → 1.29.7.dev22__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.

Potentially problematic release.


This version of large-image-converter might be problematic. Click here for more details.

@@ -109,7 +109,7 @@ def _data_from_large_image(path, outputPath, **kwargs):
109
109
  _pool_add(tasks, (pool.submit(
110
110
  _convert_via_vips, img, savePath, outputPath, mime=mime, forTiled=False), ))
111
111
  results['images'][key] = savePath
112
- _drain_pool(pool, tasks)
112
+ _drain_pool(pool, tasks, 'associated images')
113
113
  return results
114
114
 
115
115
 
@@ -218,7 +218,7 @@ def _generate_multiframe_tiff(inputPath, outputPath, tempPath, lidata, **kwargs)
218
218
  _pool_add(tasks, (pool.submit(
219
219
  _convert_via_vips, subInputPath, savePath, tempPath, False), ))
220
220
  extraImages[key] = savePath
221
- _drain_pool(pool, tasks)
221
+ _drain_pool(pool, tasks, 'subpage')
222
222
  _output_tiff(outputList, outputPath, tempPath, lidata, extraImages, **kwargs)
223
223
 
224
224
 
@@ -349,7 +349,7 @@ def _concurrency_to_value(_concurrency=None, **kwargs):
349
349
  return max(1, large_image.config.cpu_count(logical=True) + _concurrency)
350
350
 
351
351
 
352
- def _get_thread_pool(memoryLimit=None, **kwargs):
352
+ def _get_thread_pool(memoryLimit=None, parentConcurrency=None, numItems=None, **kwargs):
353
353
  """
354
354
  Allocate a thread pool based on the specific concurrency.
355
355
 
@@ -357,12 +357,37 @@ def _get_thread_pool(memoryLimit=None, **kwargs):
357
357
  process per memoryLimit bytes of total memory.
358
358
  """
359
359
  concurrency = _concurrency_to_value(**kwargs)
360
+ if parentConcurrency and parentConcurrency > 1 and concurrency > 1:
361
+ concurrency = max(1, int(math.ceil(concurrency / parentConcurrency)))
360
362
  if memoryLimit:
363
+ if parentConcurrency:
364
+ memoryLimit *= parentConcurrency
361
365
  concurrency = min(concurrency, large_image.config.total_memory() // memoryLimit)
366
+ if numItems and numItems >= 1 and concurrency > numItems:
367
+ concurrency = numItems
362
368
  concurrency = max(1, concurrency)
363
369
  return concurrent.futures.ThreadPoolExecutor(max_workers=concurrency)
364
370
 
365
371
 
372
+ def _pool_log(left, total, label):
373
+ """
374
+ Log processing within a pool.
375
+
376
+ :param left: units left to process.
377
+ :param total: total units left to process.
378
+ :param label: label to log describing what is being processed.
379
+ """
380
+ if not hasattr(logger, '_pool_log_starttime'):
381
+ logger._pool_log_starttime = time.time()
382
+ if not hasattr(logger, '_pool_log_lastlog'):
383
+ logger._pool_log_lastlog = time.time()
384
+ if time.time() - logger._pool_log_lastlog < 10:
385
+ return
386
+ elapsed = time.time() - logger._pool_log_starttime
387
+ logger.debug('%d/%d %s left %4.2fs', left, total, label, elapsed)
388
+ logger._pool_log_lastlog = time.time()
389
+
390
+
366
391
  def _pool_add(tasks, newtask):
367
392
  """
368
393
  Add a new task to a pool, then drain any finished tasks at the start of the
@@ -381,7 +406,7 @@ def _pool_add(tasks, newtask):
381
406
  tasks.pop(0)
382
407
 
383
408
 
384
- def _drain_pool(pool, tasks):
409
+ def _drain_pool(pool, tasks, label=''):
385
410
  """
386
411
  Wait for all tasks in a pool to complete, then shutdown the pool.
387
412
 
@@ -389,6 +414,8 @@ def _drain_pool(pool, tasks):
389
414
  :param tasks: a list containing either lists or tuples, the last element
390
415
  of which is a task submitted to the pool. Altered.
391
416
  """
417
+ numtasks = len(tasks)
418
+ _pool_log(len(tasks), numtasks, label)
392
419
  while len(tasks):
393
420
  # This allows better stopping on a SIGTERM
394
421
  try:
@@ -396,6 +423,7 @@ def _drain_pool(pool, tasks):
396
423
  except concurrent.futures.TimeoutError:
397
424
  continue
398
425
  tasks.pop(0)
426
+ _pool_log(len(tasks), numtasks, label)
399
427
  pool.shutdown(False)
400
428
 
401
429
 
@@ -507,7 +535,8 @@ def _convert_large_image_tile(tilelock, strips, tile):
507
535
  strips[ty] = strips[ty].insert(vimg, x, 0, expand=True)
508
536
 
509
537
 
510
- def _convert_large_image_frame(frame, numFrames, ts, frameOutputPath, tempPath, **kwargs):
538
+ def _convert_large_image_frame(frame, numFrames, ts, frameOutputPath, tempPath,
539
+ parentConcurrency=None, **kwargs):
511
540
  """
512
541
  Convert a single frame from a large_image source. This parallelizes tile
513
542
  reads. Once all tiles are converted to a composited vips image, a tiff
@@ -518,18 +547,24 @@ def _convert_large_image_frame(frame, numFrames, ts, frameOutputPath, tempPath,
518
547
  :param ts: the open tile source.
519
548
  :param frameOutputPath: the destination name for the tiff file.
520
549
  :param tempPath: a temporary file in a temporary directory.
550
+ :param parentConcurrency: amount of concurrency used by parent task.
521
551
  """
522
552
  # The iterator tile size is a balance between memory use and fewer calls
523
553
  # and file handles.
524
554
  _iterTileSize = 4096
525
555
  logger.info('Processing frame %d/%d', frame + 1, numFrames)
526
556
  strips = []
527
- pool = _get_thread_pool(**kwargs)
557
+ pool = _get_thread_pool(
558
+ memoryLimit=FrameMemoryEstimate,
559
+ # allow multiple tiles even if we are using all the cores, as it
560
+ # balances I/O and computation
561
+ parentConcurrency=(parentConcurrency // 2),
562
+ **kwargs)
528
563
  tasks = []
529
564
  tilelock = threading.Lock()
530
565
  for tile in ts.tileIterator(tile_size=dict(width=_iterTileSize), frame=frame):
531
566
  _pool_add(tasks, (pool.submit(_convert_large_image_tile, tilelock, strips, tile), ))
532
- _drain_pool(pool, tasks)
567
+ _drain_pool(pool, tasks, f'tiles from frame {frame + 1}/{numFrames}')
533
568
  minbands = min(strip.bands for strip in strips)
534
569
  maxbands = max(strip.bands for strip in strips)
535
570
  if minbands != maxbands:
@@ -556,20 +591,21 @@ def _convert_large_image(inputPath, outputPath, tempPath, lidata, **kwargs):
556
591
  numFrames = len(lidata['metadata'].get('frames', [0]))
557
592
  outputList = []
558
593
  tasks = []
559
- pool = _get_thread_pool(memoryLimit=FrameMemoryEstimate, **kwargs)
560
594
  startFrame = 0
561
595
  endFrame = numFrames
562
596
  if kwargs.get('onlyFrame') is not None and str(kwargs.get('onlyFrame')):
563
597
  startFrame = int(kwargs.get('onlyFrame'))
564
598
  endFrame = startFrame + 1
599
+ pool = _get_thread_pool(memoryLimit=FrameMemoryEstimate,
600
+ numItems=endFrame - startFrame, **kwargs)
565
601
  for frame in range(startFrame, endFrame):
566
602
  frameOutputPath = tempPath + '-%d-%s.tiff' % (
567
603
  frame + 1, time.strftime('%Y%m%d-%H%M%S'))
568
604
  _pool_add(tasks, (pool.submit(
569
605
  _convert_large_image_frame, frame, numFrames, ts, frameOutputPath,
570
- tempPath, **kwargs), ))
606
+ tempPath, pool._max_workers, **kwargs), ))
571
607
  outputList.append(frameOutputPath)
572
- _drain_pool(pool, tasks)
608
+ _drain_pool(pool, tasks, 'frames')
573
609
  _output_tiff(outputList, outputPath, tempPath, lidata, **kwargs)
574
610
 
575
611
 
@@ -891,6 +927,7 @@ def convert(inputPath, outputPath=None, **kwargs): # noqa: C901
891
927
 
892
928
  :returns: outputPath if successful
893
929
  """
930
+ logger._pool_log_starttime = time.time()
894
931
  if kwargs.get('_concurrency'):
895
932
  os.environ['VIPS_CONCURRENCY'] = str(_concurrency_to_value(**kwargs))
896
933
  geospatial = kwargs.get('geospatial')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: large-image-converter
3
- Version: 1.29.7.dev20
3
+ Version: 1.29.7.dev22
4
4
  Summary: Converter for Large Image.
5
5
  Author: Kitware Inc
6
6
  Author-email: kitware@kitware.com
@@ -18,7 +18,7 @@ Classifier: Programming Language :: Python :: 3.12
18
18
  Requires-Python: >=3.8
19
19
  Description-Content-Type: text/x-rst
20
20
  License-File: LICENSE
21
- Requires-Dist: large-image-source-tiff >=1.29.7.dev20
21
+ Requires-Dist: large-image-source-tiff >=1.29.7.dev22
22
22
  Requires-Dist: numpy
23
23
  Requires-Dist: psutil
24
24
  Requires-Dist: pyvips
@@ -26,7 +26,7 @@ Requires-Dist: tifftools
26
26
  Provides-Extra: all
27
27
  Requires-Dist: glymur ; extra == 'all'
28
28
  Requires-Dist: gdal ; extra == 'all'
29
- Requires-Dist: large-image[sources] >=1.29.7.dev20 ; extra == 'all'
29
+ Requires-Dist: large-image[sources] >=1.29.7.dev22 ; extra == 'all'
30
30
  Requires-Dist: packaging ; extra == 'all'
31
31
  Requires-Dist: scikit-image ; extra == 'all'
32
32
  Provides-Extra: geospatial
@@ -34,7 +34,7 @@ Requires-Dist: gdal ; extra == 'geospatial'
34
34
  Provides-Extra: jp2k
35
35
  Requires-Dist: glymur ; extra == 'jp2k'
36
36
  Provides-Extra: sources
37
- Requires-Dist: large-image[sources] >=1.29.7.dev20 ; extra == 'sources'
37
+ Requires-Dist: large-image[sources] >=1.29.7.dev22 ; extra == 'sources'
38
38
  Provides-Extra: stats
39
39
  Requires-Dist: packaging ; extra == 'stats'
40
40
  Requires-Dist: scikit-image ; extra == 'stats'
@@ -0,0 +1,9 @@
1
+ large_image_converter/__init__.py,sha256=_ixZBvfS3K_jOh2T98o37EF8jjZLrpNTw-ZXkW9r--w,41181
2
+ large_image_converter/__main__.py,sha256=bGQaCR01kTGTnW2c2Z9z5BIiPSpCRPfj7_kPgppLeB4,13353
3
+ large_image_converter/format_aperio.py,sha256=NkKY3gaSjPlfxvcTQgFiMADdq_mkdpKjGQ7WT_QsvaM,11761
4
+ large_image_converter-1.29.7.dev22.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
5
+ large_image_converter-1.29.7.dev22.dist-info/METADATA,sha256=R1FzqzhSNe5RQoNZmGdG4uS_RKrwgTXMYNaWLhxqIvA,4646
6
+ large_image_converter-1.29.7.dev22.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
7
+ large_image_converter-1.29.7.dev22.dist-info/entry_points.txt,sha256=TkXGWAaHgquk_ZXfqHTjQLjv8RZriv6ioiJd7JL6UIs,78
8
+ large_image_converter-1.29.7.dev22.dist-info/top_level.txt,sha256=cdRa-ZWWKzVHFsjK1Aq1f4bzAMPc3sgCpprmvpYczKg,22
9
+ large_image_converter-1.29.7.dev22.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- large_image_converter/__init__.py,sha256=tc_3t6OixaMdfSlwMMFLjQ3uuC8HZm7atoUbHU6UcHM,39472
2
- large_image_converter/__main__.py,sha256=bGQaCR01kTGTnW2c2Z9z5BIiPSpCRPfj7_kPgppLeB4,13353
3
- large_image_converter/format_aperio.py,sha256=NkKY3gaSjPlfxvcTQgFiMADdq_mkdpKjGQ7WT_QsvaM,11761
4
- large_image_converter-1.29.7.dev20.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
5
- large_image_converter-1.29.7.dev20.dist-info/METADATA,sha256=7T_cm4MpoP1B10gzPklBAtY-2Rtt-MKRrtEfHUhIT5w,4646
6
- large_image_converter-1.29.7.dev20.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
7
- large_image_converter-1.29.7.dev20.dist-info/entry_points.txt,sha256=TkXGWAaHgquk_ZXfqHTjQLjv8RZriv6ioiJd7JL6UIs,78
8
- large_image_converter-1.29.7.dev20.dist-info/top_level.txt,sha256=cdRa-ZWWKzVHFsjK1Aq1f4bzAMPc3sgCpprmvpYczKg,22
9
- large_image_converter-1.29.7.dev20.dist-info/RECORD,,