pdfdancer-client-python 0.3.8__tar.gz → 0.3.9__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 (83) hide show
  1. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/PKG-INFO +1 -1
  2. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/docs/api-schemas/v0.yml +164 -2
  3. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/docs/api-schemas/v1.yml +165 -10
  4. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/pyproject.toml +1 -1
  5. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/src/pdfdancer/models.py +21 -0
  6. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/src/pdfdancer/types.py +39 -1
  7. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/src/pdfdancer_client_python.egg-info/PKG-INFO +1 -1
  8. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_image_transform.py +121 -1
  9. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/.claude/commands/discuss.md +0 -0
  10. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/.claude/commands/implement-new-api-features.md +0 -0
  11. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/.flake8 +0 -0
  12. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/.github/workflows/ci.yml +0 -0
  13. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/.github/workflows/daily-tests.yml +0 -0
  14. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/.gitignore +0 -0
  15. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/CLAUDE.md +0 -0
  16. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/LICENSE +0 -0
  17. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/NOTICE +0 -0
  18. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/README.md +0 -0
  19. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/TODO.md +0 -0
  20. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/check.py +0 -0
  21. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/media/logo-orange-512h.webp +0 -0
  22. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/media/logo-orange-60h.webp +0 -0
  23. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/media/logo-silver-512h.webp +0 -0
  24. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/media/logo-silver-60h.webp +0 -0
  25. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/release.py +0 -0
  26. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/setup.cfg +0 -0
  27. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/src/pdfdancer/__init__.py +0 -0
  28. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/src/pdfdancer/exceptions.py +0 -0
  29. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/src/pdfdancer/fingerprint.py +0 -0
  30. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/src/pdfdancer/image_builder.py +0 -0
  31. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/src/pdfdancer/page_builder.py +0 -0
  32. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/src/pdfdancer/paragraph_builder.py +0 -0
  33. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/src/pdfdancer/path_builder.py +0 -0
  34. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/src/pdfdancer/pdfdancer_v1.py +0 -0
  35. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/src/pdfdancer/text_line_builder.py +0 -0
  36. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/src/pdfdancer_client_python.egg-info/SOURCES.txt +0 -0
  37. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/src/pdfdancer_client_python.egg-info/dependency_links.txt +0 -0
  38. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/src/pdfdancer_client_python.egg-info/requires.txt +0 -0
  39. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/src/pdfdancer_client_python.egg-info/top_level.txt +0 -0
  40. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/test.sh +0 -0
  41. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/__init__.py +0 -0
  42. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/conftest.py +0 -0
  43. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/__init__.py +0 -0
  44. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/pdf_assertions.py +0 -0
  45. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_acroform.py +0 -0
  46. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_bezier_builder.py +0 -0
  47. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_context_manager.py +0 -0
  48. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_form_x_objects.py +0 -0
  49. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_image.py +0 -0
  50. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_line.py +0 -0
  51. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_line_builder.py +0 -0
  52. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_new_pdf.py +0 -0
  53. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_page.py +0 -0
  54. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_paragraph.py +0 -0
  55. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_path.py +0 -0
  56. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_path_builder.py +0 -0
  57. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_path_builder_rectangle.py +0 -0
  58. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_path_comprehensive.py +0 -0
  59. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_pdfdancer.py +0 -0
  60. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_positioning.py +0 -0
  61. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_rectangle_builder.py +0 -0
  62. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_redact.py +0 -0
  63. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_singular_selection.py +0 -0
  64. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_snapshot.py +0 -0
  65. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_template_replace.py +0 -0
  66. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/e2e/test_text_line_edit.py +0 -0
  67. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/fixtures/DancingScript-Regular.ttf +0 -0
  68. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/fixtures/Empty.pdf +0 -0
  69. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/fixtures/JetBrainsMono-Regular.ttf +0 -0
  70. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/fixtures/Showcase.pdf +0 -0
  71. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/fixtures/basic-paths.pdf +0 -0
  72. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/fixtures/form-xobject-example.pdf +0 -0
  73. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/fixtures/logo-80.png +0 -0
  74. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/fixtures/mixed-form-types.pdf +0 -0
  75. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/test_anonymous_token.py +0 -0
  76. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/test_fingerprint.py +0 -0
  77. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/test_models.py +0 -0
  78. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/test_openapi_compliance.py +0 -0
  79. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/test_path_models.py +0 -0
  80. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/test_pdf_object_equality.py +0 -0
  81. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/test_rate_limit.py +0 -0
  82. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/tests/test_standard_fonts.py +0 -0
  83. {pdfdancer_client_python-0.3.8 → pdfdancer_client_python-0.3.9}/update-api-spec.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pdfdancer-client-python
