pkgprint 0.2.0__tar.gz → 0.2.1__tar.gz

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.
Files changed (28) hide show
  1. pkgprint-0.2.1/PKG-INFO +381 -0
  2. pkgprint-0.2.1/README.md +351 -0
  3. {pkgprint-0.2.0 → pkgprint-0.2.1}/pkgprint/__init__.py +1 -1
  4. pkgprint-0.2.1/pkgprint.egg-info/PKG-INFO +381 -0
  5. {pkgprint-0.2.0 → pkgprint-0.2.1}/pyproject.toml +1 -1
  6. pkgprint-0.2.0/PKG-INFO +0 -201
  7. pkgprint-0.2.0/README.md +0 -171
  8. pkgprint-0.2.0/pkgprint.egg-info/PKG-INFO +0 -201
  9. {pkgprint-0.2.0 → pkgprint-0.2.1}/LICENSE +0 -0
  10. {pkgprint-0.2.0 → pkgprint-0.2.1}/pkgprint/accessibility.py +0 -0
  11. {pkgprint-0.2.0 → pkgprint-0.2.1}/pkgprint/check.py +0 -0
  12. {pkgprint-0.2.0 → pkgprint-0.2.1}/pkgprint/color.py +0 -0
  13. {pkgprint-0.2.0 → pkgprint-0.2.1}/pkgprint/dieline.py +0 -0
  14. {pkgprint-0.2.0 → pkgprint-0.2.1}/pkgprint/paper.py +0 -0
  15. {pkgprint-0.2.0 → pkgprint-0.2.1}/pkgprint/print_specs.py +0 -0
  16. {pkgprint-0.2.0 → pkgprint-0.2.1}/pkgprint/units.py +0 -0
  17. {pkgprint-0.2.0 → pkgprint-0.2.1}/pkgprint.egg-info/SOURCES.txt +0 -0
  18. {pkgprint-0.2.0 → pkgprint-0.2.1}/pkgprint.egg-info/dependency_links.txt +0 -0
  19. {pkgprint-0.2.0 → pkgprint-0.2.1}/pkgprint.egg-info/requires.txt +0 -0
  20. {pkgprint-0.2.0 → pkgprint-0.2.1}/pkgprint.egg-info/top_level.txt +0 -0
  21. {pkgprint-0.2.0 → pkgprint-0.2.1}/setup.cfg +0 -0
  22. {pkgprint-0.2.0 → pkgprint-0.2.1}/tests/test_accessibility.py +0 -0
  23. {pkgprint-0.2.0 → pkgprint-0.2.1}/tests/test_check.py +0 -0
  24. {pkgprint-0.2.0 → pkgprint-0.2.1}/tests/test_color.py +0 -0
  25. {pkgprint-0.2.0 → pkgprint-0.2.1}/tests/test_dieline.py +0 -0
  26. {pkgprint-0.2.0 → pkgprint-0.2.1}/tests/test_paper.py +0 -0
  27. {pkgprint-0.2.0 → pkgprint-0.2.1}/tests/test_print_specs.py +0 -0
  28. {pkgprint-0.2.0 → pkgprint-0.2.1}/tests/test_units.py +0 -0
