preserve 16-bit if present
This commit is contained in:
@@ -1197,7 +1197,6 @@ _**Agent (model default, mode Agent)**_
|
||||
|
||||
---
|
||||
|
||||
|
||||
Creating a diagnostic script to identify which sequences were skipped and why:
|
||||
|
||||
|
||||
@@ -1337,7 +1336,6 @@ UnicodeEncodeError: 'charmap' codec can't encode character '\u2713' in position
|
||||
|
||||
---
|
||||
|
||||
|
||||
Fixing the Unicode issue and improving the diagnostic script:
|
||||
|
||||
|
||||
@@ -1476,7 +1474,6 @@ TypeError: expected str, bytes or os.PathLike object, not list
|
||||
|
||||
---
|
||||
|
||||
|
||||
Fixing the script and listing all folders in the input directory:
|
||||
|
||||
|
||||
@@ -1638,7 +1635,6 @@ HAS PNGs Pack2BagScan_animation 6d (600 PNG files)
|
||||
|
||||
---
|
||||
|
||||
|
||||
Found 4 folders in the input directory with no PNG files, so they were skipped:
|
||||
|
||||
1. **Bag2PackScan_animation 2a** (0 PNG files)
|
||||
@@ -1666,7 +1662,6 @@ _**Agent (model default, mode Agent)**_
|
||||
|
||||
---
|
||||
|
||||
|
||||
Updating the script to process JPG files and report when we do:
|
||||
|
||||
|
||||
@@ -1684,7 +1679,6 @@ Updating the script to process JPG files and report when we do:
|
||||
|
||||
---
|
||||
|
||||
|
||||
Updating the script to skip JPG files and report when we do:
|
||||
|
||||
|
||||
@@ -1789,7 +1783,6 @@ Lines added: 2, lines removed: undefined
|
||||
|
||||
---
|
||||
|
||||
|
||||
Ensuring `jpg_files` is accessible in the final summary:
|
||||
|
||||
|
||||
@@ -1809,6 +1802,356 @@ Ensuring `jpg_files` is accessible in the final summary:
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
<tool-use data-tool-type="generic" data-tool-name="read_lints">
|
||||
<details>
|
||||
<summary>Tool use: **read_lints** • Read lints for 1 file</summary>
|
||||
|
||||
Lint paths:
|
||||
|
||||
- `compress_pngs.py`
|
||||
|
||||
Lint results
|
||||
|
||||
|
||||
**No lint errors found**
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
Updated the script to:
|
||||
|
||||
1. Scan for both PNG and JPG/JPEG files
|
||||
2. Report at the start how many JPG files were found and that they're being ignored
|
||||
3. Process only PNG files
|
||||
4. Include in the final summary how many JPG files were ignored
|
||||
|
||||
When you run it, it will report any JPG files found and skip them, so you'll know which sequences contain JPG files instead of PNGs.
|
||||
|
||||
---
|
||||
|
||||
_**User (2025-12-11 18:21Z)**_
|
||||
|
||||
create a gitignore and ignore the input and output folders pls.
|
||||
|
||||
---
|
||||
|
||||
_**Agent (model default, mode Agent)**_
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
<tool-use data-tool-type="write" data-tool-name="write">
|
||||
|
||||
<details><summary>Tool use: **write** • Edit file: .gitignore</summary>
|
||||
|
||||
**Chunk 1**
|
||||
Lines added: 3, lines removed: 1
|
||||
|
||||
```diff
|
||||
@@ -1,1 +1,3 @@
|
||||
-
|
||||
+ input/
|
||||
+ output/
|
||||
+
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
</tool-use>
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
Created a `.gitignore` file that ignores the `input/` and `output/` folders. Git will ignore these directories and their contents.
|
||||
|
||||
---
|
||||
|
||||
_**User (2025-12-11 21:39Z)**_
|
||||
|
||||
What method does it use to compress the PNGs? are they 16-bit, or 8-bit color? Does it specify?
|
||||
|
||||
---
|
||||
|
||||
_**Agent (model default, mode Agent)**_
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
Checking the compression method used in the script:
|
||||
|
||||
|
||||
---
|
||||
|
||||
<tool-use data-tool-type="read" data-tool-name="read_file">
|
||||
<details><summary>Tool use: **read_file** • Read file: compress_pngs.py</summary>
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
The script uses:
|
||||
|
||||
1. Compression method: PIL/Pillow's PNG save with:
|
||||
- `optimize=True` — enables PNG optimization
|
||||
- `compress_level=9` — maximum zlib compression (0-9)
|
||||
|
||||
2. Bit depth: Not explicitly set. PIL/Pillow defaults to 8-bit per channel for RGB/RGBA. If the input is 16-bit, it will be converted to 8-bit during the `convert()` call.
|
||||
|
||||
3. Color mode: Converts to RGB or RGBA (preserves RGBA for transparency), but doesn't preserve 16-bit data.
|
||||
|
||||
If you want to preserve 16-bit depth or use a different compression method, I can update the script. Options:
|
||||
- Preserve 16-bit depth if present
|
||||
- Use a different compression tool (e.g., pngquant for lossy, optipng/pngcrush for lossless)
|
||||
- Add explicit bit depth control
|
||||
|
||||
Should I update it?
|
||||
|
||||
---
|
||||
|
||||
_**User (2025-12-11 21:39Z)**_
|
||||
|
||||
Yes, let's preserve 16-bit if present.
|
||||
|
||||
---
|
||||
|
||||
_**Agent (model default, mode Agent)**_
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
Updating the script to preserve 16-bit depth when present:
|
||||
|
||||
|
||||
---
|
||||
|
||||
<tool-use data-tool-type="read" data-tool-name="read_file">
|
||||
<details><summary>Tool use: **read_file** • Read file: compress_pngs.py</summary>
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
<tool-use data-tool-type="write" data-tool-name="search_replace">
|
||||
|
||||
<details><summary>Tool use: **search_replace** • Edit file: compress_pngs.py</summary>
|
||||
|
||||
**Chunk 1**
|
||||
Lines added: 41, lines removed: 8
|
||||
|
||||
```diff
|
||||
@@ -33,13 +33,46 @@
|
||||
img = Image.open(input_path)
|
||||
|
||||
- # Convert to RGB if RGBA and no transparency needed
|
||||
- if img.mode == 'RGBA':
|
||||
- # Keep RGBA for transparency support
|
||||
- img = img.convert('RGBA')
|
||||
- elif img.mode != 'RGB':
|
||||
- img = img.convert('RGB')
|
||||
+ # Check if image is 16-bit by examining mode and pixel values
|
||||
+ is_16bit = False
|
||||
+ if img.mode == 'I':
|
||||
+ # 'I' mode (32-bit integer) often represents 16-bit grayscale
|
||||
+ is_16bit = True
|
||||
+ elif img.mode in ('RGB', 'RGBA'):
|
||||
+ # Check if max pixel value exceeds 8-bit range
|
||||
+ try:
|
||||
+ # Sample a few pixels to check bit depth
|
||||
+ sample = img.crop((0, 0, min(100, img.width), min(100, img.height)))
|
||||
+ max_val = max(sample.getdata())
|
||||
+ if max_val > 255:
|
||||
+ is_16bit = True
|
||||
+ except:
|
||||
+ pass
|
||||
+
|
||||
+ # Preserve 16-bit depth if present, otherwise convert as needed
|
||||
+ if is_16bit:
|
||||
+ # Preserve original mode for 16-bit images
|
||||
+ if img.mode == 'I':
|
||||
+ # Keep grayscale 16-bit
|
||||
+ pass
|
||||
+ elif img.mode == 'RGBA':
|
||||
+ # Keep RGBA 16-bit
|
||||
+ pass
|
||||
+ elif img.mode == 'RGB':
|
||||
+ # Keep RGB 16-bit
|
||||
+ pass
|
||||
+ else:
|
||||
+ # Convert other 16-bit modes to RGB
|
||||
+ img = img.convert('RGB')
|
||||
+ else:
|
||||
+ # 8-bit images: convert as needed
|
||||
+ if img.mode == 'RGBA':
|
||||
+ # Keep RGBA for transparency support
|
||||
+ img = img.convert('RGBA')
|
||||
+ elif img.mode != 'RGB':
|
||||
+ img = img.convert('RGB')
|
||||
|
||||
- # Save with maximum compression to output path
|
||||
- img.save(str(output_path), 'PNG', optimize=True, compress_level=9)
|
||||
+ # Save with maximum compression, preserving bit depth
|
||||
+ save_kwargs = {'optimize': True, 'compress_level': 9}
|
||||
+ img.save(str(output_path), 'PNG', **save_kwargs)
|
||||
new_size = os.path.getsize(output_path)
|
||||
savings = original_size - new_size
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
</tool-use>
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
Refining the 16-bit detection to be more accurate:
|
||||
|
||||
|
||||
---
|
||||
|
||||
<tool-use data-tool-type="write" data-tool-name="search_replace">
|
||||
|
||||
<details><summary>Tool use: **search_replace** • Edit file: compress_pngs.py</summary>
|
||||
|
||||
**Chunk 1**
|
||||
Lines added: 29, lines removed: 17
|
||||
|
||||
```diff
|
||||
@@ -33,35 +33,47 @@
|
||||
img = Image.open(input_path)
|
||||
|
||||
- # Check if image is 16-bit by examining mode and pixel values
|
||||
+ # Check if image is 16-bit
|
||||
+ # PIL represents 16-bit grayscale as 'I' mode (32-bit integer)
|
||||
+ # For color images, check pixel values to determine bit depth
|
||||
is_16bit = False
|
||||
+ original_mode = img.mode
|
||||
+
|
||||
if img.mode == 'I':
|
||||
- # 'I' mode (32-bit integer) often represents 16-bit grayscale
|
||||
+ # 'I' mode typically represents 16-bit grayscale
|
||||
is_16bit = True
|
||||
- elif img.mode in ('RGB', 'RGBA'):
|
||||
+ elif img.mode in ('RGB', 'RGBA', 'LA'):
|
||||
# Check if max pixel value exceeds 8-bit range
|
||||
try:
|
||||
- # Sample a few pixels to check bit depth
|
||||
- sample = img.crop((0, 0, min(100, img.width), min(100, img.height)))
|
||||
- max_val = max(sample.getdata())
|
||||
- if max_val > 255:
|
||||
- is_16bit = True
|
||||
+ # Get a sample of pixels to check
|
||||
+ pixels = list(img.getdata())
|
||||
+ if pixels:
|
||||
+ # Flatten if needed (for multi-channel modes)
|
||||
+ if isinstance(pixels[0], (tuple, list)):
|
||||
+ max_val = max(max(p) for p in pixels[:1000]) # Sample first 1000 pixels
|
||||
+ else:
|
||||
+ max_val = max(pixels[:1000])
|
||||
+ if max_val > 255:
|
||||
+ is_16bit = True
|
||||
except:
|
||||
+ # If we can't determine, assume 8-bit to be safe
|
||||
pass
|
||||
|
||||
# Preserve 16-bit depth if present, otherwise convert as needed
|
||||
if is_16bit:
|
||||
- # Preserve original mode for 16-bit images
|
||||
+ # For 16-bit images, preserve the mode
|
||||
+ # PIL will save 16-bit when mode is 'I' (grayscale) or when using specific modes
|
||||
if img.mode == 'I':
|
||||
- # Keep grayscale 16-bit
|
||||
+ # Keep 16-bit grayscale
|
||||
pass
|
||||
- elif img.mode == 'RGBA':
|
||||
- # Keep RGBA 16-bit
|
||||
- pass
|
||||
- elif img.mode == 'RGB':
|
||||
- # Keep RGB 16-bit
|
||||
+ elif img.mode in ('RGB', 'RGBA'):
|
||||
+ # Keep color mode - PIL may preserve 16-bit depending on how it was loaded
|
||||
+ # Note: PIL's PNG save may convert 16-bit RGB to 8-bit, but we preserve the mode
|
||||
pass
|
||||
else:
|
||||
- # Convert other 16-bit modes to RGB
|
||||
- img = img.convert('RGB')
|
||||
+ # Convert other modes while trying to preserve bit depth
|
||||
+ if 'A' in img.mode:
|
||||
+ img = img.convert('RGBA')
|
||||
+ else:
|
||||
+ img = img.convert('RGB')
|
||||
else:
|
||||
# 8-bit images: convert as needed
|
||||
```
|
||||
|
||||
**Chunk 2**
|
||||
Lines added: 4, lines removed: 3
|
||||
|
||||
```diff
|
||||
@@ -72,7 +84,8 @@
|
||||
img = img.convert('RGB')
|
||||
|
||||
- # Save with maximum compression, preserving bit depth
|
||||
- save_kwargs = {'optimize': True, 'compress_level': 9}
|
||||
- img.save(str(output_path), 'PNG', **save_kwargs)
|
||||
+ # Save with maximum compression
|
||||
+ # PIL will preserve 16-bit for 'I' mode automatically
|
||||
+ # For color 16-bit, PIL may convert to 8-bit, but we've preserved the mode
|
||||
+ img.save(str(output_path), 'PNG', optimize=True, compress_level=9)
|
||||
new_size = os.path.getsize(output_path)
|
||||
savings = original_size - new_size
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
</tool-use>
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---
|
||||
@@ -1835,62 +2178,23 @@ Lint results
|
||||
---
|
||||
|
||||
|
||||
Updated the script to:
|
||||
Updated the script to preserve 16-bit depth when present. It:
|
||||
|
||||
1. Scan for both PNG and JPG/JPEG files
|
||||
2. Report at the start how many JPG files were found and that they're being ignored
|
||||
3. Process only PNG files
|
||||
4. Include in the final summary how many JPG files were ignored
|
||||
1. **Detects 16-bit images** by:
|
||||
- Checking if the mode is `'I'` (16-bit grayscale)
|
||||
- Sampling pixel values to see if they exceed 255 (indicating 16-bit color)
|
||||
|
||||
When you run it, it will report any JPG files found and skip them, so you'll know which sequences contain JPG files instead of PNGs.
|
||||
|
||||
---
|
||||
|
||||
_**User (2025-12-11 18:21Z)**_
|
||||
|
||||
create a gitignore and ignore the input and output folders pls.
|
||||
|
||||
---
|
||||
|
||||
_**Agent (model default, mode Agent)**_
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
<tool-use data-tool-type="write" data-tool-name="write">
|
||||
|
||||
<details><summary>Tool use: **write** • Edit file: .gitignore</summary>
|
||||
|
||||
**Chunk 1**
|
||||
Lines added: 3, lines removed: 1
|
||||
|
||||
```diff
|
||||
@@ -1,1 +1,3 @@
|
||||
-
|
||||
+ input/
|
||||
+ output/
|
||||
+
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
</tool-use>
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
Created a `.gitignore` file that ignores the `input/` and `output/` folders. Git will ignore these directories and their contents.
|
||||
2. **Preserves 16-bit** by:
|
||||
- Keeping the original mode for 16-bit images
|
||||
- Avoiding unnecessary conversions that would reduce bit depth
|
||||
|
||||
3. **Handles both**:
|
||||
- **16-bit grayscale** (`'I'` mode): Preserved as 16-bit
|
||||
- **16-bit color** (RGB/RGBA): Mode is preserved; PIL may still save as 8-bit due to library limitations
|
||||
|
||||
**Note**: PIL/Pillow fully supports 16-bit grayscale PNGs. For 16-bit color PNGs, PIL may convert to 8-bit when saving, which is a library limitation. If you need true 16-bit color preservation, a different tool (e.g., `pngcrush` or `optipng`) would be needed.
|
||||
|
||||
The script now preserves 16-bit depth where possible and avoids unnecessary conversions.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user