3
- Version: 0.3.8
3
+ Version: 0.3.9
4
4
  Summary: Python client for PDFDancer API
5
5
  Author-email: "The Famous Cat Ltd." <hi@thefamouscat.com>
6
6
  License:
@@ -458,7 +458,7 @@ paths:
458
458
  description: removeTenantUser 200 response
459
459
  /config:
460
460
  get:
461
- operationId: findFont
461
+ operationId: getConfig
462
462
  parameters:
463
463
  - name: v
464
464
  in: query
@@ -482,7 +482,7 @@ paths:
482
482
  type: string
483
483
  responses:
484
484
  "200":
485
- description: findFont 200 response
485
+ description: getConfig 200 response
486
486
  content:
487
487
  application/json:
488
488
  schema:
@@ -2257,6 +2257,51 @@ paths:
2257
2257
  application/json:
2258
2258
  schema:
2259
2259
  $ref: "#/components/schemas/CommandResult"
2260
+ /pii/detect:
2261
+ post:
2262
+ operationId: detectPii
2263
+ parameters:
2264
+ - name: v
2265
+ in: query
2266
+ description: API version
2267
+ schema:
2268
+ type: string
2269
+ - name: api-version
2270
+ in: query
2271
+ description: API version
2272
+ schema:
2273
+ type: string
2274
+ - name: X-API-VERSION
2275
+ in: header
2276
+ description: API version
2277
+ schema:
2278
+ type: string
2279
+ - name: Accept-Version
2280
+ in: header
2281
+ description: API version
2282
+ schema:
2283
+ type: string
2284
+ requestBody:
2285
+ content:
2286
+ multipart/form-data:
2287
+ schema:
2288
+ type: object
2289
+ properties:
2290
+ pdf:
2291
+ type: string
2292
+ format: binary
2293
+ encoding:
2294
+ pdf:
2295
+ contentType: application/octet-stream
2296
+ explode: false
2297
+ required: true
2298
+ responses:
2299
+ "200":
2300
+ description: detectPii 200 response
2301
+ content:
2302
+ application/json:
2303
+ schema:
2304
+ $ref: "#/components/schemas/DocumentPiiResponse"
2260
2305
  /ping:
2261
2306
  get:
2262
2307
  operationId: index
@@ -3823,6 +3868,36 @@ components:
3823
3868
  type: string
3824
3869
  systemFontName:
3825
3870
  type: string
3871
+ DocumentPiiResponse:
3872
+ required:
3873
+ - errors
3874
+ - pageCount
3875
+ - paragraphsAnalyzed
3876
+ - paragraphsWithPii
3877
+ - results
3878
+ - totalEntities
3879
+ type: object
3880
+ properties:
3881
+ pageCount:
3882
+ type: integer
3883
+ format: int32
3884
+ paragraphsAnalyzed:
3885
+ type: integer
3886
+ format: int32
3887
+ paragraphsWithPii:
3888
+ type: integer
3889
+ format: int32
3890
+ totalEntities:
3891
+ type: integer
3892
+ format: int32
3893
+ results:
3894
+ type: array
3895
+ items:
3896
+ $ref: "#/components/schemas/ParagraphPiiResult"
3897
+ errors:
3898
+ type: array
3899
+ items:
3900
+ type: string
3826
3901
  DocumentSnapshot:
3827
3902
  required:
3828
3903
  - fonts
@@ -4041,6 +4116,26 @@ components:
4041
4116
  nullable: true
4042
4117
  allOf:
4043
4118
  - $ref: "#/components/schemas/ImageTransformRequest.FlipDirection"
4119
+ fillRegionX:
4120
+ type: integer
4121
+ format: int32
4122
+ nullable: true
4123
+ fillRegionY:
4124
+ type: integer
4125
+ format: int32
4126
+ nullable: true
4127
+ fillRegionWidth:
4128
+ type: integer
4129
+ format: int32
4130
+ nullable: true
4131
+ fillRegionHeight:
4132
+ type: integer
4133
+ format: int32
4134
+ nullable: true
4135
+ fillColor:
4136
+ type: integer
4137
+ format: int32
4138
+ nullable: true
4044
4139
  ImageTransformRequest.FlipDirection:
