aboutsummaryrefslogtreecommitdiffstats
path: root/env/lib/python3.10/site-packages/pikepdf/models/_transcoding.py
diff options
context:
space:
mode:
Diffstat (limited to 'env/lib/python3.10/site-packages/pikepdf/models/_transcoding.py')
-rw-r--r--env/lib/python3.10/site-packages/pikepdf/models/_transcoding.py243
1 files changed, 0 insertions, 243 deletions
diff --git a/env/lib/python3.10/site-packages/pikepdf/models/_transcoding.py b/env/lib/python3.10/site-packages/pikepdf/models/_transcoding.py
deleted file mode 100644
index e54facf..0000000
--- a/env/lib/python3.10/site-packages/pikepdf/models/_transcoding.py
+++ /dev/null
@@ -1,243 +0,0 @@
-# SPDX-FileCopyrightText: 2022 James R. Barlow
-# SPDX-License-Identifier: MPL-2.0
-
-from __future__ import annotations
-
-import struct
-from typing import Any, Callable, NamedTuple, Union
-
-from PIL import Image
-from PIL.TiffTags import TAGS_V2 as TIFF_TAGS
-
-BytesLike = Union[bytes, memoryview]
-MutableBytesLike = Union[bytearray, memoryview]
-
-
-def _next_multiple(n: int, k: int) -> int:
- """Return the multiple of k that is greater than or equal n.
-
- >>> _next_multiple(101, 4)
- 104
- >>> _next_multiple(100, 4)
- 100
- """
- div, mod = divmod(n, k)
- if mod > 0:
- div += 1
- return div * k
-
-
-def unpack_subbyte_pixels(
- packed: BytesLike, size: tuple[int, int], bits: int, scale: int = 0
-) -> tuple[BytesLike, int]:
- """Unpack subbyte *bits* pixels into full bytes and rescale.
-
- When scale is 0, the appropriate scale is calculated.
- e.g. for 2-bit, the scale is adjusted so that
- 0b00 = 0.00 = 0x00
- 0b01 = 0.33 = 0x55
- 0b10 = 0.66 = 0xaa
- 0b11 = 1.00 = 0xff
- When scale is 1, no scaling is applied, appropriate when
- the bytes are palette indexes.
- """
- width, height = size
- bits_per_byte = 8 // bits
- stride = _next_multiple(width, bits_per_byte)
- buffer = bytearray(bits_per_byte * stride * height)
- max_read = len(buffer) // bits_per_byte
- if scale == 0:
- scale = 255 / ((2**bits) - 1)
- if bits == 4:
- _4bit_inner_loop(packed[:max_read], buffer, scale)
- elif bits == 2:
- _2bit_inner_loop(packed[:max_read], buffer, scale)
- # elif bits == 1:
- # _1bit_inner_loop(packed[:max_read], buffer, scale)
- else:
- raise NotImplementedError(bits)
- return memoryview(buffer), stride
-
-
-# def _1bit_inner_loop(in_: BytesLike, out: MutableBytesLike, scale: int) -> None:
-# """Unpack 1-bit values to their 8-bit equivalents.
-
-# Thus *out* must be 8x at long as *in*.
-# """
-# for n, val in enumerate(in_):
-# out[8 * n + 0] = int((val >> 7) & 0b1) * scale
-# out[8 * n + 1] = int((val >> 6) & 0b1) * scale
-# out[8 * n + 2] = int((val >> 5) & 0b1) * scale
-# out[8 * n + 3] = int((val >> 4) & 0b1) * scale
-# out[8 * n + 4] = int((val >> 3) & 0b1) * scale
-# out[8 * n + 5] = int((val >> 2) & 0b1) * scale
-# out[8 * n + 6] = int((val >> 1) & 0b1) * scale
-# out[8 * n + 7] = int((val >> 0) & 0b1) * scale
-
-
-def _2bit_inner_loop(in_: BytesLike, out: MutableBytesLike, scale: int) -> None:
- """Unpack 2-bit values to their 8-bit equivalents.
-
- Thus *out* must be 4x at long as *in*.
- """
- for n, val in enumerate(in_):
- out[4 * n] = int((val >> 6) * scale)
- out[4 * n + 1] = int(((val >> 4) & 0b11) * scale)
- out[4 * n + 2] = int(((val >> 2) & 0b11) * scale)
- out[4 * n + 3] = int((val & 0b11) * scale)
-
-
-def _4bit_inner_loop(in_: BytesLike, out: MutableBytesLike, scale: int) -> None:
- """Unpack 4-bit values to their 8-bit equivalents.
-
- Thus *out* must be 2x at long as *in*.
- """
- for n, val in enumerate(in_):
- out[2 * n] = int((val >> 4) * scale)
- out[2 * n + 1] = int((val & 0b1111) * scale)
-
-
-def image_from_byte_buffer(buffer: BytesLike, size: tuple[int, int], stride: int):
- """Use Pillow to create one-component image from a byte buffer.
-
- *stride* is the number of bytes per row, and is essential for packed bits
- with odd image widths.
- """
- ystep = 1 # image is top to bottom in memory
- return Image.frombuffer('L', size, buffer, "raw", 'L', stride, ystep)
-
-
-def _make_rgb_palette(gray_palette: bytes) -> bytes:
- palette = b''
- for entry in gray_palette:
- palette += bytes([entry]) * 3
- return palette
-
-
-def _depalettize_cmyk(buffer: BytesLike, palette: BytesLike):
- with memoryview(buffer) as mv:
- output = bytearray(4 * len(mv))
- for n, pal_idx in enumerate(mv):
- output[4 * n : 4 * (n + 1)] = palette[4 * pal_idx : 4 * (pal_idx + 1)]
- return output
-
-
-def image_from_buffer_and_palette(
- buffer: BytesLike,
- size: tuple[int, int],
- stride: int,
- base_mode: str,
- palette: BytesLike,
-) -> Image.Image:
- """Construct an image from a byte buffer and apply the palette.
-
- 1/2/4-bit images must be unpacked (no scaling!) to byte buffers first, such
- that every 8-bit integer is an index into the palette.
- """
- # Reminder Pillow palette byte order unintentionally changed in 8.3.0
- # https://github.com/python-pillow/Pillow/issues/5595
- # 8.2.0: all aligned by channel (very nonstandard)
- # 8.3.0: all channels for one color followed by the next color (e.g. RGBRGBRGB)
-
- if base_mode == 'RGB':
- im = image_from_byte_buffer(buffer, size, stride)
- im.putpalette(palette, rawmode=base_mode)
- elif base_mode == 'L':
- # Pillow does not fully support palettes with rawmode='L'.
- # Convert to RGB palette.
- gray_palette = _make_rgb_palette(palette)
- im = image_from_byte_buffer(buffer, size, stride)
- im.putpalette(gray_palette, rawmode='RGB')
- elif base_mode == 'CMYK':
- # Pillow does not support CMYK with palettes; convert manually
- output = _depalettize_cmyk(buffer, palette)
- im = Image.frombuffer('CMYK', size, data=output, decoder_name='raw')
- else:
- raise NotImplementedError(f'palette with {base_mode}')
- return im
-
-
-def fix_1bit_palette_image(
- im: Image.Image, base_mode: str, palette: BytesLike
-) -> Image.Image:
- """Apply palettes to 1-bit images."""
- im = im.convert('P')
- if base_mode == 'RGB' and len(palette) == 6:
- # rgbrgb -> rgb000000...rgb
- palette = palette[0:3] + (b'\x00\x00\x00' * (256 - 2)) + palette[3:6]
- im.putpalette(palette, rawmode='RGB')
- elif base_mode == 'L':
- try:
- im.putpalette(palette, rawmode='L')
- except ValueError as e:
- if 'unrecognized raw mode' in str(e):
- rgb_palette = _make_rgb_palette(palette)
- im.putpalette(rgb_palette, rawmode='RGB')
- return im
-
-
-def generate_ccitt_header(
- size: tuple[int, int],
- data_length: int,
- ccitt_group: int,
- photometry: int,
- icc: bytes,
-) -> bytes:
- """Generate binary CCITT header for image with given parameters."""
- tiff_header_struct = '<' + '2s' + 'H' + 'L' + 'H'
-
- tag_keys = {tag.name: key for key, tag in TIFF_TAGS.items()} # type: ignore
- ifd_struct = '<HHLL'
-
- class IFD(NamedTuple):
- key: int
- typecode: Any
- count_: int
- data: int | Callable[[], int | None]
-
- ifds: list[IFD] = []
-
- def header_length(ifd_count) -> int:
- return (
- struct.calcsize(tiff_header_struct)
- + struct.calcsize(ifd_struct) * ifd_count
- + 4
- )
-
- def add_ifd(tag_name: str, data: int | Callable[[], int | None], count: int = 1):
- key = tag_keys[tag_name]
- typecode = TIFF_TAGS[key].type # type: ignore
- ifds.append(IFD(key, typecode, count, data))
-
- image_offset = None
- width, height = size
- add_ifd('ImageWidth', width)
- add_ifd('ImageLength', height)
- add_ifd('BitsPerSample', 1)
- add_ifd('Compression', ccitt_group)
- add_ifd('PhotometricInterpretation', int(photometry))
- add_ifd('StripOffsets', lambda: image_offset)
- add_ifd('RowsPerStrip', height)
- add_ifd('StripByteCounts', data_length)
-
- icc_offset = 0
- if icc:
- add_ifd('ICCProfile', lambda: icc_offset, count=len(icc))
-
- icc_offset = header_length(len(ifds))
- image_offset = icc_offset + len(icc)
-
- ifd_args = [(arg() if callable(arg) else arg) for ifd in ifds for arg in ifd]
- tiff_header = struct.pack(
- (tiff_header_struct + ifd_struct[1:] * len(ifds) + 'L'),
- b'II', # Byte order indication: Little endian
- 42, # Version number (always 42)
- 8, # Offset to first IFD
- len(ifds), # Number of tags in IFD
- *ifd_args,
- 0, # Last IFD
- )
-
- if icc:
- tiff_header += icc
- return tiff_header