pyimagecuda 0.0.1__cp313-cp313-win_amd64.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 pyimagecuda might be problematic. Click here for more details.

@@ -0,0 +1,60 @@
1
+ import ctypes
2
+ import sys
3
+
4
+ def _check_nvidia_driver():
5
+ try:
6
+ ctypes.windll.LoadLibrary("nvcuda.dll")
7
+ return True
8
+ except OSError:
9
+ return False
10
+
11
+ _INTERNAL_LOADED = False
12
+
13
+ try:
14
+ from . import pyimagecuda_internal
15
+ _INTERNAL_LOADED = True
16
+ except ImportError as e:
17
+ _INTERNAL_LOADED = False
18
+ error_msg = str(e).lower()
19
+
20
+ if "dll load failed" in error_msg:
21
+ print("\n" + "!" * 75)
22
+ print(" [CRITICAL ERROR] Failed to load pyimagecuda backend.")
23
+
24
+ if not _check_nvidia_driver():
25
+ print(" CAUSE: NVIDIA Drivers are missing or not detected.")
26
+ print(" SOLUTION: Install latest drivers from: https://www.nvidia.com/Download/index.aspx")
27
+ else:
28
+ print(" CAUSE: Microsoft Visual C++ Redistributable is missing.")
29
+ print(" SOLUTION: Install it from: https://aka.ms/vs/17/release/vc_redist.x64.exe")
30
+
31
+ print("!" * 75 + "\n")
32
+ else:
33
+ print(f"Error loading internal module: {e}")
34
+
35
+ if _INTERNAL_LOADED:
36
+ try:
37
+ from .image import Image, ImageU8
38
+ from .io import upload, download, copy, save, load, convert_float_to_u8, convert_u8_to_float
39
+ from .fill import Fill
40
+ from .resize import Resize
41
+ from .blend import Blend
42
+ from .filter import Filter
43
+ from .effect import Effect
44
+ except ImportError as e:
45
+ print(f"Warning: Error importing Python wrappers: {e}")
46
+
47
+ def check_system():
48
+ print("--- PYIMAGECUDA DIAGNOSTIC ---")
49
+
50
+ if not _INTERNAL_LOADED:
51
+ print("❌ Backend C++ NOT loaded. See errors above.")
52
+ return False
53
+
54
+ try:
55
+ pyimagecuda_internal.cuda_sync()
56
+ print("✅ SYSTEM OK. GPU Ready & Libraries Loaded.")
57
+ return True
58
+ except Exception as e:
59
+ print(f"❌ Backend loaded but GPU runtime failed: {e}")
60
+ return False
pyimagecuda/blend.py ADDED
@@ -0,0 +1,77 @@
1
+ from .image import Image
2
+ from .pyimagecuda_internal import blend_f32 #type: ignore
3
+
4
+
5
+ class Blend:
6
+
7
+ @staticmethod
8
+ def normal(
9
+ base: Image,
10
+ overlay: Image,
11
+ pos_x: int = 0,
12
+ pos_y: int = 0,
13
+ opacity: float = 1.0
14
+ ) -> None:
15
+ blend_f32(
16
+ base._buffer._handle,
17
+ overlay._buffer._handle,
18
+ base.width, base.height,
19
+ overlay.width, overlay.height,
20
+ pos_x, pos_y,
21
+ 0,
22
+ opacity
23
+ )
24
+
25
+ @staticmethod
26
+ def multiply(
27
+ base: Image,
28
+ overlay: Image,
29
+ pos_x: int = 0,
30
+ pos_y: int = 0,
31
+ opacity: float = 1.0
32
+ ) -> None:
33
+ blend_f32(
34
+ base._buffer._handle,
35
+ overlay._buffer._handle,
36
+ base.width, base.height,
37
+ overlay.width, overlay.height,
38
+ pos_x, pos_y,
39
+ 1,
40
+ opacity
41
+ )
42
+
43
+ @staticmethod
44
+ def screen(
45
+ base: Image,
46
+ overlay: Image,
47
+ pos_x: int = 0,
48
+ pos_y: int = 0,
49
+ opacity: float = 1.0
50
+ ) -> None:
51
+ blend_f32(
52
+ base._buffer._handle,
53
+ overlay._buffer._handle,
54
+ base.width, base.height,
55
+ overlay.width, overlay.height,
56
+ pos_x, pos_y,
57
+ 2,
58
+ opacity
59
+ )
60
+
61
+ @staticmethod
62
+ def add(
63
+ base: Image,
64
+ overlay: Image,
65
+ pos_x: int = 0,
66
+ pos_y: int = 0,
67
+ opacity: float = 1.0
68
+ ) -> None:
69
+ blend_f32(
70
+ base._buffer._handle,
71
+ overlay._buffer._handle,
72
+ base.width, base.height,
73
+ overlay.width, overlay.height,
74
+ pos_x, pos_y,
75
+ 3,
76
+ opacity
77
+ )
pyimagecuda/effect.py ADDED
@@ -0,0 +1,90 @@
1
+ from .image import Image
2
+ from .filter import Filter
3
+ from .blend import Blend
4
+ from .fill import Fill
5
+ from .utils import check_dimensions_match
6
+ from .pyimagecuda_internal import ( #type: ignore
7
+ rounded_corners_f32,
8
+ extract_alpha_f32,
9
+ colorize_shadow_f32
10
+ )
11
+
12
+
13
+ class Effect:
14
+
15
+ @staticmethod
16
+ def rounded_corners(image: Image, radius: float) -> None:
17
+ max_radius = min(image.width, image.height) / 2.0
18
+
19
+ if radius < 0:
20
+ raise ValueError("Radius must be non-negative")
21
+
22
+ if radius > max_radius:
23
+ radius = max_radius
24
+
25
+ rounded_corners_f32(
26
+ image._buffer._handle,
27
+ image.width,
28
+ image.height,
29
+ float(radius)
30
+ )
31
+
32
+ @staticmethod
33
+ def drop_shadow(
34
+ image: Image,
35
+ offset_x: int = 10,
36
+ offset_y: int = 10,
37
+ blur: int = 20,
38
+ color: tuple[float, float, float, float] = (0.0, 0.0, 0.0, 0.5),
39
+ dst_buffer: Image | None = None,
40
+ shadow_buffer: Image | None = None,
41
+ temp_buffer: Image | None = None
42
+ ) -> Image | None:
43
+
44
+ if dst_buffer is None:
45
+ result = Image(image.width, image.height)
46
+ return_result = True
47
+ else:
48
+ check_dimensions_match(dst_buffer, image)
49
+ result = dst_buffer
50
+ return_result = False
51
+
52
+ if shadow_buffer is None:
53
+ shadow = Image(image.width, image.height)
54
+ owns_shadow = True
55
+ else:
56
+ check_dimensions_match(shadow_buffer, image)
57
+ shadow = shadow_buffer
58
+ owns_shadow = False
59
+
60
+ extract_alpha_f32(
61
+ image._buffer._handle,
62
+ shadow._buffer._handle,
63
+ image.width,
64
+ image.height
65
+ )
66
+
67
+ if blur > 0:
68
+ Filter.gaussian_blur(
69
+ shadow,
70
+ radius=blur,
71
+ sigma=blur / 3.0,
72
+ dst_buffer=shadow,
73
+ temp_buffer=temp_buffer
74
+ )
75
+
76
+ colorize_shadow_f32(
77
+ shadow._buffer._handle,
78
+ shadow.width,
79
+ shadow.height,
80
+ color
81
+ )
82
+
83
+ Fill.color(result, (0.0, 0.0, 0.0, 0.0))
84
+ Blend.normal(result, shadow, pos_x=offset_x, pos_y=offset_y)
85
+ Blend.normal(result, image, pos_x=0, pos_y=0)
86
+
87
+ if owns_shadow:
88
+ shadow.free()
89
+
90
+ return result if return_result else None
pyimagecuda/fill.py ADDED
@@ -0,0 +1,36 @@
1
+ from typing import Literal
2
+ from .image import Image
3
+ from .pyimagecuda_internal import fill_color_f32, fill_gradient_f32 #type: ignore
4
+
5
+ class Fill:
6
+
7
+ @staticmethod
8
+ def color(image: Image, rgba: tuple[float, float, float, float]) -> None:
9
+ fill_color_f32(image._buffer._handle, rgba, image.width, image.height)
10
+
11
+ @staticmethod
12
+ def gradient(image: Image,
13
+ rgba1: tuple[float, float, float, float],
14
+ rgba2: tuple[float, float, float, float],
15
+ direction: Literal['horizontal', 'vertical', 'diagonal', 'radial'] = 'horizontal',
16
+ seamless: bool = False) -> None:
17
+ direction_map = {
18
+ 'horizontal': 0,
19
+ 'vertical': 1,
20
+ 'diagonal': 2,
21
+ 'radial': 3
22
+ }
23
+
24
+ dir_int = direction_map.get(direction)
25
+ if dir_int is None:
26
+ raise ValueError(f"Invalid direction: {direction}. Must be one of {list(direction_map.keys())}")
27
+
28
+ fill_gradient_f32(
29
+ image._buffer._handle,
30
+ rgba1,
31
+ rgba2,
32
+ image.width,
33
+ image.height,
34
+ dir_int,
35
+ seamless
36
+ )
pyimagecuda/filter.py ADDED
@@ -0,0 +1,71 @@
1
+ from .image import Image
2
+ from .utils import check_dimensions_match
3
+ from .pyimagecuda_internal import gaussian_blur_separable_f32, sharpen_f32 #type: ignore
4
+
5
+
6
+ class Filter:
7
+
8
+ @staticmethod
9
+ def gaussian_blur(
10
+ src: Image,
11
+ radius: int = 3,
12
+ sigma: float | None = None,
13
+ dst_buffer: Image | None = None,
14
+ temp_buffer: Image | None = None
15
+ ) -> Image | None:
16
+
17
+ if sigma is None:
18
+ sigma = radius / 3.0
19
+
20
+ if dst_buffer is None:
21
+ dst_buffer = Image(src.width, src.height)
22
+ return_dst = True
23
+ else:
24
+ check_dimensions_match(dst_buffer, src)
25
+ return_dst = False
26
+
27
+ if temp_buffer is None:
28
+ temp_buffer = Image(src.width, src.height)
29
+ owns_temp = True
30
+ else:
31
+ check_dimensions_match(temp_buffer, src)
32
+ owns_temp = False
33
+
34
+ gaussian_blur_separable_f32(
35
+ src._buffer._handle,
36
+ temp_buffer._buffer._handle,
37
+ dst_buffer._buffer._handle,
38
+ src.width,
39
+ src.height,
40
+ int(radius),
41
+ float(sigma)
42
+ )
43
+
44
+ if owns_temp:
45
+ temp_buffer.free()
46
+
47
+ return dst_buffer if return_dst else None
48
+
49
+ @staticmethod
50
+ def sharpen(
51
+ src: Image,
52
+ strength: float = 1.0,
53
+ dst_buffer: Image | None = None
54
+ ) -> Image | None:
55
+
56
+ if dst_buffer is None:
57
+ dst_buffer = Image(src.width, src.height)
58
+ return_buffer = True
59
+ else:
60
+ check_dimensions_match(dst_buffer, src)
61
+ return_buffer = False
62
+
63
+ sharpen_f32(
64
+ src._buffer._handle,
65
+ dst_buffer._buffer._handle,
66
+ src.width,
67
+ src.height,
68
+ float(strength)
69
+ )
70
+
71
+ return dst_buffer if return_buffer else None
pyimagecuda/image.py ADDED
@@ -0,0 +1,78 @@
1
+ from .pyimagecuda_internal import create_buffer_f32, free_buffer, create_buffer_u8 #type: ignore
2
+
3
+
4
+ class Buffer:
5
+
6
+ def __init__(self, width: int, height: int, is_u8: bool = False):
7
+ create_func = create_buffer_u8 if is_u8 else create_buffer_f32
8
+ self._handle = create_func(width, height)
9
+ self.capacity_width = width
10
+ self.capacity_height = height
11
+
12
+ def free(self) -> None:
13
+ free_buffer(self._handle)
14
+
15
+
16
+ class ImageBase:
17
+
18
+ def __init__(self, width: int, height: int, is_u8: bool = False):
19
+ self._buffer = Buffer(width, height, is_u8)
20
+ self._width = width
21
+ self._height = height
22
+
23
+ @property
24
+ def width(self) -> int:
25
+ return self._width
26
+
27
+ @width.setter
28
+ def width(self, value: int) -> None:
29
+ value = int(value)
30
+ if value <= 0:
31
+ raise ValueError(f"Width must be positive, got {value}")
32
+
33
+ if value > self._buffer.capacity_width:
34
+ raise ValueError(
35
+ f"Width {value} exceeds buffer capacity "
36
+ f"{self._buffer.capacity_width}"
37
+ )
38
+
39
+ self._width = value
40
+
41
+ @property
42
+ def height(self) -> int:
43
+ return self._height
44
+
45
+ @height.setter
46
+ def height(self, value: int) -> None:
47
+ value = int(value)
48
+ if value <= 0:
49
+ raise ValueError(f"Height must be positive, got {value}")
50
+
51
+ if value > self._buffer.capacity_height:
52
+ raise ValueError(
53
+ f"Height {value} exceeds buffer capacity "
54
+ f"{self._buffer.capacity_height}"
55
+ )
56
+
57
+ self._height = value
58
+
59
+ def free(self) -> None:
60
+ self._buffer.free()
61
+
62
+ def get_max_capacity(self) -> tuple[int, int]:
63
+ return (self._buffer.capacity_width, self._buffer.capacity_height)
64
+
65
+ def __repr__(self) -> str:
66
+ return f"{self.__class__.__name__}({self.width}×{self.height})"
67
+
68
+
69
+ class Image(ImageBase):
70
+
71
+ def __init__(self, width: int, height: int):
72
+ super().__init__(width, height, is_u8=False)
73
+
74
+
75
+ class ImageU8(ImageBase):
76
+
77
+ def __init__(self, width: int, height: int):
78
+ super().__init__(width, height, is_u8=True)
pyimagecuda/io.py ADDED
@@ -0,0 +1,130 @@
1
+ import pyvips
2
+
3
+ from .pyimagecuda_internal import upload_to_buffer, convert_f32_to_u8, convert_u8_to_f32, download_from_buffer, copy_buffer #type: ignore
4
+ from .image import Image, ImageU8, ImageBase
5
+ from .utils import check_dimensions_match
6
+
7
+
8
+
9
+ def upload(image: ImageBase, data: bytes | bytearray | memoryview) -> None:
10
+ bytes_per_pixel = 4 if isinstance(image, ImageU8) else 16
11
+ expected = image.width * image.height * bytes_per_pixel
12
+ actual = data.nbytes if isinstance(data, memoryview) else len(data)
13
+
14
+ if actual != expected:
15
+ raise ValueError(f"Expected {expected} bytes, got {actual}")
16
+
17
+ upload_to_buffer(image._buffer._handle, data, image.width, image.height)
18
+
19
+
20
+ def download(image: ImageBase) -> bytes:
21
+ return download_from_buffer(image._buffer._handle, image.width, image.height)
22
+
23
+
24
+ def copy(dst: ImageBase, src: ImageBase) -> None:
25
+ check_dimensions_match(dst, src)
26
+ copy_buffer(dst._buffer._handle, src._buffer._handle, src.width, src.height)
27
+
28
+
29
+ def convert_float_to_u8(dst: ImageU8, src: Image) -> None:
30
+ check_dimensions_match(dst, src)
31
+ convert_f32_to_u8(dst._buffer._handle, src._buffer._handle, src.width, src.height)
32
+
33
+
34
+ def convert_u8_to_float(dst: Image, src: ImageU8) -> None:
35
+ check_dimensions_match(dst, src)
36
+ convert_u8_to_f32(dst._buffer._handle, src._buffer._handle, src.width, src.height)
37
+
38
+
39
+ def load(filepath: str, f32_buffer: Image | None = None, u8_buffer: ImageU8 | None = None) -> Image:
40
+ vips_img = pyvips.Image.new_from_file(filepath, access='sequential')
41
+
42
+ if vips_img.bands == 1:
43
+ vips_img = vips_img.bandjoin([vips_img, vips_img, vips_img])
44
+ vips_img = vips_img.bandjoin(255)
45
+ elif vips_img.bands == 3:
46
+ vips_img = vips_img.bandjoin(255)
47
+ elif vips_img.bands == 4:
48
+ pass
49
+ else:
50
+ raise ValueError(
51
+ f"Unsupported image format: {vips_img.bands} channels. "
52
+ f"Only grayscale (1), RGB (3), and RGBA (4) are supported."
53
+ )
54
+
55
+ width = vips_img.width
56
+ height = vips_img.height
57
+
58
+ if f32_buffer is None:
59
+ f32_buffer = Image(width, height)
60
+ else:
61
+ max_w, max_h = f32_buffer.get_max_capacity()
62
+ if width > max_w or height > max_h:
63
+ raise ValueError(
64
+ f"Image {width}×{height} exceeds f32_buffer capacity {max_w}×{max_h}"
65
+ )
66
+
67
+ f32_buffer.width = width
68
+ f32_buffer.height = height
69
+
70
+ if u8_buffer is None:
71
+ u8_buffer = ImageU8(width, height)
72
+ owns_u8 = True
73
+ else:
74
+ max_w, max_h = u8_buffer.get_max_capacity()
75
+ if width > max_w or height > max_h:
76
+ raise ValueError(
77
+ f"Image {width}×{height} exceeds u8_buffer capacity {max_w}×{max_h}"
78
+ )
79
+
80
+ u8_buffer.width = width
81
+ u8_buffer.height = height
82
+ owns_u8 = False
83
+
84
+ vips_img = vips_img.cast('uchar')
85
+ pixel_data = vips_img.write_to_memory()
86
+
87
+ upload(u8_buffer, pixel_data)
88
+
89
+ convert_u8_to_float(f32_buffer, u8_buffer)
90
+
91
+ if owns_u8:
92
+ u8_buffer.free()
93
+
94
+ return f32_buffer
95
+
96
+
97
+ def save(image: Image, filepath: str, u8_buffer: ImageU8 | None = None, quality: int | None = None) -> None:
98
+ if u8_buffer is None:
99
+ u8_buffer = ImageU8(image.width, image.height)
100
+ owns_buffer = True
101
+ else:
102
+ check_dimensions_match(u8_buffer, image)
103
+ owns_buffer = False
104
+
105
+ convert_float_to_u8(u8_buffer, image)
106
+ pixel_data = download(u8_buffer)
107
+
108
+ vips_img = pyvips.Image.new_from_memory(
109
+ pixel_data,
110
+ image.width,
111
+ image.height,
112
+ bands=4,
113
+ format='uchar'
114
+ )
115
+
116
+ vips_img = vips_img.copy(interpretation='srgb')
117
+
118
+ save_kwargs = {}
119
+ if quality is not None:
120
+ if filepath.lower().endswith(('.jpg', '.jpeg')):
121
+ save_kwargs['Q'] = quality
122
+ elif filepath.lower().endswith('.webp'):
123
+ save_kwargs['Q'] = quality
124
+ elif filepath.lower().endswith(('.heic', '.heif')):
125
+ save_kwargs['Q'] = quality
126
+
127
+ vips_img.write_to_file(filepath, **save_kwargs)
128
+
129
+ if owns_buffer:
130
+ u8_buffer.free()
pyimagecuda/resize.py ADDED
@@ -0,0 +1,72 @@
1
+ from .image import Image
2
+ from .pyimagecuda_internal import resize_f32 #type: ignore
3
+
4
+
5
+ def _resize_internal(
6
+ src: Image,
7
+ width: int,
8
+ height: int,
9
+ method: int,
10
+ dst_buffer: Image | None = None
11
+ ) -> Image | None:
12
+
13
+ if dst_buffer is None:
14
+ dst_buffer = Image(width, height)
15
+ return_buffer = True
16
+ else:
17
+ if dst_buffer.width != width or dst_buffer.height != height:
18
+ raise ValueError(
19
+ f"dst_buffer size mismatch: expected {width}×{height}, "
20
+ f"got {dst_buffer.width}×{dst_buffer.height}"
21
+ )
22
+ return_buffer = False
23
+
24
+ resize_f32(
25
+ src._buffer._handle,
26
+ dst_buffer._buffer._handle,
27
+ src.width,
28
+ src.height,
29
+ width,
30
+ height,
31
+ method
32
+ )
33
+
34
+ return dst_buffer if return_buffer else None
35
+
36
+
37
+ class Resize:
38
+ @staticmethod
39
+ def nearest(
40
+ src: Image,
41
+ width: int,
42
+ height: int,
43
+ dst_buffer: Image | None = None
44
+ ) -> Image | None:
45
+ return _resize_internal(src, width, height, 0, dst_buffer)
46
+
47
+ @staticmethod
48
+ def bilinear(
49
+ src: Image,
50
+ width: int,
51
+ height: int,
52
+ dst_buffer: Image | None = None
53
+ ) -> Image | None:
54
+ return _resize_internal(src, width, height, 1, dst_buffer)
55
+
56
+ @staticmethod
57
+ def bicubic(
58
+ src: Image,
59
+ width: int,
60
+ height: int,
61
+ dst_buffer: Image | None = None
62
+ ) -> Image | None:
63
+ return _resize_internal(src, width, height, 2, dst_buffer)
64
+
65
+ @staticmethod
66
+ def lanczos(
67
+ src: Image,
68
+ width: int,
69
+ height: int,
70
+ dst_buffer: Image | None = None
71
+ ) -> Image | None:
72
+ return _resize_internal(src, width, height, 3, dst_buffer)
pyimagecuda/utils.py ADDED
@@ -0,0 +1,9 @@
1
+ from .image import ImageBase
2
+
3
+
4
+
5
+ def check_dimensions_match(img1: ImageBase, img2: ImageBase) -> None:
6
+ if img1.width != img2.width or img1.height != img2.height:
7
+ raise ValueError(
8
+ f"Dimension mismatch: {img1.width}×{img1.height} vs {img2.width}×{img2.height}"
9
+ )
@@ -0,0 +1,29 @@
1
+ Metadata-Version: 2.2
2
+ Name: pyimagecuda
3
+ Version: 0.0.1
4
+ Summary: GPU-accelerated image processing library for Python
5
+ Author: Beltrán Offerrall
6
+ Requires-Python: >=3.10
7
+ Requires-Dist: pyvips[binary]
8
+ Description-Content-Type: text/markdown
9
+
10
+ # PyImageCUDA
11
+
12
+ [![Build Status](https://github.com/offerrall/pyimagecuda/actions/workflows/build.yml/badge.svg)](https://github.com/offerrall/pyimagecuda/actions)
13
+
14
+ > ⚠️ **STATUS: PRE-ALPHA / INFRASTRUCTURE TESTING**
15
+ >
16
+ > This repository is currently validating the build and distribution system.
17
+ > **It is NOT ready for production use yet.**
18
+
19
+ ### Goal
20
+ GPU-accelerated (CUDA) image processing library for Python.
21
+ Designed to be installed via a simple `pip install` without requiring the user to have the CUDA Toolkit or Visual Studio installed.
22
+
23
+ ### Verification (Testers Only)
24
+
25
+ If you have installed a test build, you can verify that hardware acceleration is working correctly by running:
26
+
27
+ ```bash
28
+ python -c "import pyimagecuda; pyimagecuda.check_system()"
29
+ ```
@@ -0,0 +1,13 @@
1
+ pyimagecuda/__init__.py,sha256=YNyiiMnR1XgqMqdhXbbPG2r-w8VUPetHZN-la2sJUAU,1941
2
+ pyimagecuda/blend.py,sha256=_WgLwveDHJ_-OpqpcRf7FVZIF_k0SoPhA_RwRjgqV1M,1824
3
+ pyimagecuda/effect.py,sha256=BPnu53goEMZGWWF0_9_tPfKXEF5eLkMtfM99H_KN3GE,2585
4
+ pyimagecuda/fill.py,sha256=ZBzN1L8iXsymd7aixovkc397osrD8AQCiytOWiYRwac,1238
5
+ pyimagecuda/filter.py,sha256=GdGIiadYuqtY8k7kFISR8GMTHZ1QYtvtLWFxDMO9_qY,1956
6
+ pyimagecuda/image.py,sha256=K3d13hhUb1y4DKu8zlA81JFgQ81_MWZeMKHc4OOUvFA,2304
7
+ pyimagecuda/io.py,sha256=sATHtf0tHH-4luZ9kmVF1EQ7vhyoB5iIhLK7bnj9x5E,4285
8
+ pyimagecuda/pyimagecuda_internal.cp313-win_amd64.pyd,sha256=iaNyBlVlySdiHYQtCUH13YeaIXmokMByNbjmYvfvKQA,336896
9
+ pyimagecuda/resize.py,sha256=WZAf85t1BNxF4THbPR6_dcj44xZroLKmTR5T90pw6nk,1848
10
+ pyimagecuda/utils.py,sha256=9QDAFFnb2uJYwXup3hHHUm7uOjT7e5omfDEpwRx_F_w,302
11
+ pyimagecuda-0.0.1.dist-info/METADATA,sha256=nhfRJoEYkBlNw3d8pgQ89LCx1rB73exmg02Gc27fwGI,1001
12
+ pyimagecuda-0.0.1.dist-info/WHEEL,sha256=vkL3wTIkhjZa3RmEXX20hldNp6Q8qtwRjrXW6K5sw_Q,106
13
+ pyimagecuda-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: scikit-build-core 0.11.6
3
+ Root-Is-Purelib: false
4
+ Tag: cp313-cp313-win_amd64
5
+