4045
4140
  type: string
4046
4141
  enum:
@@ -4056,6 +4151,7 @@ components:
4056
4151
  - CROP
4057
4152
  - OPACITY
4058
4153
  - FLIP
4154
+ - FILL_REGION
4059
4155
  JvmStatsService.BufferPoolStats:
4060
4156
  required:
4061
4157
  - count
@@ -4320,6 +4416,23 @@ components:
4320
4416
  $ref: "#/components/schemas/Point"
4321
4417
  objectType:
4322
4418
  $ref: "#/components/schemas/ObjectType"
4419
+ MatchedWord:
4420
+ required:
4421
+ - boundingBox
4422
+ - id
4423
+ - text
4424
+ - wordIndex
4425
+ type: object
4426
+ properties:
4427
+ id:
4428
+ type: string
4429
+ wordIndex:
4430
+ type: integer
4431
+ format: int32
4432
+ text:
4433
+ type: string
4434
+ boundingBox:
4435
+ $ref: "#/components/schemas/BoundingRect"
4323
4436
  MetricsBuffer.BufferStats:
4324
4437
  required:
4325
4438
  - configEnabled
@@ -4585,6 +4698,28 @@ components:
4585
4698
  $ref: "#/components/schemas/Font"
4586
4699
  text:
4587
4700
  type: string
4701
+ ParagraphPiiResult:
4702
+ required:
4703
+ - matches
4704
+ - pageIndex
4705
+ - paragraphId
4706
+ - position
4707
+ - text
4708
+ type: object
4709
+ properties:
4710
+ pageIndex:
4711
+ type: integer
4712
+ format: int32
4713
+ paragraphId:
4714
+ type: string
4715
+ text:
4716
+ type: string
4717
+ position:
4718
+ $ref: "#/components/schemas/Position"
4719
+ matches:
4720
+ type: array
4721
+ items:
4722
+ $ref: "#/components/schemas/PiiMatch"
4588
4723
  Path:
4589
4724
  type: object
4590
4725
  allOf:
@@ -4629,6 +4764,33 @@ components:
4629
4764
  oneOf:
4630
4765
  - $ref: "#/components/schemas/Line"
4631
4766
  - $ref: "#/components/schemas/Bezier"
4767
+ PiiMatch:
4768
+ required:
4769
+ - end
4770
+ - score
4771
+ - start
4772
+ - text
4773
+ - type
4774
+ - words
4775
+ type: object
4776
+ properties:
4777
+ type:
4778
+ type: string
4779
+ text:
4780
+ type: string
4781
+ start:
4782
+ type: integer
4783
+ format: int32
4784
+ end:
4785
+ type: integer
4786
+ format: int32
4787
+ score:
4788
+ type: number
4789
+ format: double
4790
+ words:
4791
+ type: array
4792
+ items:
4793
+ $ref: "#/components/schemas/MatchedWord"
4632
4794
  Point:
4633
4795
  required:
4634
4796
  - x
@@ -458,7 +458,7 @@ paths:
458
458
  description: removeTenantUser 200 response
459
459
  /config:
460
460
  get:
461
- operationId: findFont
461
+ operationId: getConfig
462
462
  parameters:
463
463
  - name: v
464
464
  in: query
@@ -482,7 +482,7 @@ paths:
482
482
  type: string
483
483
  responses:
484
484
  "200":
485
- description: findFont 200 response
485
+ description: getConfig 200 response
486
486
  content:
487
487
  application/json:
488
488
  schema:
@@ -2257,6 +2257,51 @@ paths:
2257
2257
  application/json:
2258
2258
  schema:
2259
2259
  $ref: "#/components/schemas/CommandResult"