@@ -0,0 +1,381 @@
1
+ Metadata-Version: 2.2
2
+ Name: pkgprint
3
+ Version: 0.2.1
4
+ Summary: Print and packaging math utilities for developers
5
+ Author: Rishabh
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Rishabh55122/pkgprint
8
+ Project-URL: Bug Tracker, https://github.com/Rishabh55122/pkgprint/issues
9
+ Keywords: print,packaging,design,cmyk,dpi,bleed,typography
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.8
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Topic :: Multimedia :: Graphics
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Intended Audience :: Developers
22
+ Requires-Python: >=3.8
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: Pillow>=9.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0; extra == "dev"
28
+ Requires-Dist: build; extra == "dev"
29
+ Requires-Dist: twine; extra == "dev"
30
+
31
+ # pkgprint
32
+
33
+ **Print and packaging math — straight to your Python project.**
34
+
35
+ [![PyPI version](https://badge.fury.io/py/pkgprint.svg)](https://pypi.org/project/pkgprint/)
36
+ [![Python 3.8+](https://img.shields.io/badge/python-3.8%2B-blue.svg)](https://www.python.org/)
37
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
38
+ [![Tests](https://img.shields.io/badge/tests-220%20passing-brightgreen.svg)](#testing--quality)
39
+
40
+ `pkgprint` is a Python library for the fiddly arithmetic behind print and packaging production: unit conversions, colour model translations, standard paper and box sizes, bleed calculations, print-readiness file checking, WCAG colour contrast validation, and box dieline layout. It's built for developers who work with print pipelines, packaging design tools, or any application that touches commercial print — people who need correct, well-tested answers, not approximations. The core math is zero-dependency; Pillow is only pulled in when you actually check image files.
41
+
42
+ ---
43
+
44
+ ## Installation
45
+
46
+ ```bash
47
+ pip install pkgprint
48
+ ```
49
+
50
+ ---
51
+
52
+ ## Quick Start
53
+
54
+ ```python
55
+ import pkgprint
56
+
57
+ # Look up a standard size and convert to inches
58
+ w, h = pkgprint.paper_size("A4") # (210, 297)
59
+ pkgprint.mm_to_inches(w) # 8.267716535433072
60
+
61
+ # Add 3 mm bleed to a US business card
62
+ pkgprint.add_bleed(89, 51) # (95, 57)
63
+
64
+ # Translate a brand colour between colour models
65
+ pkgprint.cmyk_to_rgb(0, 100, 100, 0) # (255, 0, 0)
66
+ pkgprint.rgb_to_hex(255, 0, 0) # '#FF0000'
67
+
68
+ # Check text contrast against WCAG AA
69
+ pkgprint.contrast_ratio((0, 0, 0), (255, 255, 255)) # 21.0
70
+ result = pkgprint.check_wcag_compliance((140, 140, 140), (255, 255, 255))
71
+ result.passed # False (3.36:1 < 4.5)
72
+
73
+ # Calculate flat sheet size for a shipping box (RSC style)
74
+ pkgprint.rsc_flat_size(300, 200, 150) # (1035.0, 350)
75
+ ```
76
+
77
+ ---
78
+
79
+ ## Why pkgprint?
80
+
81
+ - **Zero-dependency core.** Unit conversions, colour math, paper sizes, bleed calculations — none of it needs an external package. Pillow is only imported when you call `check_dpi`, `check_color_mode`, or `check_dimensions`.
82
+ - **Formulas from the field.** The WCAG relative luminance uses the exact sRGB gamma correction; RSC flat-size formulas match industry practice; paper sizes reference ISO 216 and ANSI standards. Shortcuts are flagged explicitly in docstrings.
83
+ - **Rigorous tests.** 220+ tests covering normal cases, edge cases, and error paths. The suite caught a real production edge case during development: `2480 × 3508 px` — the widely-cited "A4 at 300 DPI" pixel count — actually resolves to 299.97 DPI due to mm→inch rounding, and fails a 300 DPI check. `pkgprint` ships the correct `2481 px` threshold.
84
+ - **MIT licensed, commercially free.** Use it in client projects, SaaS products, or internal tooling without restriction.
85
+
86
+ ---
87
+
88
+ ## Feature Overview
89
+
90
+ | Module | Description | Functions |
91
+ |---|---|---|
92
+ | `units` | mm ↔ inches ↔ points, DPI ↔ PPI conversions | 6 |
93
+ | `color` | CMYK ↔ RGB ↔ hex colour model conversions | 4 |
94
+ | `paper` | Standard paper sizes (ISO, ANSI, US) and common box dimensions | 3 |
95
+ | `print_specs` | Bleed, safe margin, and trim size calculations | 3 |
96
+ | `check` | Image file print-readiness: DPI, colour mode, and dimension checks | 4 + 2 types |
97
+ | `accessibility` | WCAG 2.1 contrast ratio checking and colour adjustment | 4 + 1 type |
98
+ | `dieline` | Flat sheet and named panel layout for RSC and Mailer box styles | 3 + 1 type |
99
+
100
+ ---
101
+
102
+ ## Module Reference
103
+
104
+ <details>
105
+ <summary><strong>📏 units — Measurement Conversions</strong></summary>
106
+
107
+ Converts between the measurement units used throughout print and design workflows. DPI and PPI functions are semantic aliases — numerically identical, provided for clarity in code that mixes screen and print contexts.
108
+
109
+ | Function | Converts |
110
+ |---|---|
111
+ | `mm_to_inches(mm)` | millimetres → inches |
112
+ | `inches_to_mm(inches)` | inches → millimetres |
113
+ | `mm_to_points(mm)` | millimetres → PostScript points (1 pt = 1/72 in) |
114
+ | `points_to_mm(points)` | PostScript points → millimetres |
115
+ | `dpi_to_ppi(dpi)` | DPI → PPI (identity, semantic alias) |
116
+ | `ppi_to_dpi(ppi)` | PPI → DPI (identity, semantic alias) |
117
+
118
+ ```python
119
+ import pkgprint
120
+
121
+ pkgprint.mm_to_inches(25.4) # 1.0
122
+ pkgprint.mm_to_inches(210) # 8.267716535433072 (A4 width)
123
+ pkgprint.inches_to_mm(1) # 25.4
124
+ pkgprint.mm_to_points(25.4) # 72.0 (1 inch = 72 pt)
125
+ ```
126
+
127
+ </details>
128
+
129
+ ---
130
+
131
+ <details>
132
+ <summary><strong>🎨 color — Colour Model Conversions</strong></summary>
133
+
134
+ Converts between the colour models used in print (CMYK) and screen/web (RGB, hex) workflows. CMYK channels use the 0–100 scale (percentage); RGB channels use 0–255.
135
+
136
+ | Function | Converts |
137
+ |---|---|
138
+ | `cmyk_to_rgb(c, m, y, k)` | CMYK (0–100 each) → RGB (0–255 each) |
139
+ | `rgb_to_cmyk(r, g, b)` | RGB (0–255 each) → CMYK (0–100 each) |
140
+ | `hex_to_rgb(hex_str)` | Hex colour string → RGB tuple |
141
+ | `rgb_to_hex(r, g, b)` | RGB tuple → hex colour string |
142
+
143
+ ```python
144
+ import pkgprint
145
+
146
+ pkgprint.cmyk_to_rgb(0, 100, 100, 0) # (255, 0, 0) — pure red
147
+ pkgprint.cmyk_to_rgb(0, 0, 0, 100) # (0, 0, 0) — process black
148
+ pkgprint.rgb_to_cmyk(255, 0, 0) # (0.0, 100.0, 100.0, 0.0)
149
+ pkgprint.rgb_to_hex(255, 0, 0) # '#FF0000'
150
+ pkgprint.hex_to_rgb('#FF0000') # (255, 0, 0)
151
+ ```
152
+
153
+ </details>
154
+
155
+ ---
156
+
157
+ <details>
158
+ <summary><strong>📄 paper — Standard Paper & Box Sizes</strong></summary>
159
+
160
+ Looks up standard paper sizes (ISO A-series, B-series, US Letter/Legal/Tabloid, business cards) and common shipping box sizes. All dimensions are in millimetres. Lookups are case-insensitive.
161
+
162
+ | Function | Returns |
163
+ |---|---|
164
+ | `paper_size(name)` | `(width_mm, height_mm)` for a named paper size |
165
+ | `list_paper_sizes()` | Sorted list of all available paper size names |
166
+ | `box_size(name)` | `(length_mm, width_mm, height_mm)` for a named box size |
167
+
168
+ ```python
169
+ import pkgprint
170
+
171
+ pkgprint.paper_size("A4") # (210, 297)
172
+ pkgprint.paper_size("Letter") # (216, 279)
173
+ pkgprint.paper_size("Business Card US") # (89, 51)
174
+ pkgprint.paper_size("Business Card ISO") # (85, 55)
175
+ pkgprint.box_size("RSC Medium") # (305, 229, 152)
176
+
177
+ pkgprint.list_paper_sizes()[:4]
178
+ # ['A0', 'A1', 'A2', 'A3']
179
+ ```
180
+
181
+ > **Note on business card sizes:** ISO/European business cards are 85×55 mm; US business cards are 89×51 mm (3.5"×2"). Both are available under distinct names.
182
+
183
+ </details>
184
+
185
+ ---
186
+
187
+ <details>
188
+ <summary><strong>✂️ print_specs — Bleed, Margin & Trim Calculations</strong></summary>
189
+
190
+ Calculates the three key dimension sets in any print-ready file: the bleed size (artwork canvas with bleed added), the safe area (the zone guaranteed not to be trimmed), and the trim size (finished size recovered from a bled-up file).
191
+
192
+ | Function | Purpose |
193
+ |---|---|
194
+ | `add_bleed(w, h, bleed_mm=3)` | Add bleed to both dimensions; returns `(bleed_w, bleed_h)` |
195
+ | `safe_margin(w, h, margin_mm=5)` | Subtract safe margin; returns `(safe_w, safe_h)` |
196
+ | `trim_size(w, h, bleed_mm=3)` | Recover trim size from a bled-up file; returns `(trim_w, trim_h)` |
197
+
198
+ ```python
199
+ import pkgprint
200
+
201
+ # US business card: 89×51 mm trim, 3 mm bleed → canvas size
202
+ pkgprint.add_bleed(89, 51) # (95, 57)
203
+
204
+ # A4 with 5 mm bleed
205
+ pkgprint.add_bleed(210, 297, bleed_mm=5) # (220, 307)
206
+
207
+ # Safe text area inside A4 (5 mm margin from each edge)
208
+ pkgprint.safe_margin(210, 297) # (200, 287)
209
+
210
+ # Recover trim size from a 95×57 mm bled-up business card
211
+ pkgprint.trim_size(95, 57) # (89, 51)
212
+ ```
213
+
214
+ </details>
215
+
216
+ ---
217
+
218
+ <details>
219
+ <summary><strong>✅ check — Print-Readiness File Checker</strong></summary>
220
+
221
+ Inspects an actual image file and reports whether it meets commercial print requirements. Requires **Pillow** (installed automatically with `pip install pkgprint`).
222
+
223
+ Each check returns a `CheckResult` with `.passed`, `.actual`, `.expected`, and `.message`. `full_report()` collects all three checks without raising on individual failures.
224
+
225
+ | Function | Checks |
226
+ |---|---|
227
+ | `check_dpi(path, w_mm, h_mm, min_dpi=300)` | Effective DPI at the target print size |
228
+ | `check_color_mode(path, required_mode="CMYK")` | Colour mode (CMYK, RGB, Grayscale…) |
229
+ | `check_dimensions(path, w_mm, h_mm, tolerance_mm=1)` | Physical size at native DPI vs target |
230
+ | `full_report(path, w_mm, h_mm, min_dpi=300, required_color_mode="CMYK")` | All three checks combined |
231
+
232
+ ```python
233
+ import pkgprint
234
+
235
+ report = pkgprint.full_report("artwork.tif", 210, 297)
236
+
237
+ print(report.summary)
238
+ # DPI check: PASS — Effective DPI 304.8 ≥ 300 ...
239
+ # Colour mode: FAIL — Colour mode is 'RGB' but 'CMYK' is required ...
240
+ # Dimensions check: PASS — Dimensions 210.0×297.0 mm match target ...
241
+ # Overall: NOT PRINT-READY
242
+
243
+ report.passed # False
244
+ report.dpi.passed # True
245
+ report.color_mode.passed # False
246
+ report.dimensions.actual # (210.0, 297.0)
247
+
248
+ # Individual checks
249
+ result = pkgprint.check_dpi("artwork.tif", 210, 297, min_dpi=300)
250
+ result.passed # True / False
251
+ result.actual # effective DPI on the worst axis
252
+ result.message # human-readable diagnostic
253
+ ```
254
+
255
+ **Result types:** `CheckResult(passed, actual, expected, message)` and `PrintReport(dpi, color_mode, dimensions, passed, summary)`.
256
+
257
+ </details>
258
+
259
+ ---
260
+
261
+ <details>
262
+ <summary><strong>♿ accessibility — WCAG Colour Contrast Checker</strong></summary>
263
+
264
+ Checks foreground/background colour pairs for legibility using the WCAG 2.1 contrast formulas — useful for packaging with text, label design, or any print piece with brand colour over a background.
265
+
266
+ WCAG thresholds: AA normal text = 4.5:1, AA large text = 3.0:1, AAA normal = 7.0:1, AAA large = 4.5:1.
267
+
268
+ | Function | Purpose |
269
+ |---|---|
270
+ | `relative_luminance(r, g, b)` | WCAG sRGB relative luminance (0.0–1.0) |
271
+ | `contrast_ratio(rgb1, rgb2)` | WCAG contrast ratio (1.0–21.0) |
272
+ | `check_wcag_compliance(rgb1, rgb2, level="AA", text_size="normal")` | Pass/fail + ratio vs WCAG threshold |
273
+ | `suggest_darker_or_lighter(rgb_text, rgb_bg, target_ratio=4.5)` | Adjusted text colour that meets the target ratio |
274
+
275
+ ```python
276
+ import pkgprint
277
+
278
+ # Pure black on white: maximum contrast
279
+ pkgprint.contrast_ratio((0, 0, 0), (255, 255, 255)) # 21.0
280
+
281
+ # Mid-grey on white: fails AA normal text
282
+ result = pkgprint.check_wcag_compliance((140, 140, 140), (255, 255, 255))
283
+ result.passed # False
284
+ result.ratio # 3.36
285
+ result.required_ratio # 4.5
286
+ result.message # 'Contrast ratio 3.36:1 does NOT meet WCAG AA ...'
287
+
288
+ # Get an adjusted colour that passes
289
+ adjusted = pkgprint.suggest_darker_or_lighter(
290
+ (140, 140, 140), (255, 255, 255), target_ratio=4.5
291
+ )
292
+ adjusted # (118, 118, 118)
293
+ pkgprint.contrast_ratio(adjusted, (255, 255, 255)) # 4.54
294
+ ```
295
+
296
+ **Result type:** `ContrastResult(passed, ratio, required_ratio, level, text_size, message)`.
297
+
298
+ </details>
299
+
300
+ ---
301
+
302
+ <details>
303
+ <summary><strong>📦 dieline — Flat Panel Layout Calculator</strong></summary>
304
+
305
+ Calculates the flat sheet dimensions and named panel sizes for common box styles, so designers know how large their artwork canvas needs to be before structural work starts.
306
+
307
+ > **Planning formulas only.** These are standard industry approximations. They do not account for material thickness, flute direction, or supplier-specific tuck geometry. Confirm with your structural engineer or printer's dieline template before production.
308
+
309
+ Supported styles in v0.2.0: `"RSC"` (Regular Slotted Container) and `"Mailer"` (tuck-end mailer). More styles planned — see [Roadmap](#roadmap).
310
+
311
+ | Function | Returns |
312
+ |---|---|
313
+ | `rsc_flat_size(length, width, height)` | `(flat_width_mm, flat_height_mm)` for an RSC box |
314
+ | `mailer_flat_size(length, width, height)` | `(flat_width_mm, flat_height_mm)` for a tuck mailer |
315
+ | `panel_layout(length, width, height, style="RSC")` | List of `Panel` objects with name, width_mm, height_mm |
316
+
317
+ ```python
318
+ import pkgprint
319
+
320
+ # Flat canvas for a 300×200×150 mm RSC shipping box
321
+ pkgprint.rsc_flat_size(300, 200, 150) # (1035.0, 350)
322
+ # flat_width = 2×(300+200) + 35 mm glue flap = 1035 mm
323
+ # flat_height = 150 + 200 (top + bottom flaps each = W/2) = 350 mm
324
+
325
+ # Named panels for the same box
326
+ panels = pkgprint.panel_layout(300, 200, 150)
327
+ len(panels) # 13 (4 body + 8 flaps + 1 glue flap)
328
+ panels[0] # Panel(name='front', width_mm=300, height_mm=150)
329
+ panels[1] # Panel(name='right side', width_mm=200, height_mm=150)
330
+
331
+ # Tuck mailer: 200×100×50 mm
332
+ pkgprint.mailer_flat_size(200, 100, 50) # (635.0, 300.0)
333
+ pkgprint.panel_layout(200, 100, 50, style="Mailer")
334
+ # 7 panels: front, right side, back, left side,
335
+ # top tuck flap, bottom tuck flap, glue flap
336
+ ```
337
+
338
+ **Result type:** `Panel(name, width_mm, height_mm)`.
339
+
340
+ </details>
341
+
342
+ ---
343
+
344
+ ## Real-World Use Case
345
+
346
+ **Scenario: Preparing a client's business card artwork for print.**
347
+
348
+ A client uploads a logo file intended for their US business card (89×51 mm). Before sending to print, you need to verify the file meets your printer's spec, add bleed, and check that their brand colour — a warm grey — will actually be legible as text over the card's white background. With `pkgprint`, you look up the standard size with `paper_size("Business Card US")`, then run `full_report()` on the uploaded file: it instantly tells you the effective DPI at that print size, whether the file is CMYK or RGB (most printers require CMYK), and whether the physical dimensions match. You then call `add_bleed(89, 51)` to get the 95×57 mm canvas size your designer needs. Finally, `check_wcag_compliance(brand_grey, (255, 255, 255))` flags that the grey is only 3.36:1 contrast — failing AA — and `suggest_darker_or_lighter()` proposes an adjusted value that passes, keeping the hue intact. The whole check pipeline runs in under a second, before anything goes to the print queue.
349
+
350
+ ---
351
+
352
+ ## Testing & Quality
353
+
354
+ `pkgprint` ships with **220 tests** across 7 test files, one per module. The suite covers:
355
+
356
+ - Normal operation, edge cases (zero bleed, exact threshold values), and error paths (wrong types, out-of-range inputs, missing files)
357
+ - Both WCAG AA and AAA thresholds for all four normal/large text combinations
358
+ - Programmatically generated image fixtures for `check.py` — no binary assets committed to the repo
359
+
360
+ **A note on rigor:** During development, the test suite caught a subtle real-world edge case. `2480 × 3508 px` is widely cited as "A4 at 300 DPI", but `2480 ÷ (210 mm / 25.4) = 299.97 DPI` — fractionally below 300 due to mm→inch conversion. The correct pixel count is `2481 × 3508`. The test suite uses the accurate value and the `check_dpi` function enforces the correct threshold.
361
+
362
+ ---
363
+
364
+ ## Roadmap
365
+
366
+ - **SVG dieline output** — generate production-ready flat dieline artwork directly from `panel_layout()` (v0.3.0)
367
+ - **Extended box styles** — crash-lock bottom, auto-bottom, five-panel wrap, and more
368
+ - **Expanded paper standards** — JIS B-series, Japanese Shiroku-ban, additional envelope sizes
369
+ - **CLI tool** — `pkgprint check artwork.tif --size A4 --dpi 300` for quick pre-flight from the terminal
370
+
371
+ ---
372
+
373
+ ## Contributing
374
+
375
+ Bug reports, feature requests, and pull requests are welcome at [github.com/Rishabh55122/pkgprint/issues](https://github.com/Rishabh55122/pkgprint/issues). Please open an issue before starting significant work so we can align on approach.
376
+
377
+ ---
378
+
379
+ ## License
380
+
381
+ MIT — see [LICENSE](LICENSE). Free to use in commercial and open-source projects.