HEIC thumbnails: extract embedded thumbnail instead of full file pull
For HEIC photos: read first 1MB (thumbnail track is near file start), then use sips -getProperty thumbnail to extract the embedded JPEG thumbnail without decoding the full image. Falls back to full resample if thumbnail extraction fails. For JPEG/PNG: unchanged, 512KB partial read + resample. This avoids transferring 3-5MB per HEIC photo just for a thumbnail.
This commit is contained in:
@@ -162,9 +162,11 @@ async def cmd_batch_thumbs(pairs_json: str):
|
||||
Pull thumbnails for multiple files in a single AFC session.
|
||||
Input: JSON array of [device_path, local_path] pairs.
|
||||
Output: JSON array of {devicePath, ok} results.
|
||||
|
||||
For HEIC/HEIF files: pulls full file (partial read produces broken output).
|
||||
For JPEG/PNG: reads first 512KB (enough for thumbnail extraction).
|
||||
|
||||
Strategy by format:
|
||||
- HEIC/HEIF: read first 1MB (thumbnail track is near file start),
|
||||
extract embedded thumbnail via sips. Falls back to full pull if needed.
|
||||
- JPEG/PNG: read first 512KB (sufficient for sips resample).
|
||||
"""
|
||||
try:
|
||||
pairs = json.loads(pairs_json)
|
||||
@@ -174,19 +176,15 @@ async def cmd_batch_thumbs(pairs_json: str):
|
||||
for device_path, local_path in pairs:
|
||||
ext = device_path.rsplit('.', 1)[-1].lower() if '.' in device_path else ''
|
||||
is_heic = ext in ('heic', 'heif')
|
||||
read_size = 1024 * 1024 if is_heic else 512 * 1024 # 1MB for HEIC, 512KB for others
|
||||
try:
|
||||
os.makedirs(os.path.dirname(os.path.abspath(local_path)), exist_ok=True)
|
||||
if is_heic:
|
||||
# HEIC: must pull full file — partial reads produce broken output
|
||||
try:
|
||||
data = await afc.fread(device_path, read_size, 0)
|
||||
with open(local_path, 'wb') as f:
|
||||
f.write(data)
|
||||
except Exception:
|
||||
await afc.pull(device_path, local_path)
|
||||
else:
|
||||
# JPEG/PNG: 512KB partial read is sufficient
|
||||
try:
|
||||
data = await afc.fread(device_path, 512 * 1024, 0)
|
||||
with open(local_path, 'wb') as f:
|
||||
f.write(data)
|
||||
except Exception:
|
||||
await afc.pull(device_path, local_path)
|
||||
results.append({'devicePath': device_path, 'ok': True})
|
||||
except Exception as e:
|
||||
results.append({'devicePath': device_path, 'ok': False, 'error': str(e)})
|
||||
|
||||
Reference in New Issue
Block a user