2260
+ /pii/detect:
2261
+ post:
2262
+ operationId: detectPii
2263
+ parameters:
2264
+ - name: v
2265
+ in: query
2266
+ description: API version
2267
+ schema:
2268
+ type: string
2269
+ - name: api-version
2270
+ in: query
2271
+ description: API version
2272
+ schema:
2273
+ type: string
2274
+ - name: X-API-VERSION
2275
+ in: header
2276
+ description: API version
2277
+ schema:
2278
+ type: string
2279
+ - name: Accept-Version
2280
+ in: header
2281
+ description: API version
2282
+ schema:
2283
+ type: string
2284
+ requestBody:
2285
+ content:
2286
+ multipart/form-data:
2287
+ schema:
2288
+ type: object
2289
+ properties:
2290
+ pdf:
2291
+ type: string
2292
+ format: binary
2293
+ encoding:
2294
+ pdf:
2295
+ contentType: application/octet-stream
2296
+ explode: false
2297
+ required: true
2298
+ responses:
2299
+ "200":
2300
+ description: detectPii 200 response
2301
+ content:
2302
+ application/json:
2303
+ schema:
2304
+ $ref: "#/components/schemas/DocumentPiiResponse"
2260
2305
  /ping:
2261
2306
  get:
2262
2307
  operationId: index
@@ -2723,16 +2768,10 @@ paths:
2723
2768
  $ref: "#/components/schemas/SubscriptionController.SubscriptionStatus"
2724
2769
  /template/replace:
2725
2770
  post:
2726
- summary: Performs batch template placeholder replacements in a PDF document.
2727
- description: "Performs batch template placeholder replacements in a PDF document.\
2728
- \ This operation finds exact text matches for placeholders and replaces them\
2729
- \ with specified content, optionally with formatting overrides. All placeholders\
2730
- \ must be found or the operation fails atomically."
2731
2771
  operationId: replaceTemplates
2732
2772
  parameters:
2733
2773
  - name: X-Session-Id
2734
2774
  in: header
2735
- description: unique identifier for the user session containing the PDF
2736
2775
  required: true
2737
2776
  schema:
2738
2777
  type: string
@@ -2757,7 +2796,6 @@ paths:
2757
2796
  schema:
2758
2797
  type: string
2759
2798
  requestBody:
2760
- description: replacement specifications including placeholders and new text
2761
2799
  content:
2762
2800
  application/json:
2763
2801
  schema:
@@ -2765,7 +2803,7 @@ paths:
2765
2803
  required: true
2766
2804
  responses:
2767
2805
  "200":
2768
- description: HTTP response indicating success or failure with error details
2806
+ description: replaceTemplates 200 response
2769
2807
  content:
2770
2808
  application/json:
2771
2809
  schema:
@@ -3841,6 +3879,36 @@ components:
3841
3879
  type: string
3842
3880
  systemFontName:
3843
3881
  type: string
3882
+ DocumentPiiResponse:
3883
+ required:
3884
+ - errors
3885
+ - pageCount
3886
+ - paragraphsAnalyzed
3887
+ - paragraphsWithPii
3888
+ - results
3889
+ - totalEntities
3890
+ type: object
3891
+ properties:
3892
+ pageCount:
3893
+ type: integer
3894
+ format: int32
3895
+ paragraphsAnalyzed:
3896
+ type: integer
3897
+ format: int32
3898
+ paragraphsWithPii:
3899
+ type: integer
3900
+ format: int32
3901
+ totalEntities:
3902
+ type: integer
3903
+ format: int32
3904
+ results:
3905
+ type: array
3906
+ items:
3907
+ $ref: "#/components/schemas/ParagraphPiiResult"
3908
+ errors:
3909
+ type: array
3910
+ items:
3911
+ type: string
3844
3912
  DocumentSnapshot:
3845
3913
  required:
3846
3914
  - fonts
@@ -4077,6 +4145,26 @@ components:
4077
4145
  nullable: true
4078
4146
  allOf:
4079
4147
  - $ref: "#/components/schemas/ImageTransformRequest.FlipDirection"
4148
+ fillRegionX:
4149
+ type: integer
4150
+ format: int32
4151
+ nullable: true
4152
+ fillRegionY:
4153
+ type: integer
4154
+ format: int32
4155
+ nullable: true
4156
+ fillRegionWidth:
4157
+ type: integer
4158
+ format: int32
4159
+ nullable: true
4160
+ fillRegionHeight:
4161
+ type: integer
4162
+ format: int32
4163
+ nullable: true
4164
+ fillColor:
4165
+ type: integer
4166
+ format: int32
4167
+ nullable: true
4080
4168
  ImageTransformRequest.FlipDirection:
4081
4169
  type: string
4082
4170
  enum:
@@ -4092,6 +4180,7 @@ components:
4092
4180
  - CROP
4093
4181
  - OPACITY
4094
4182
  - FLIP
4183
+ - FILL_REGION
4095
4184
  JvmStatsService.BufferPoolStats:
4096
4185
  required:
4097
4186
  - count
@@ -4356,6 +4445,23 @@ components:
4356
4445
  $ref: "#/components/schemas/Point"
4357
4446
  objectType:
4358
4447
  $ref: "#/components/schemas/ObjectType"
4448
+ MatchedWord:
4449
+ required:
4450
+ - boundingBox
4451
+ - id
4452
+ - text
4453
+ - wordIndex
4454
+ type: object
4455
+ properties:
4456
+ id:
4457
+ type: string
4458
+ wordIndex:
4459
+ type: integer
4460
+ format: int32
4461
+ text:
4462
+ type: string
4463
+ boundingBox:
4464
+ $ref: "#/components/schemas/BoundingRect"
4359
4465
  MetricsBuffer.BufferStats:
4360
4466
  required:
4361
4467
  - configEnabled
@@ -4638,6 +4744,28 @@ components:
4638
4744
  $ref: "#/components/schemas/Font"
4639
4745
  text:
4640
4746
  type: string
4747
+ ParagraphPiiResult:
4748
+ required:
4749
+ - matches
4750
+ - pageIndex
4751
+ - paragraphId
4752
+ - position
4753
+ - text
4754
+ type: object
4755
+ properties:
4756
+ pageIndex:
4757
+ type: integer
4758
+ format: int32
4759
+ paragraphId:
4760
+ type: string
4761
+ text:
4762
+ type: string
4763
+ position:
4764
+ $ref: "#/components/schemas/Position"
4765
+ matches:
4766
+ type: array
4767
+ items:
4768
+ $ref: "#/components/schemas/PiiMatch"
4641
4769
  Path:
4642
4770
  type: object
4643
4771
  allOf:
@@ -4682,6 +4810,33 @@ components:
4682
4810
  oneOf:
4683
4811
  - $ref: "#/components/schemas/Line"
4684
4812
  - $ref: "#/components/schemas/Bezier"
4813
+ PiiMatch:
4814
+ required:
4815
+ - end
4816
+ - score
4817
+ - start
4818
+ - text
4819
+ - type
4820
+ - words
4821
+ type: object
4822
+ properties:
4823
+ type:
4824
+ type: string
4825
+ text:
4826
+ type: string
4827
+ start:
4828
+ type: integer
4829
+ format: int32
4830
+ end:
4831
+ type: integer
4832
+ format: int32
4833
+ score:
4834
+ type: number
4835
+ format: double
4836
+ words:
4837
+ type: array
4838
+ items:
4839
+ $ref: "#/components/schemas/MatchedWord"
4685
4840
  Point:
4686
4841
  required:
4687
4842
  - x
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pdfdancer-client-python"
7
- version = "0.3.8"
7
+ version = "0.3.9"
8
8
  description = "Python client for PDFDancer API"
9
9
  readme = "README.md"
10
10
  authors = [
@@ -1652,6 +1652,7 @@ class ImageTransformType(Enum):
1652
1652
  CROP = "CROP"
1653
1653
  OPACITY = "OPACITY"
1654
1654
  FLIP = "FLIP"
1655
+ FILL_REGION = "FILL_REGION"
1655
1656
 
1656
1657
 
1657
1658
  class ImageFlipDirection(Enum):
@@ -1781,6 +1782,11 @@ class ImageTransformRequest:
1781
1782
  crop_bottom: Optional[int] = None
1782
1783
  opacity: Optional[float] = None
1783
1784
  flip_direction: Optional[ImageFlipDirection] = None
1785
+ fill_region_x: Optional[int] = None
1786
+ fill_region_y: Optional[int] = None
1787
+ fill_region_width: Optional[int] = None
1788
+ fill_region_height: Optional[int] = None
1789
+ fill_color: Optional[int] = None
1784
1790
 
1785
1791
  def to_dict(self) -> dict:
1786
1792
  """Convert to dictionary for JSON serialization."""
@@ -1836,4 +1842,19 @@ class ImageTransformRequest:
1836
1842
  if self.flip_direction is not None:
1837
1843
  result["flipDirection"] = self.flip_direction.value
1838
1844
 
1845
+ if self.fill_region_x is not None:
1846
+ result["fillRegionX"] = self.fill_region_x
1847
+
1848
+ if self.fill_region_y is not None:
1849
+ result["fillRegionY"] = self.fill_region_y
1850
+
1851
+ if self.fill_region_width is not None:
1852
+ result["fillRegionWidth"] = self.fill_region_width
1853
+
1854
+ if self.fill_region_height is not None:
1855
+ result["fillRegionHeight"] = self.fill_region_height
1856
+
1857
+ if self.fill_color is not None:
1858
+ result["fillColor"] = self.fill_color
1859
+
1839
1860
  return result
@@ -8,7 +8,7 @@ from . import FormFieldRef, ObjectRef, ObjectType, Point, Position, TextObjectRe
8
8
  from .exceptions import ValidationException
9
9
 
10
10
  if TYPE_CHECKING:
11
- from .models import CommandResult, Image, ImageFlipDirection
11
+ from .models import Color, CommandResult, Image, ImageFlipDirection
12
12
  from .pdfdancer_v1 import PDFDancer
13
13
 
14
14
 
@@ -244,6 +244,44 @@ class ImageObject(PDFObjectBase):
244
244
  )
245
245
  return self._client._transform_image(request)
246
246
 
247
+ def fill_region(
248
+ self, x: int, y: int, width: int, height: int, color: "Color"
249
+ ) -> "CommandResult":
250
+ """Fill a rectangular region within this image with a solid color.
251
+
252
+ Args:
253
+ x: X coordinate of the region (pixels from left edge of image)
254
+ y: Y coordinate of the region (pixels from top edge of image)
255
+ width: Width of the region in pixels
256
+ height: Height of the region in pixels
257
+ color: Fill color as a Color object (alpha channel is ignored)
258
+
259
+ Returns:
260
+ CommandResult indicating success or failure
261
+ """
262
+ from .models import Color, ImageTransformRequest, ImageTransformType
263
+
264
+ if not isinstance(color, Color):
265
+ raise ValidationException("color must be a Color object")
266
+ if width <= 0:
267
+ raise ValidationException(f"width must be positive, got {width}")
268
+ if height <= 0:
269
+ raise ValidationException(f"height must be positive, got {height}")
270
+
271
+ # Convert Color to integer: 0xRRGGBB format (RGB only, no alpha)
272
+ fill_color_int = (color.r << 16) | (color.g << 8) | color.b
273
+
274
+ request = ImageTransformRequest(
275
+ object_ref=self.object_ref(),
276
+ transform_type=ImageTransformType.FILL_REGION,
277
+ fill_region_x=x,
278
+ fill_region_y=y,
279
+ fill_region_width=width,
280
+ fill_region_height=height,
281
+ fill_color=fill_color_int,
282
+ )
283
+ return self._client._transform_image(request)
284
+
247
285
  def __eq__(self, other):
248
286
  if not isinstance(other, ImageObject):
249
287
  return False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pdfdancer-client-python
3
- Version: 0.3.8
3
+ Version: 0.3.9
4
4
  Summary: Python client for PDFDancer API
5
5
  Author-email: "The Famous Cat Ltd." <hi@thefamouscat.com>
6
6
  License:
@@ -2,7 +2,7 @@ from pathlib import Path
2
2
 
3
3
  import pytest
4
4
 
5
- from pdfdancer import Image, ImageFlipDirection, ObjectType, ValidationException
5
+ from pdfdancer import Color, Image, ImageFlipDirection, ObjectType, ValidationException
6
6
  from pdfdancer.pdfdancer_v1 import PDFDancer
7
7
  from tests.e2e import _require_env_and_fixture
8
8
  from tests.e2e.pdf_assertions import PDFAssertions
@@ -562,3 +562,123 @@ class TestImageTransformChaining:
562
562
  assertions.assert_image_size(
563
563
  image_id, original_width, original_height, epsilon=2.0
564
564
  )
565
+
566
+
567
+ class TestImageFillRegion:
568
+ def test_fill_region_basic(self):
569
+ """Test filling a region within an image with a solid color."""
570
+ base_url, token, pdf_path = _require_env_and_fixture("Showcase.pdf")
571
+
572
+ with PDFDancer.open(
573
+ pdf_path, token=token, base_url=base_url, timeout=30.0
574
+ ) as pdf:
575
+ images = pdf.select_images()
576
+ assert len(images) > 0
577
+
578
+ image = images[0]
579
+ image_id = image.internal_id
580
+ page_num = image.position.page_number
581
+
582
+ # Fill a region with black color
583
+ result = image.fill_region(
584
+ x=10, y=10, width=50, height=30, color=Color(0, 0, 0)
585
+ )
586
+ assert result.success, f"Fill region failed: {result.message}"
587
+
588
+ # Verify image still exists
589
+ assertions = PDFAssertions(pdf)
590
+ image_after = assertions.get_image_by_id(image_id, page_num)
591
+ assert image_after is not None
592
+
593
+ def test_fill_region_with_red_color(self):
594
+ """Test filling a region with red color."""
595
+ base_url, token, pdf_path = _require_env_and_fixture("Showcase.pdf")
596
+
597
+ with PDFDancer.open(
598
+ pdf_path, token=token, base_url=base_url, timeout=30.0
599
+ ) as pdf:
600
+ images = pdf.select_images()
601
+ image = images[0]
602
+ image_id = image.internal_id
603
+ page_num = image.position.page_number
604
+
605
+ result = image.fill_region(
606
+ x=0, y=0, width=5, height=5, color=Color(255, 0, 0)
607
+ )
608
+ assert result.success, f"Fill region failed: {result.message}"
609
+
610
+ # Verify image still exists
611
+ assertions = PDFAssertions(pdf)
612
+ image_after = assertions.get_image_by_id(image_id, page_num)
613
+ assert image_after is not None
614
+
615
+ def test_fill_region_with_different_colors(self):
616
+ """Test fill_region with various colors."""
617
+ base_url, token, pdf_path = _require_env_and_fixture("Showcase.pdf")
618
+
619
+ with PDFDancer.open(
620
+ pdf_path, token=token, base_url=base_url, timeout=30.0
621
+ ) as pdf:
622
+ images = pdf.select_images()
623
+ image = images[0]
624
+ image_id = image.internal_id
625
+ page_num = image.position.page_number
626
+
627
+ # Test with white
628
+ result = image.fill_region(
629
+ x=0, y=0, width=10, height=10, color=Color(255, 255, 255)
630
+ )
631
+ assert result.success, f"Fill with white failed: {result.message}"
632
+
633
+ # Re-select image after transform
634
+ images = pdf.select_images()
635
+ image = next(i for i in images if i.internal_id == image_id)
636
+
637
+ # Test with blue
638
+ result = image.fill_region(
639
+ x=20, y=20, width=15, height=15, color=Color(0, 0, 255)
640
+ )
641
+ assert result.success, f"Fill with blue failed: {result.message}"
642
+
643
+ assertions = PDFAssertions(pdf)
644
+ image_after = assertions.get_image_by_id(image_id, page_num)
645
+ assert image_after is not None
646
+
647
+ def test_fill_region_invalid_width_raises_error(self):
648
+ """Test that width <= 0 raises ValidationException."""
649
+ base_url, token, pdf_path = _require_env_and_fixture("Showcase.pdf")
650
+
651
+ with PDFDancer.open(
652
+ pdf_path, token=token, base_url=base_url, timeout=30.0
653
+ ) as pdf:
654
+ images = pdf.select_images()
655
+ image = images[0]
656
+
657
+ with pytest.raises(ValidationException):
658
+ image.fill_region(x=0, y=0, width=0, height=10, color=Color(0, 0, 0))
659
+
660
+ def test_fill_region_invalid_height_raises_error(self):
661
+ """Test that height <= 0 raises ValidationException."""
662
+ base_url, token, pdf_path = _require_env_and_fixture("Showcase.pdf")
663
+
664
+ with PDFDancer.open(
665
+ pdf_path, token=token, base_url=base_url, timeout=30.0
666
+ ) as pdf:
667
+ images = pdf.select_images()
668
+ image = images[0]
669
+
670
+ with pytest.raises(ValidationException):
671
+ image.fill_region(x=0, y=0, width=10, height=-5, color=Color(0, 0, 0))
672
+
673
+ def test_fill_region_invalid_color_type_raises_error(self):
674
+ """Test that non-Color object raises ValidationException."""
675
+ base_url, token, pdf_path = _require_env_and_fixture("Showcase.pdf")
676
+
677
+ with PDFDancer.open(
678
+ pdf_path, token=token, base_url=base_url, timeout=30.0
679
+ ) as pdf:
680
+ images = pdf.select_images()
681
+ image = images[0]
682
+
683
+ with pytest.raises(ValidationException):
684
+ image.fill_region(x=0, y=0, width=10, height=10, color=0xFF0000)