@mohasinac/appkit 4.52.5 → 4.53.0
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.
- package/dist/.build-stamp.json +4 -4
- package/dist/_internal/client/features/sticker-trace/canvas-codec.d.ts +2 -0
- package/dist/_internal/client/features/sticker-trace/canvas-codec.js +148 -0
- package/dist/_internal/server/features/auctions/actions.js +1 -1
- package/dist/_internal/server/features/categories/data.js +23 -7
- package/dist/_internal/server/features/checkout/actions.js +10 -3
- package/dist/_internal/server/features/checkout/data.d.ts +15 -0
- package/dist/_internal/server/features/checkout/data.js +20 -3
- package/dist/_internal/server/features/lottery/actions.js +9 -1
- package/dist/_internal/server/features/lottery/og.d.ts +40 -0
- package/dist/_internal/server/features/lottery/og.js +79 -0
- package/dist/_internal/server/features/messages/actions.js +4 -0
- package/dist/_internal/server/features/offers/adapters.js +17 -3
- package/dist/_internal/server/features/orders/actions.js +7 -2
- package/dist/_internal/server/features/raffle/actions.d.ts +19 -0
- package/dist/_internal/server/features/raffle/actions.js +25 -0
- package/dist/_internal/server/features/reviews/actions.js +1 -1
- package/dist/_internal/server/features/reviews/data.d.ts +1 -1
- package/dist/_internal/server/features/search/index-build/artifact-store.d.ts +89 -0
- package/dist/_internal/server/features/search/index-build/artifact-store.js +208 -0
- package/dist/_internal/server/features/search/index-build/build.d.ts +57 -0
- package/dist/_internal/server/features/search/index-build/build.js +285 -0
- package/dist/_internal/server/features/search/index-build/sources.d.ts +53 -0
- package/dist/_internal/server/features/search/index-build/sources.js +385 -0
- package/dist/_internal/server/features/search/search-sources.d.ts +0 -15
- package/dist/_internal/server/features/search/search-sources.js +142 -7
- package/dist/_internal/server/features/seo/robots.js +21 -1
- package/dist/_internal/server/features/seo/sitemap.js +1 -1
- package/dist/_internal/server/features/shared/listing-data-factory.js +16 -4
- package/dist/_internal/server/features/site-settings/adapters.d.ts +1 -1
- package/dist/_internal/server/features/site-settings/adapters.js +26 -0
- package/dist/_internal/server/features/sticker-trace/actions.d.ts +109 -0
- package/dist/_internal/server/features/sticker-trace/actions.js +172 -0
- package/dist/_internal/server/features/sticker-trace/adapters.d.ts +80 -0
- package/dist/_internal/server/features/sticker-trace/adapters.js +174 -0
- package/dist/_internal/server/features/sticker-trace/build-cut-file.d.ts +26 -0
- package/dist/_internal/server/features/sticker-trace/build-cut-file.js +127 -0
- package/dist/_internal/server/features/sticker-trace/coordinator.d.ts +27 -0
- package/dist/_internal/server/features/sticker-trace/coordinator.js +169 -0
- package/dist/_internal/server/features/sticker-trace/fanout.d.ts +43 -0
- package/dist/_internal/server/features/sticker-trace/fanout.js +180 -0
- package/dist/_internal/server/features/sticker-trace/finalizer.d.ts +25 -0
- package/dist/_internal/server/features/sticker-trace/finalizer.js +123 -0
- package/dist/_internal/server/features/sticker-trace/mosaic-inputs.d.ts +30 -0
- package/dist/_internal/server/features/sticker-trace/mosaic-inputs.js +112 -0
- package/dist/_internal/server/features/sticker-trace/progress.d.ts +81 -0
- package/dist/_internal/server/features/sticker-trace/progress.js +198 -0
- package/dist/_internal/server/features/sticker-trace/promote.d.ts +23 -0
- package/dist/_internal/server/features/sticker-trace/promote.js +193 -0
- package/dist/_internal/server/features/sticker-trace/shard.d.ts +50 -0
- package/dist/_internal/server/features/sticker-trace/shard.js +174 -0
- package/dist/_internal/server/features/sticker-trace/sheet-actions.d.ts +141 -0
- package/dist/_internal/server/features/sticker-trace/sheet-actions.js +279 -0
- package/dist/_internal/server/features/sticker-trace/storage.d.ts +135 -0
- package/dist/_internal/server/features/sticker-trace/storage.js +282 -0
- package/dist/_internal/server/functions/scheduled.d.ts +2 -1
- package/dist/_internal/server/functions/scheduled.js +25 -1
- package/dist/_internal/server/jobs/core/_event-ref.d.ts +51 -0
- package/dist/_internal/server/jobs/core/_event-ref.js +63 -0
- package/dist/_internal/server/jobs/core/assignSpinPrize.d.ts +18 -0
- package/dist/_internal/server/jobs/core/assignSpinPrize.js +77 -16
- package/dist/_internal/server/jobs/core/auctionSettlement.js +13 -4
- package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +44 -15
- package/dist/_internal/server/jobs/core/bundleStockSync.js +3 -4
- package/dist/_internal/server/jobs/core/cleanupRtdbEvents.js +44 -0
- package/dist/_internal/server/jobs/core/event-draw-reasons.d.ts +78 -0
- package/dist/_internal/server/jobs/core/event-draw-reasons.js +133 -0
- package/dist/_internal/server/jobs/core/listingProcessor.js +28 -8
- package/dist/_internal/server/jobs/core/onOrderCreate.js +12 -1
- package/dist/_internal/server/jobs/core/onScamReportCreate.js +13 -2
- package/dist/_internal/server/jobs/core/onScamReportRejected.js +8 -2
- package/dist/_internal/server/jobs/core/onScamReportVerified.js +8 -2
- package/dist/_internal/server/jobs/core/onStoreWrite.js +11 -4
- package/dist/_internal/server/jobs/core/prizeDrawAssignWinner.js +5 -4
- package/dist/_internal/server/jobs/core/prizeDrawExpiryReveal.js +1 -4
- package/dist/_internal/server/jobs/core/prizeDrawSoldOutReveal.js +1 -2
- package/dist/_internal/server/jobs/core/promotions.js +7 -4
- package/dist/_internal/server/jobs/core/searchIndexBuild.d.ts +7 -0
- package/dist/_internal/server/jobs/core/searchIndexBuild.js +211 -0
- package/dist/_internal/server/jobs/core/triggerEventRaffle.d.ts +35 -0
- package/dist/_internal/server/jobs/core/triggerEventRaffle.js +213 -31
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +20 -14
- package/dist/_internal/server/jobs/handlers/assignSpinPrize.d.ts +8 -0
- package/dist/_internal/server/jobs/handlers/assignSpinPrize.js +15 -15
- package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
- package/dist/_internal/server/jobs/handlers/index.js +1 -0
- package/dist/_internal/server/jobs/handlers/onCategoryWrite.js +18 -0
- package/dist/_internal/server/jobs/handlers/onProductWrite.js +18 -0
- package/dist/_internal/server/jobs/handlers/onReviewWrite.js +18 -0
- package/dist/_internal/server/jobs/handlers/onScamReportUpdate.js +18 -0
- package/dist/_internal/server/jobs/handlers/onStoreWrite.js +18 -0
- package/dist/_internal/server/jobs/handlers/searchIndexBuild.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/searchIndexBuild.js +2 -0
- package/dist/_internal/server/jobs/handlers/triggerEventRaffle.d.ts +8 -0
- package/dist/_internal/server/jobs/handlers/triggerEventRaffle.js +15 -6
- package/dist/_internal/shared/actions/action-registry.js +29 -0
- package/dist/_internal/shared/cache/revalidate-targets.d.ts +0 -1
- package/dist/_internal/shared/cache/revalidate-targets.js +10 -8
- package/dist/_internal/shared/features/events/config.d.ts +14 -0
- package/dist/_internal/shared/features/events/config.js +14 -0
- package/dist/_internal/shared/features/notifications/action-url.js +8 -0
- package/dist/_internal/shared/features/site-settings/types.d.ts +11 -0
- package/dist/_internal/shared/features/sticker-trace/codec.d.ts +81 -0
- package/dist/_internal/shared/features/sticker-trace/codec.js +30 -0
- package/dist/_internal/shared/features/sticker-trace/config.d.ts +81 -0
- package/dist/_internal/shared/features/sticker-trace/config.js +177 -0
- package/dist/_internal/shared/features/sticker-trace/cut-contour.d.ts +20 -0
- package/dist/_internal/shared/features/sticker-trace/cut-contour.js +60 -0
- package/dist/_internal/shared/features/sticker-trace/export/build-export-set.d.ts +65 -0
- package/dist/_internal/shared/features/sticker-trace/export/build-export-set.js +176 -0
- package/dist/_internal/shared/features/sticker-trace/export/cut-svg.d.ts +56 -0
- package/dist/_internal/shared/features/sticker-trace/export/cut-svg.js +120 -0
- package/dist/_internal/shared/features/sticker-trace/export/machine-profiles.d.ts +92 -0
- package/dist/_internal/shared/features/sticker-trace/export/machine-profiles.js +153 -0
- package/dist/_internal/shared/features/sticker-trace/export/nesting.d.ts +51 -0
- package/dist/_internal/shared/features/sticker-trace/export/nesting.js +110 -0
- package/dist/_internal/shared/features/sticker-trace/export/page-sizes.d.ts +68 -0
- package/dist/_internal/shared/features/sticker-trace/export/page-sizes.js +223 -0
- package/dist/_internal/shared/features/sticker-trace/export/part-tiling.d.ts +51 -0
- package/dist/_internal/shared/features/sticker-trace/export/part-tiling.js +178 -0
- package/dist/_internal/shared/features/sticker-trace/export/simplify-budget.d.ts +26 -0
- package/dist/_internal/shared/features/sticker-trace/export/simplify-budget.js +134 -0
- package/dist/_internal/shared/features/sticker-trace/export/vectorise-art.d.ts +40 -0
- package/dist/_internal/shared/features/sticker-trace/export/vectorise-art.js +195 -0
- package/dist/_internal/shared/features/sticker-trace/index.d.ts +2 -0
- package/dist/_internal/shared/features/sticker-trace/index.js +59 -0
- package/dist/_internal/shared/features/sticker-trace/math/catmull-rom.d.ts +11 -0
- package/dist/_internal/shared/features/sticker-trace/math/catmull-rom.js +66 -0
- package/dist/_internal/shared/features/sticker-trace/math/edt.d.ts +27 -0
- package/dist/_internal/shared/features/sticker-trace/math/edt.js +165 -0
- package/dist/_internal/shared/features/sticker-trace/math/label.d.ts +15 -0
- package/dist/_internal/shared/features/sticker-trace/math/label.js +156 -0
- package/dist/_internal/shared/features/sticker-trace/math/marching-squares.d.ts +16 -0
- package/dist/_internal/shared/features/sticker-trace/math/marching-squares.js +242 -0
- package/dist/_internal/shared/features/sticker-trace/math/morphology.d.ts +46 -0
- package/dist/_internal/shared/features/sticker-trace/math/morphology.js +168 -0
- package/dist/_internal/shared/features/sticker-trace/math/rasterize-path.d.ts +88 -0
- package/dist/_internal/shared/features/sticker-trace/math/rasterize-path.js +286 -0
- package/dist/_internal/shared/features/sticker-trace/math/rdp.d.ts +10 -0
- package/dist/_internal/shared/features/sticker-trace/math/rdp.js +74 -0
- package/dist/_internal/shared/features/sticker-trace/resume.d.ts +50 -0
- package/dist/_internal/shared/features/sticker-trace/resume.js +160 -0
- package/dist/_internal/shared/features/sticker-trace/trace/cluster.d.ts +20 -0
- package/dist/_internal/shared/features/sticker-trace/trace/cluster.js +132 -0
- package/dist/_internal/shared/features/sticker-trace/trace/cross-profile.d.ts +28 -0
- package/dist/_internal/shared/features/sticker-trace/trace/cross-profile.js +120 -0
- package/dist/_internal/shared/features/sticker-trace/trace/flood.d.ts +21 -0
- package/dist/_internal/shared/features/sticker-trace/trace/flood.js +104 -0
- package/dist/_internal/shared/features/sticker-trace/trace/geometry.d.ts +3 -0
- package/dist/_internal/shared/features/sticker-trace/trace/geometry.js +140 -0
- package/dist/_internal/shared/features/sticker-trace/trace/line-filter.d.ts +15 -0
- package/dist/_internal/shared/features/sticker-trace/trace/line-filter.js +138 -0
- package/dist/_internal/shared/features/sticker-trace/trace/merge.d.ts +27 -0
- package/dist/_internal/shared/features/sticker-trace/trace/merge.js +187 -0
- package/dist/_internal/shared/features/sticker-trace/trace/paper.d.ts +32 -0
- package/dist/_internal/shared/features/sticker-trace/trace/paper.js +147 -0
- package/dist/_internal/shared/features/sticker-trace/trace/prefilter.d.ts +30 -0
- package/dist/_internal/shared/features/sticker-trace/trace/prefilter.js +125 -0
- package/dist/_internal/shared/features/sticker-trace/trace/quantise.d.ts +10 -0
- package/dist/_internal/shared/features/sticker-trace/trace/quantise.js +153 -0
- package/dist/_internal/shared/features/sticker-trace/trace/ridge.d.ts +88 -0
- package/dist/_internal/shared/features/sticker-trace/trace/ridge.js +344 -0
- package/dist/_internal/shared/features/sticker-trace/trace/segment.d.ts +10 -0
- package/dist/_internal/shared/features/sticker-trace/trace/segment.js +251 -0
- package/dist/_internal/shared/features/sticker-trace/types.d.ts +197 -0
- package/dist/_internal/shared/features/sticker-trace/types.js +49 -0
- package/dist/_internal/shared/listing-types/_registry.d.ts +11 -0
- package/dist/_internal/shared/listing-types/art/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/art/config.js +1 -0
- package/dist/_internal/shared/listing-types/auction/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/auction/config.js +1 -0
- package/dist/_internal/shared/listing-types/classified/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/classified/config.js +1 -0
- package/dist/_internal/shared/listing-types/digital-code/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/digital-code/config.js +1 -0
- package/dist/_internal/shared/listing-types/feature-flags.d.ts +7 -0
- package/dist/_internal/shared/listing-types/feature-flags.js +9 -0
- package/dist/_internal/shared/listing-types/live/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/live/config.js +1 -0
- package/dist/_internal/shared/listing-types/pre-order/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/pre-order/config.js +1 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.js +1 -0
- package/dist/_internal/shared/listing-types/standard/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/standard/config.js +1 -0
- package/dist/_internal/shared/listing-types/stickers/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/stickers/config.js +1 -0
- package/dist/_internal/shared/media/limits.d.ts +12 -2
- package/dist/_internal/shared/media/limits.js +12 -2
- package/dist/_internal/shared/search/artifact-url.d.ts +35 -0
- package/dist/_internal/shared/search/artifact-url.js +119 -0
- package/dist/_internal/shared/search/index-record.d.ts +68 -0
- package/dist/_internal/shared/search/index-record.js +96 -0
- package/dist/_internal/shared/search/match.d.ts +65 -0
- package/dist/_internal/shared/search/match.js +263 -0
- package/dist/client.d.ts +8 -7
- package/dist/client.js +12 -5
- package/dist/configs/eslint.js +22 -2
- package/dist/constants/api-endpoints.d.ts +68 -0
- package/dist/constants/api-endpoints.js +32 -0
- package/dist/constants/field-names.d.ts +7 -1
- package/dist/constants/field-names.js +36 -1
- package/dist/contracts/repository.d.ts +8 -7
- package/dist/contracts/search.d.ts +2 -2
- package/dist/contracts/table.d.ts +3 -3
- package/dist/contracts/table.js +3 -3
- package/dist/core/contact-submissions.repository.js +2 -2
- package/dist/core/integration-keys.js +7 -1
- package/dist/core/newsletter.repository.js +2 -2
- package/dist/core/site-config.js +1 -1
- package/dist/errors/error-codes.d.ts +30 -0
- package/dist/errors/error-codes.js +30 -0
- package/dist/errors/error-display-map.js +40 -1
- package/dist/features/account/api/[userId]/addresses/route.js +1 -1
- package/dist/features/account/components/UserBidsView.js +1 -1
- package/dist/features/account/components/index.d.ts +0 -8
- package/dist/features/account/components/index.js +0 -4
- package/dist/features/addresses/repository/addresses.repository.d.ts +17 -6
- package/dist/features/addresses/repository/addresses.repository.js +65 -9
- package/dist/features/addresses/schemas/firestore.d.ts +17 -6
- package/dist/features/admin/actions/notification-actions.js +15 -6
- package/dist/features/admin/api/bids/route.js +1 -1
- package/dist/features/admin/api/coupons/route.js +1 -1
- package/dist/features/admin/api/products/route.js +1 -1
- package/dist/features/admin/api/reviews/route.js +1 -1
- package/dist/features/admin/components/AdminAdEditorView.js +19 -5
- package/dist/features/admin/components/AdminAuditLogView.js +1 -1
- package/dist/features/admin/components/AdminBlogEditorView.js +0 -1
- package/dist/features/admin/components/AdminBlogView.js +1 -1
- package/dist/features/admin/components/AdminBrandsView.js +17 -1
- package/dist/features/admin/components/AdminCategoryEditorView.js +0 -1
- package/dist/features/admin/components/AdminContactView.js +1 -1
- package/dist/features/admin/components/AdminEmployeeEditorView.js +1 -3
- package/dist/features/admin/components/AdminNewsletterView.js +1 -1
- package/dist/features/admin/components/AdminOrdersView.js +9 -2
- package/dist/features/admin/components/AdminPayoutsView.js +1 -1
- package/dist/features/admin/components/AdminPrizeDrawsView.js +11 -0
- package/dist/features/admin/components/AdminProductEditorView.d.ts +10 -1
- package/dist/features/admin/components/AdminProductEditorView.js +24 -37
- package/dist/features/admin/components/AdminProductsView.js +10 -3
- package/dist/features/admin/components/AdminScammersView.js +1 -1
- package/dist/features/admin/components/AdminSectionsView.js +21 -5
- package/dist/features/admin/components/AdminSessionsView.js +1 -1
- package/dist/features/admin/components/AdminSublistingCategoriesView.js +22 -1
- package/dist/features/admin/components/AdminTeamView.js +1 -1
- package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +0 -1
- package/dist/features/admin/components/AdminUsersView.js +1 -1
- package/dist/features/admin/components/DataListingView.d.ts +2 -1
- package/dist/features/admin/components/DataListingView.js +9 -4
- package/dist/features/admin/components/analytics/AdminPageViewsReportView.js +0 -2
- package/dist/features/admin/hooks/useAdminListing.d.ts +1 -1
- package/dist/features/admin/repository/site-settings.repository.js +8 -3
- package/dist/features/admin/schemas/firestore.d.ts +62 -1
- package/dist/features/admin/schemas/firestore.js +32 -0
- package/dist/features/admin/types/index.d.ts +1 -1
- package/dist/features/auctions/actions/bid-actions.d.ts +2 -2
- package/dist/features/auctions/actions/bid-actions.js +16 -4
- package/dist/features/auctions/api/route.js +1 -1
- package/dist/features/auctions/components/AuctionBottomActions.js +4 -0
- package/dist/features/auctions/repository/bid.repository.d.ts +46 -4
- package/dist/features/auctions/repository/bid.repository.js +114 -13
- package/dist/features/auctions/schemas/firestore.d.ts +24 -4
- package/dist/features/auctions/schemas/firestore.js +1 -0
- package/dist/features/auth/actions/profile-actions.js +30 -4
- package/dist/features/auth/components/index.d.ts +0 -1
- package/dist/features/auth/components/index.js +0 -1
- package/dist/features/auth/repository/session.repository.d.ts +17 -3
- package/dist/features/auth/repository/session.repository.js +46 -5
- package/dist/features/auth/repository/token.repository.d.ts +27 -4
- package/dist/features/auth/repository/token.repository.js +65 -11
- package/dist/features/auth/repository/user.repository.d.ts +33 -7
- package/dist/features/auth/repository/user.repository.js +100 -15
- package/dist/features/auth/schemas/firestore.d.ts +63 -12
- package/dist/features/auth/schemas/firestore.js +11 -0
- package/dist/features/before-after/api/route.js +1 -1
- package/dist/features/blog/components/BlogListView.js +16 -3
- package/dist/features/blog/components/BlogPostView.js +1 -1
- package/dist/features/blog/schemas/index.d.ts +2 -2
- package/dist/features/cart/api/route.js +1 -1
- package/dist/features/catalogue/repository/catalogue.repository.d.ts +7 -7
- package/dist/features/catalogue/repository/catalogue.repository.js +28 -10
- package/dist/features/catalogue/schemas/firestore.d.ts +11 -0
- package/dist/features/categories/api/route.js +10 -10
- package/dist/features/categories/components/CategoryDetailPageView.js +35 -5
- package/dist/features/categories/components/CategorySelectorCreate.js +0 -1
- package/dist/features/categories/components/index.d.ts +0 -2
- package/dist/features/categories/components/index.js +0 -1
- package/dist/features/categories/repository/categories.repository.d.ts +1 -0
- package/dist/features/categories/repository/categories.repository.js +31 -1
- package/dist/features/categories/schemas/index.d.ts +2 -2
- package/dist/features/categories/utils/taxonomy-visual.d.ts +21 -0
- package/dist/features/categories/utils/taxonomy-visual.js +58 -0
- package/dist/features/checkout/actions/checkout-value-otp-actions.js +8 -1
- package/dist/features/collections/api/[slug]/route.js +3 -3
- package/dist/features/collections/api/route.js +1 -1
- package/dist/features/consultation/api/route.js +1 -1
- package/dist/features/consultation/repository/consultations.repository.js +1 -1
- package/dist/features/consultation/types/index.d.ts +1 -1
- package/dist/features/contact/components/ContactForm.js +1 -3
- package/dist/features/corporate/api/route.js +1 -1
- package/dist/features/corporate/repository/corporate.repository.js +1 -1
- package/dist/features/corporate/types/index.d.ts +1 -1
- package/dist/features/cron/jobs/auction-expiry.job.js +1 -1
- package/dist/features/cron/jobs/preorder-reminder.job.js +1 -1
- package/dist/features/events/actions/event-actions.d.ts +14 -0
- package/dist/features/events/actions/event-actions.js +82 -3
- package/dist/features/events/api/[id]/route.js +2 -2
- package/dist/features/events/components/AdminEventEditorView.js +22 -3
- package/dist/features/events/components/AdminEventsView.js +32 -8
- package/dist/features/events/components/EventRafflesSection.d.ts +34 -1
- package/dist/features/events/components/EventRafflesSection.js +52 -3
- package/dist/features/events/components/SpinWheelView.d.ts +2 -2
- package/dist/features/events/components/SpinWheelView.js +41 -4
- package/dist/features/events/repository/event-entry.repository.d.ts +14 -2
- package/dist/features/events/repository/event-entry.repository.js +41 -7
- package/dist/features/events/schemas/firestore.d.ts +17 -4
- package/dist/features/events/types/index.d.ts +37 -0
- package/dist/features/faq/repository/faqs.repository.js +1 -1
- package/dist/features/faq/schemas/index.d.ts +5 -2
- package/dist/features/faq/schemas/index.js +6 -0
- package/dist/features/faq/types/index.d.ts +0 -1
- package/dist/features/grouped/components/GroupedListingEditorView.js +17 -2
- package/dist/features/homepage/api/carousel/[id]/route.js +1 -1
- package/dist/features/homepage/api/carousel/route.js +4 -4
- package/dist/features/homepage/api/route.js +2 -2
- package/dist/features/homepage/api/sections/route.js +1 -1
- package/dist/features/homepage/components/AnnouncementBar.d.ts +1 -9
- package/dist/features/homepage/components/AnnouncementBar.js +13 -19
- package/dist/features/homepage/components/MarketplaceHomepageView.js +6 -1
- package/dist/features/homepage/components/index.d.ts +0 -2
- package/dist/features/homepage/components/index.js +0 -1
- package/dist/features/homepage/repository/homepage.repository.js +1 -1
- package/dist/features/homepage/schemas/firestore.d.ts +6 -0
- package/dist/features/homepage/schemas/index.d.ts +10 -10
- package/dist/features/layout/AppLayoutShell.d.ts +11 -0
- package/dist/features/layout/AppLayoutShell.js +64 -12
- package/dist/features/layout/BottomActionsContext.d.ts +16 -0
- package/dist/features/layout/BottomActionsContext.js +5 -0
- package/dist/features/layout/BottomChrome.js +48 -9
- package/dist/features/layout/BottomNavbar.d.ts +14 -0
- package/dist/features/layout/BottomNavbar.js +43 -3
- package/dist/features/layout/MainNavbar.d.ts +11 -0
- package/dist/features/layout/NavbarLayout.d.ts +3 -0
- package/dist/features/layout/NavbarLayout.js +88 -11
- package/dist/features/layout/SideActionDock.d.ts +1 -0
- package/dist/features/layout/SideActionDock.js +219 -0
- package/dist/features/layout/TitleBarLayout.js +1 -1
- package/dist/features/layout/cta-anchor.d.ts +31 -0
- package/dist/features/layout/cta-anchor.js +31 -0
- package/dist/features/layout/hooks/useBottomActions.d.ts +7 -0
- package/dist/features/layout/hooks/useBottomActions.js +6 -1
- package/dist/features/layout/index.d.ts +9 -1
- package/dist/features/layout/index.js +9 -1
- package/dist/features/layout/useCtaReveal.d.ts +24 -0
- package/dist/features/layout/useCtaReveal.js +82 -0
- package/dist/features/layout/useHoldToOpen.d.ts +41 -0
- package/dist/features/layout/useHoldToOpen.js +84 -0
- package/dist/features/lottery/repository/lottery-entry.repository.d.ts +18 -3
- package/dist/features/lottery/repository/lottery-entry.repository.js +48 -6
- package/dist/features/lottery/schemas/firestore.d.ts +33 -5
- package/dist/features/loyalty/api/balance/route.js +1 -1
- package/dist/features/loyalty/api/history/route.js +1 -1
- package/dist/features/media/MediaImage.js +0 -1
- package/dist/features/media/MediaPickerModal.js +7 -1
- package/dist/features/media/modals/ImageEditor.js +5 -1
- package/dist/features/media/modals/VideoThumbnailSelector.js +17 -1
- package/dist/features/media/repository/media-assets.repository.d.ts +19 -0
- package/dist/features/media/upload/CameraCapture.js +16 -1
- package/dist/features/media/upload/ImageUpload.js +42 -4
- package/dist/features/media/upload/MediaUploadField.js +69 -13
- package/dist/features/media/upload/downscale-image.d.ts +56 -0
- package/dist/features/media/upload/downscale-image.js +150 -0
- package/dist/features/messages/components/ConversationThreadView.js +45 -2
- package/dist/features/messages/components/MessageSellerButton.d.ts +15 -1
- package/dist/features/messages/components/MessageSellerButton.js +10 -2
- package/dist/features/messages/schemas/firestore.d.ts +15 -0
- package/dist/features/orders/hooks/useOrders.js +4 -2
- package/dist/features/orders/repository/orders.repository.d.ts +15 -4
- package/dist/features/orders/repository/orders.repository.js +52 -20
- package/dist/features/orders/schemas/firestore.d.ts +15 -4
- package/dist/features/orders/schemas/index.d.ts +8 -8
- package/dist/features/orders/types/index.d.ts +2 -2
- package/dist/features/payments/repository/payments.repository.js +2 -2
- package/dist/features/payments/repository/payout.repository.d.ts +23 -6
- package/dist/features/payments/repository/payout.repository.js +63 -23
- package/dist/features/payments/repository/saved-payment-methods.repository.d.ts +17 -6
- package/dist/features/payments/repository/saved-payment-methods.repository.js +59 -11
- package/dist/features/payments/schemas/firestore.d.ts +14 -3
- package/dist/features/payments/schemas/saved-methods-firestore.d.ts +12 -1
- package/dist/features/pre-orders/api/[slug]/route.js +1 -1
- package/dist/features/pre-orders/api/admin/route.js +1 -1
- package/dist/features/pre-orders/api/route.js +1 -1
- package/dist/features/pre-orders/repository/pre-orders.repository.d.ts +3 -3
- package/dist/features/pre-orders/repository/pre-orders.repository.js +6 -6
- package/dist/features/products/api/[id]/route.js +1 -1
- package/dist/features/products/components/ListingBottomActions.js +4 -0
- package/dist/features/products/components/ProductDetailPageView.js +2 -1
- package/dist/features/products/components/ProductGalleryClient.js +2 -2
- package/dist/features/products/components/ProductGrid.js +12 -1
- package/dist/features/products/components/index.d.ts +0 -2
- package/dist/features/products/components/index.js +0 -1
- package/dist/features/products/config/listing-type-listing-config.d.ts +0 -3
- package/dist/features/products/config/listing-type-listing-config.js +27 -2
- package/dist/features/products/constants/listing-tabs.d.ts +9 -0
- package/dist/features/products/constants/listing-tabs.js +3 -2
- package/dist/features/products/hooks/useProducts.js +2 -2
- package/dist/features/products/repository/products.repository.js +13 -1
- package/dist/features/products/schemas/index.d.ts +2 -2
- package/dist/features/products/types/index.d.ts +1 -1
- package/dist/features/promotions/api/route.js +1 -1
- package/dist/features/reviews/actions/review-actions.d.ts +6 -6
- package/dist/features/reviews/actions/review-actions.js +22 -8
- package/dist/features/reviews/components/ReviewDetailPageView.js +13 -1
- package/dist/features/reviews/components/ReviewsIndexPageView.js +21 -4
- package/dist/features/reviews/repository/reviews.repository.d.ts +19 -7
- package/dist/features/reviews/repository/reviews.repository.js +63 -12
- package/dist/features/reviews/schemas/firestore.d.ts +13 -2
- package/dist/features/reviews/schemas/index.d.ts +2 -2
- package/dist/features/scams/actions/scam-actions.js +16 -4
- package/dist/features/search/components/SearchResultsPageView.js +2 -1
- package/dist/features/search/hooks/useSearchIndex.d.ts +34 -0
- package/dist/features/search/hooks/useSearchIndex.js +172 -0
- package/dist/features/search/repository/search.repository.js +2 -2
- package/dist/features/seller/actions/offer-actions.d.ts +5 -5
- package/dist/features/seller/actions/offer-actions.js +38 -8
- package/dist/features/seller/actions/seller-actions.js +34 -7
- package/dist/features/seller/api/coupons/route.js +1 -1
- package/dist/features/seller/api/products/route.js +1 -1
- package/dist/features/seller/api/store/route.js +1 -1
- package/dist/features/seller/components/SellerBidsView.js +1 -1
- package/dist/features/seller/components/SellerCouponsView.js +1 -1
- package/dist/features/seller/components/SellerListingTypeView.js +9 -1
- package/dist/features/seller/components/SellerOrdersView.js +1 -1
- package/dist/features/seller/components/SellerPayoutSettingsView.js +0 -1
- package/dist/features/seller/components/SellerPayoutsView.js +1 -1
- package/dist/features/seller/components/SellerProductShell.js +0 -1
- package/dist/features/seller/components/SellerProductsView.js +1 -1
- package/dist/features/seller/components/SellerShippingView.js +0 -1
- package/dist/features/seller/components/SellerStorefrontView.js +0 -1
- package/dist/features/seller/components/index.d.ts +0 -4
- package/dist/features/seller/components/index.js +0 -2
- package/dist/features/seller/repository/offer.repository.d.ts +15 -3
- package/dist/features/seller/repository/offer.repository.js +43 -7
- package/dist/features/seller/schemas/firestore.d.ts +14 -3
- package/dist/features/seller/schemas/index.d.ts +4 -4
- package/dist/features/seller/schemas/order-forms.d.ts +39 -0
- package/dist/features/seller/schemas/order-forms.js +37 -0
- package/dist/features/shell/FormShell.js +6 -2
- package/dist/features/shell/QuickFormDrawer.js +15 -1
- package/dist/features/shipments/components/AdminShipmentEditorView.js +0 -1
- package/dist/features/shipments/components/AdminShipmentsView.js +1 -1
- package/dist/features/sticker-trace/components/StickerCommitPanel.d.ts +30 -0
- package/dist/features/sticker-trace/components/StickerCommitPanel.js +93 -0
- package/dist/features/sticker-trace/components/StickerPrintPanel.d.ts +33 -0
- package/dist/features/sticker-trace/components/StickerPrintPanel.js +104 -0
- package/dist/features/sticker-trace/components/StickerRetryPanel.d.ts +20 -0
- package/dist/features/sticker-trace/components/StickerRetryPanel.js +128 -0
- package/dist/features/sticker-trace/components/StickerRunHistoryPanel.d.ts +45 -0
- package/dist/features/sticker-trace/components/StickerRunHistoryPanel.js +84 -0
- package/dist/features/sticker-trace/components/StickerTraceStudio.d.ts +27 -0
- package/dist/features/sticker-trace/components/StickerTraceStudio.js +171 -0
- package/dist/features/sticker-trace/constants/help-content.d.ts +23 -0
- package/dist/features/sticker-trace/constants/help-content.js +172 -0
- package/dist/features/sticker-trace/hooks/useLiveTrace.d.ts +27 -0
- package/dist/features/sticker-trace/hooks/useLiveTrace.js +160 -0
- package/dist/features/sticker-trace/hooks/useStickerTraceProgress.d.ts +22 -0
- package/dist/features/sticker-trace/hooks/useStickerTraceProgress.js +106 -0
- package/dist/features/sticker-trace/repository/sticker-sheets.repository.d.ts +113 -0
- package/dist/features/sticker-trace/repository/sticker-sheets.repository.js +146 -0
- package/dist/features/sticker-trace/repository/sticker-trace-runs.repository.d.ts +132 -0
- package/dist/features/sticker-trace/repository/sticker-trace-runs.repository.js +174 -0
- package/dist/features/sticker-trace/schemas/firestore.d.ts +248 -0
- package/dist/features/sticker-trace/schemas/firestore.js +79 -0
- package/dist/features/sticker-trace/server.d.ts +8 -0
- package/dist/features/sticker-trace/server.js +51 -0
- package/dist/features/stores/actions/store-query-actions.d.ts +2 -2
- package/dist/features/stores/actions/store-query-actions.js +7 -2
- package/dist/features/stores/api/[storeSlug]/auctions/route.js +3 -3
- package/dist/features/stores/api/[storeSlug]/products/route.js +3 -3
- package/dist/features/stores/api/[storeSlug]/reviews/route.js +1 -1
- package/dist/features/stores/api/[storeSlug]/route.js +1 -1
- package/dist/features/stores/components/StoreNavTabs.js +17 -2
- package/dist/features/stores/manifest.js +8 -4
- package/dist/features/support/repository/support.repository.d.ts +14 -3
- package/dist/features/support/repository/support.repository.js +93 -13
- package/dist/features/support/schemas/firestore.d.ts +16 -5
- package/dist/features/tester/seed-data/authored/admin__events-raffles-spin.js +61 -19
- package/dist/features/tester/seed-data/authored/buying__browsing-search.js +19 -3
- package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.js +243 -0
- package/dist/features/tester/seed-data/authored/content-discovery__events.js +36 -10
- package/dist/features/tester/seed-data/authored/content-discovery__overflowing-pill-rows.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__overflowing-pill-rows.js +209 -0
- package/dist/features/tester/seed-data/authored/design-ux__header-brand-mark-centring.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__header-brand-mark-centring.js +90 -0
- package/dist/features/tester/seed-data/authored/index.js +8 -0
- package/dist/features/tester/seed-data/authored/selling__media-limits.js +19 -17
- package/dist/features/tester/seed-data/authored/selling__product-upload-details.js +10 -5
- package/dist/features/tester/seed-data/authored/tools__sticker-tracer.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/tools__sticker-tracer.js +283 -0
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +192 -22
- package/dist/index.d.ts +10 -23
- package/dist/index.js +27 -19
- package/dist/next/api/routeHandler.js +9 -0
- package/dist/next/routing/require-record.d.ts +13 -0
- package/dist/next/routing/require-record.js +62 -0
- package/dist/next/routing/route-map.d.ts +4 -4
- package/dist/next/routing/route-map.js +25 -3
- package/dist/providers/db-firebase/base.d.ts +4 -2
- package/dist/providers/db-firebase/base.js +21 -5
- package/dist/providers/db-firebase/base.repository.d.ts +11 -9
- package/dist/providers/db-firebase/base.repository.js +19 -0
- package/dist/providers/db-firebase/rtdb-paths.d.ts +12 -0
- package/dist/providers/db-firebase/rtdb-paths.js +12 -0
- package/dist/react/ErrorBoundary.js +6 -1
- package/dist/react/hooks/realtime-event-constants.d.ts +1 -0
- package/dist/react/hooks/realtime-event-constants.js +8 -0
- package/dist/react/hooks/useEntityDelete.js +5 -1
- package/dist/react/hooks/useMessage.js +5 -1
- package/dist/repositories/index.d.ts +2 -2
- package/dist/repositories/index.js +6 -1
- package/dist/schemas/registry.d.ts +13 -20
- package/dist/schemas/registry.js +31 -14
- package/dist/schemas/webhooks/google-oauth.d.ts +2 -2
- package/dist/security/encrypted.d.ts +117 -0
- package/dist/security/encrypted.js +100 -0
- package/dist/security/index.d.ts +5 -2
- package/dist/security/index.js +16 -2
- package/dist/security/pii-accessors.d.ts +71 -0
- package/dist/security/pii-accessors.js +150 -0
- package/dist/security/pii-encrypt.d.ts +0 -8
- package/dist/security/pii-encrypt.js +22 -15
- package/dist/security/pii-mask.d.ts +18 -0
- package/dist/security/pii-mask.js +27 -0
- package/dist/seed/_helpers/search-txt-wrappers.d.ts +6 -6
- package/dist/seed/_helpers/search-txt-wrappers.js +22 -0
- package/dist/seed/addresses-seed-data.d.ts +2 -2
- package/dist/seed/authenticity-knowledge-seed-data.d.ts +34 -0
- package/dist/seed/authenticity-knowledge-seed-data.js +1277 -0
- package/dist/seed/bids-seed-data.d.ts +2 -2
- package/dist/seed/bids-seed-data.js +23 -2
- package/dist/seed/events-seed-data.d.ts +2 -2
- package/dist/seed/events-seed-data.js +5 -0
- package/dist/seed/faq-seed-data.js +175 -5
- package/dist/seed/homepage-sections-seed-data.js +39 -23
- package/dist/seed/index.d.ts +1 -0
- package/dist/seed/index.js +1 -0
- package/dist/seed/lottery-entries-seed-data.d.ts +2 -2
- package/dist/seed/offers-seed-data.d.ts +2 -2
- package/dist/seed/offers-seed-data.js +1 -1
- package/dist/seed/orders-seed-data.d.ts +2 -2
- package/dist/seed/payouts-seed-data.d.ts +2 -2
- package/dist/seed/payouts-seed-data.js +1 -1
- package/dist/seed/reviews-seed-data.d.ts +1 -2
- package/dist/seed/seed-purpose.js +7 -0
- package/dist/seed/sessions-seed-data.d.ts +2 -2
- package/dist/seed/sessions-seed-data.js +5 -0
- package/dist/seed/site-settings-seed-data.js +1 -1
- package/dist/seed/support-tickets-seed-data.d.ts +2 -2
- package/dist/seed/support-tickets-seed-data.js +1 -1
- package/dist/seed/users-seed-data.d.ts +2 -2
- package/dist/seed/users-seed-data.js +1 -1
- package/dist/seo/json-ld.js +5 -1
- package/dist/server.d.ts +18 -3
- package/dist/server.js +59 -3
- package/dist/styles.css +237 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/Button.js +7 -1
- package/dist/ui/components/FilterChipGroup.d.ts +11 -0
- package/dist/ui/components/FilterChipGroup.js +1 -1
- package/dist/ui/components/ImageGallery.js +6 -1
- package/dist/ui/components/ListingLayout.js +14 -8
- package/dist/ui/components/OverflowRow.d.ts +92 -0
- package/dist/ui/components/OverflowRow.js +203 -0
- package/dist/ui/components/OverflowRow.style.css +235 -0
- package/dist/ui/components/RecordDetailModal.js +14 -1
- package/dist/ui/components/RowActionMenu.js +5 -1
- package/dist/ui/components/SideDrawer.js +5 -1
- package/dist/ui/components/SideModal.js +9 -1
- package/dist/ui/components/TabBarShell.d.ts +12 -1
- package/dist/ui/components/TabBarShell.js +3 -2
- package/dist/ui/components/Tabs.js +36 -24
- package/dist/ui/components/Toast.d.ts +3 -24
- package/dist/ui/components/Toast.js +2 -19
- package/dist/ui/components/TopBannerPortal.d.ts +15 -0
- package/dist/ui/components/TopBannerPortal.js +19 -0
- package/dist/ui/components/UnsavedChangesModal.js +5 -1
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/components/row-collapse.d.ts +15 -0
- package/dist/ui/components/row-collapse.js +127 -0
- package/dist/ui/components/toast-context.d.ts +63 -0
- package/dist/ui/components/toast-context.js +48 -0
- package/dist/ui/components/top-banner-slot.d.ts +37 -0
- package/dist/ui/components/top-banner-slot.js +45 -0
- package/dist/ui/icons/icon-registry.d.ts +6 -0
- package/dist/ui/icons/icon-registry.js +17 -1
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +1 -0
- package/dist/utils/array.helper.d.ts +2 -2
- package/dist/utils/array.helper.js +5 -5
- package/dist/utils/id-generators.d.ts +6 -0
- package/dist/utils/id-generators.js +10 -0
- package/dist/utils/media-url.js +0 -2
- package/dist/utils/search-txt-builders.d.ts +28 -4
- package/dist/utils/search-txt-builders.js +41 -1
- package/dist/validation/schemas.d.ts +8 -8
- package/package.json +6 -2
- package/scripts/seed-cli.mjs +3 -0
- package/dist/features/account/components/UserAddressesView.d.ts +0 -13
- package/dist/features/account/components/UserAddressesView.js +0 -5
- package/dist/features/account/components/UserNotificationsView.d.ts +0 -15
- package/dist/features/account/components/UserNotificationsView.js +0 -12
- package/dist/features/account/components/UserSettingsView.d.ts +0 -16
- package/dist/features/account/components/UserSettingsView.js +0 -13
- package/dist/features/account/components/UserSupportView.d.ts +0 -3
- package/dist/features/account/components/UserSupportView.js +0 -166
- package/dist/features/admin/components/DemoSeedView.d.ts +0 -11
- package/dist/features/admin/components/DemoSeedView.js +0 -5
- package/dist/features/auth/components/AuthStatusPanel.d.ts +0 -10
- package/dist/features/auth/components/AuthStatusPanel.js +0 -22
- package/dist/features/categories/components/CategoryProductsView.d.ts +0 -45
- package/dist/features/categories/components/CategoryProductsView.js +0 -21
- package/dist/features/homepage/components/HowItWorksInfoView.d.ts +0 -36
- package/dist/features/homepage/components/HowItWorksInfoView.js +0 -10
- package/dist/features/layout/BottomActions.d.ts +0 -1
- package/dist/features/layout/BottomActions.js +0 -311
- package/dist/features/products/components/ProductsView.d.ts +0 -6
- package/dist/features/products/components/ProductsView.js +0 -5
- package/dist/features/seller/components/SellerStoreView.d.ts +0 -8
- package/dist/features/seller/components/SellerStoreView.js +0 -8
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: This is the measurement the whole tool rests on, and the reason it
|
|
3
|
+
* replaced the previous colour-threshold approach.
|
|
4
|
+
*
|
|
5
|
+
* A kiss cut is a physical impression in the sheet, so under a scanner it
|
|
6
|
+
* reads as a DOUBLET — a dark trough beside a light ridge — regardless of
|
|
7
|
+
* what colour sits either side of it. Sampling four scanlines across known
|
|
8
|
+
* cut lines on the reference scans, detrended against a local median:
|
|
9
|
+
*
|
|
10
|
+
* yellow panel on yellow : luminance 173-240, doublet -40/+27, noise +-2
|
|
11
|
+
* red field on red : luminance 98-127, ridge +22, noise +-1
|
|
12
|
+
* white sticker on cream : luminance 6-224, spikes +75/+103, noise +-7
|
|
13
|
+
* halftone green panel : luminance 93-161, ridge +18..+47, noise +-6
|
|
14
|
+
*
|
|
15
|
+
* The first two are the cases that defeated colour thresholding entirely —
|
|
16
|
+
* there is no colour edge to find — and the doublet is 10-20x noise in
|
|
17
|
+
* both. The third is the "white fades into the paper" failure: the colour
|
|
18
|
+
* is gone but the cut line is still there at 10x. Only the halftone scan is
|
|
19
|
+
* marginal, at ~3x, which is what the prefilter and the second detector
|
|
20
|
+
* channel exist for.
|
|
21
|
+
* WHAT: Detrended local-range ridge detection with hysteresis linking.
|
|
22
|
+
*
|
|
23
|
+
* EXPORTS: RidgeResult, detectRidges
|
|
24
|
+
*
|
|
25
|
+
* @tag domain:sticker-trace
|
|
26
|
+
* @tag layer:shared
|
|
27
|
+
* @tag pattern:none
|
|
28
|
+
* @tag access:isomorphic
|
|
29
|
+
* @tag consumers:fuse,segment
|
|
30
|
+
* @tag sideEffects:none
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* Separable box blur with running sums — O(n) regardless of radius.
|
|
34
|
+
*
|
|
35
|
+
* Used only to estimate the local BACKGROUND level, never to smooth the signal.
|
|
36
|
+
* A mean is the right tool here precisely because the cut line is thin: it
|
|
37
|
+
* barely moves a large-window mean, so subtracting that mean leaves the line
|
|
38
|
+
* standing while removing the gradient underneath it.
|
|
39
|
+
*/
|
|
40
|
+
function boxBlur(src, width, height, radius) {
|
|
41
|
+
const tmp = new Float32Array(src.length);
|
|
42
|
+
const out = new Float32Array(src.length);
|
|
43
|
+
const window = radius * 2 + 1;
|
|
44
|
+
for (let y = 0; y < height; y++) {
|
|
45
|
+
const row = y * width;
|
|
46
|
+
let sum = 0;
|
|
47
|
+
for (let i = -radius; i <= radius; i++) {
|
|
48
|
+
sum += src[row + Math.min(width - 1, Math.max(0, i))];
|
|
49
|
+
}
|
|
50
|
+
for (let x = 0; x < width; x++) {
|
|
51
|
+
tmp[row + x] = sum / window;
|
|
52
|
+
const outX = Math.min(width - 1, Math.max(0, x - radius));
|
|
53
|
+
const inX = Math.min(width - 1, Math.max(0, x + radius + 1));
|
|
54
|
+
sum += src[row + inX] - src[row + outX];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
for (let x = 0; x < width; x++) {
|
|
58
|
+
let sum = 0;
|
|
59
|
+
for (let i = -radius; i <= radius; i++) {
|
|
60
|
+
sum += tmp[Math.min(height - 1, Math.max(0, i)) * width + x];
|
|
61
|
+
}
|
|
62
|
+
for (let y = 0; y < height; y++) {
|
|
63
|
+
out[y * width + x] = sum / window;
|
|
64
|
+
const outY = Math.min(height - 1, Math.max(0, y - radius));
|
|
65
|
+
const inY = Math.min(height - 1, Math.max(0, y + radius + 1));
|
|
66
|
+
sum += tmp[inY * width + x] - tmp[outY * width + x];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Hysteresis: seed at `high`, grow through anything above `low`.
|
|
73
|
+
*
|
|
74
|
+
* 🛑 This is what makes a FAINT but CONTINUOUS line beat a BRIGHT but isolated
|
|
75
|
+
* speck, which is the entire discrimination the detector needs. A single
|
|
76
|
+
* threshold cannot express it: set high enough to reject scanner speckle and
|
|
77
|
+
* the halftone scan's cut line disappears; set low enough to keep that line and
|
|
78
|
+
* every rosette dot becomes a barrier.
|
|
79
|
+
*
|
|
80
|
+
* Iterative with an explicit stack rather than recursion — a connected ridge on
|
|
81
|
+
* a 9 MP raster can run to hundreds of thousands of pixels.
|
|
82
|
+
*/
|
|
83
|
+
function hysteresis(response, width, height, low, high) {
|
|
84
|
+
const lowField = new Float32Array(response.length).fill(low);
|
|
85
|
+
const highField = new Float32Array(response.length).fill(high);
|
|
86
|
+
return hysteresisField(response, width, height, lowField, highField);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Hysteresis where each pixel carries its own pair of thresholds.
|
|
90
|
+
*
|
|
91
|
+
* The growth rule compares a candidate against the threshold at the CANDIDATE's
|
|
92
|
+
* position, not the seed's. That matters where a cut line crosses from a flat
|
|
93
|
+
* field into busy artwork: the line stays linked because each pixel is judged
|
|
94
|
+
* against its own surroundings, whereas carrying the seed's threshold along
|
|
95
|
+
* would either break the line at the boundary or flood the busy side.
|
|
96
|
+
*/
|
|
97
|
+
function hysteresisField(response, width, height, low, high) {
|
|
98
|
+
const out = new Uint8Array(response.length);
|
|
99
|
+
const stack = [];
|
|
100
|
+
for (let i = 0; i < response.length; i++) {
|
|
101
|
+
if (response[i] >= high[i]) {
|
|
102
|
+
out[i] = 1;
|
|
103
|
+
stack.push(i);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
while (stack.length > 0) {
|
|
107
|
+
const i = stack.pop();
|
|
108
|
+
const x = i % width;
|
|
109
|
+
const y = (i / width) | 0;
|
|
110
|
+
// 8-connected growth, deliberately wider than the 4-connectivity used for
|
|
111
|
+
// components: a scanned line steps diagonally all the time, and refusing to
|
|
112
|
+
// follow it there would break the barrier at every stair-step.
|
|
113
|
+
for (let dy = -1; dy <= 1; dy++) {
|
|
114
|
+
const ny = y + dy;
|
|
115
|
+
if (ny < 0 || ny >= height)
|
|
116
|
+
continue;
|
|
117
|
+
for (let dx = -1; dx <= 1; dx++) {
|
|
118
|
+
const nx = x + dx;
|
|
119
|
+
if (nx < 0 || nx >= width)
|
|
120
|
+
continue;
|
|
121
|
+
const j = ny * width + nx;
|
|
122
|
+
if (out[j] || response[j] < low[j])
|
|
123
|
+
continue;
|
|
124
|
+
out[j] = 1;
|
|
125
|
+
stack.push(j);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return out;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Detect cut lines.
|
|
133
|
+
*
|
|
134
|
+
* Three steps, each answering one objection to the previous:
|
|
135
|
+
*
|
|
136
|
+
* 1. DETREND. Subtract a large-window mean. Without this, the detector sees
|
|
137
|
+
* the airbrushed gradient under a sticker as a huge slow ramp and the cut
|
|
138
|
+
* line as a rounding error on top of it. This is the step that exposed the
|
|
139
|
+
* signal in the measurements above.
|
|
140
|
+
* 2. LOCAL RANGE. The doublet's signature is that a trough and a ridge sit
|
|
141
|
+
* within a pixel or two of each other, so the local max-minus-min of the
|
|
142
|
+
* detrended field is large on a cut line and ~0 on flat ink. A plain
|
|
143
|
+
* gradient magnitude would fire equally on one-sided edges; the range
|
|
144
|
+
* specifically rewards the paired shape an impression makes.
|
|
145
|
+
* 3. HYSTERESIS. Continuity beats amplitude — see above.
|
|
146
|
+
*/
|
|
147
|
+
/**
|
|
148
|
+
* A ROBUST estimate of "the typical response around here".
|
|
149
|
+
*
|
|
150
|
+
* 🛑 Robust is the operative word, and it is a measured correction. The first
|
|
151
|
+
* version used `localMean + k * localStdDev` over a 48px window, and on the
|
|
152
|
+
* `torch pegases` sheet that detected 0 of 10 cut-line pixels where the
|
|
153
|
+
* absolute threshold had found 10 — because the white "Gyro Engine" lettering
|
|
154
|
+
* inside the window inflated the standard deviation far above the cut line it
|
|
155
|
+
* sat next to. A mean and an SD are both wrecked by one bright feature, and
|
|
156
|
+
* printed artwork is nothing but bright features.
|
|
157
|
+
*
|
|
158
|
+
* So: block-average down by 8, MEDIAN-filter at that coarse scale, then
|
|
159
|
+
* bilinearly upsample. The median discards the lettering outright instead of
|
|
160
|
+
* averaging it in, and doing it on a 1/64-size grid makes a genuine median
|
|
161
|
+
* affordable — the same filter at full resolution would cost more than every
|
|
162
|
+
* other stage combined.
|
|
163
|
+
*/
|
|
164
|
+
function robustLocalBackground(response, width, height) {
|
|
165
|
+
const SHRINK = 8;
|
|
166
|
+
const cw = Math.max(1, Math.ceil(width / SHRINK));
|
|
167
|
+
const ch = Math.max(1, Math.ceil(height / SHRINK));
|
|
168
|
+
const coarse = new Float32Array(cw * ch);
|
|
169
|
+
for (let cy = 0; cy < ch; cy++) {
|
|
170
|
+
for (let cx = 0; cx < cw; cx++) {
|
|
171
|
+
let sum = 0;
|
|
172
|
+
let n = 0;
|
|
173
|
+
for (let y = cy * SHRINK; y < Math.min(height, (cy + 1) * SHRINK); y++) {
|
|
174
|
+
for (let x = cx * SHRINK; x < Math.min(width, (cx + 1) * SHRINK); x++) {
|
|
175
|
+
sum += response[y * width + x];
|
|
176
|
+
n++;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
coarse[cy * cw + cx] = n > 0 ? sum / n : 0;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// Median over a 7x7 coarse window — ~56px at full resolution, wider than any
|
|
183
|
+
// cut line and narrower than any sticker.
|
|
184
|
+
const R = 3;
|
|
185
|
+
const smoothed = new Float32Array(cw * ch);
|
|
186
|
+
const buf = new Float32Array((R * 2 + 1) ** 2);
|
|
187
|
+
for (let cy = 0; cy < ch; cy++) {
|
|
188
|
+
for (let cx = 0; cx < cw; cx++) {
|
|
189
|
+
let n = 0;
|
|
190
|
+
for (let dy = -R; dy <= R; dy++) {
|
|
191
|
+
const sy = Math.min(ch - 1, Math.max(0, cy + dy));
|
|
192
|
+
for (let dx = -R; dx <= R; dx++) {
|
|
193
|
+
const sx = Math.min(cw - 1, Math.max(0, cx + dx));
|
|
194
|
+
buf[n++] = coarse[sy * cw + sx];
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const slice = buf.subarray(0, n);
|
|
198
|
+
slice.sort();
|
|
199
|
+
smoothed[cy * cw + cx] = slice[n >> 1];
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
const out = new Float32Array(response.length);
|
|
203
|
+
for (let y = 0; y < height; y++) {
|
|
204
|
+
const fy = Math.min(ch - 1, y / SHRINK);
|
|
205
|
+
const y0 = Math.floor(fy);
|
|
206
|
+
const y1 = Math.min(ch - 1, y0 + 1);
|
|
207
|
+
const ty = fy - y0;
|
|
208
|
+
for (let x = 0; x < width; x++) {
|
|
209
|
+
const fx = Math.min(cw - 1, x / SHRINK);
|
|
210
|
+
const x0 = Math.floor(fx);
|
|
211
|
+
const x1 = Math.min(cw - 1, x0 + 1);
|
|
212
|
+
const tx = fx - x0;
|
|
213
|
+
const a = smoothed[y0 * cw + x0] * (1 - tx) + smoothed[y0 * cw + x1] * tx;
|
|
214
|
+
const b = smoothed[y1 * cw + x0] * (1 - tx) + smoothed[y1 * cw + x1] * tx;
|
|
215
|
+
out[y * width + x] = a * (1 - ty) + b * ty;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return out;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Hysteresis against a LOCAL threshold rather than a global one.
|
|
222
|
+
*
|
|
223
|
+
* 🛑 This replaced both a fixed-value and a fixed-percentile threshold, and the
|
|
224
|
+
* measurements that killed each are worth keeping:
|
|
225
|
+
*
|
|
226
|
+
* absolute (low=9, high=18) — barrier coverage 34-61% across the corpus. The
|
|
227
|
+
* median response spans 0.1 (Driger: clean paper) to 14.1 (Poseidon: JPEG
|
|
228
|
+
* cream field), so one pair of numbers is simultaneously far too low for
|
|
229
|
+
* one scan and far too high for another.
|
|
230
|
+
* percentile (p60/p80) — coverage pinned at ~38% on EVERY scan, which is
|
|
231
|
+
* what a quantile does by construction rather than what a detector does.
|
|
232
|
+
* Worse, Poseidon's cream-field cut line (response 12-16) fell below that
|
|
233
|
+
* scan's own p60 and vanished completely.
|
|
234
|
+
*
|
|
235
|
+
* The second failure is the informative one: a response of 12-16 is plainly a
|
|
236
|
+
* line on a flat cream field and plainly noise inside dense artwork, so NO
|
|
237
|
+
* single global number can separate them. Significance is local, so the
|
|
238
|
+
* threshold is local — Niblack/Sauvola-style, `localMean + k * localStdDev`
|
|
239
|
+
* over a window much larger than a cut line but much smaller than a sticker.
|
|
240
|
+
*
|
|
241
|
+
* Both statistics come from box blurs (mean, and mean-of-squares for the
|
|
242
|
+
* variance), so the whole thing stays O(n) and independent of window size.
|
|
243
|
+
*/
|
|
244
|
+
/**
|
|
245
|
+
* Threshold ANY response field against its own robust local background.
|
|
246
|
+
*
|
|
247
|
+
* Exported because the art path feeds it a Hessian line response rather than
|
|
248
|
+
* this module's edge response — the thresholding policy (local, robust,
|
|
249
|
+
* hysteresis-linked) is right for both and must not be written twice.
|
|
250
|
+
*/
|
|
251
|
+
export function thresholdAdaptive(response, width, height, kLow, kHigh) {
|
|
252
|
+
return adaptiveHysteresis(response, width, height, kLow, kHigh);
|
|
253
|
+
}
|
|
254
|
+
function adaptiveHysteresis(response, width, height, kLow, kHigh, assist, assistWeight = 0) {
|
|
255
|
+
const background = robustLocalBackground(response, width, height);
|
|
256
|
+
const lowField = new Float32Array(response.length);
|
|
257
|
+
const highField = new Float32Array(response.length);
|
|
258
|
+
for (let i = 0; i < response.length; i++) {
|
|
259
|
+
const bg = background[i];
|
|
260
|
+
// Multiplicative, not additive. The response is a local CONTRAST measure,
|
|
261
|
+
// so its scale rides with how busy the neighbourhood is; "k standard
|
|
262
|
+
// deviations above the mean" assumes a spread that printed artwork does not
|
|
263
|
+
// have. "A few times the typical local contrast" does hold across the
|
|
264
|
+
// corpus. The floors keep a perfectly flat region (Driger's paper sits at a
|
|
265
|
+
// median response of 0.1) from treating 8-bit quantisation as signal.
|
|
266
|
+
//
|
|
267
|
+
// 🛑 The assist LOWERS the bar; it never clears it. Where the colour
|
|
268
|
+
// channel also sees a boundary the ridge only has to be `1 - weight` as
|
|
269
|
+
// convincing — so a marginal ridge on the halftone sheet links, while a
|
|
270
|
+
// pure colour change with NO ridge behind it still fails both thresholds
|
|
271
|
+
// and does not become a cut line. Letting the assist seed on its own would
|
|
272
|
+
// turn every gradient band inside a sticker into an outline.
|
|
273
|
+
const relief = assist && assist[i] ? 1 - assistWeight : 1;
|
|
274
|
+
lowField[i] = Math.max(3, bg * kLow * relief);
|
|
275
|
+
highField[i] = Math.max(6, bg * kHigh * relief);
|
|
276
|
+
}
|
|
277
|
+
return hysteresisField(response, width, height, lowField, highField);
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Detect cut lines.
|
|
281
|
+
*
|
|
282
|
+
* 🛑 Thresholds are PERCENTILES of this scan's own response, not absolute
|
|
283
|
+
* luminance values, and that is a measured correction rather than a
|
|
284
|
+
* preference. Across the reference corpus the median response spans two orders
|
|
285
|
+
* of magnitude — 0.1 on the Driger G sheet (clean white paper, almost no
|
|
286
|
+
* texture) against 14.1 on the Poseidon scan (JPEG, printed cream field) — so
|
|
287
|
+
* any fixed pair of numbers is simultaneously far too high for one scan and far
|
|
288
|
+
* too low for another. Measured with absolute low=9/high=18, barrier coverage
|
|
289
|
+
* came out between 34% and 61%, which floods nothing.
|
|
290
|
+
*
|
|
291
|
+
* The cut line is only ~2.8-3.2x the median on the two hardest sheets, so the
|
|
292
|
+
* separation that matters is NOT cut-line-versus-artwork — a logo edge is a
|
|
293
|
+
* genuine edge and will exceed a cut line. It is cut-line-versus-BACKGROUND.
|
|
294
|
+
* Interior artwork edges joining the barrier is harmless: the flood arrives
|
|
295
|
+
* from outside and is already stopped by the outer cut line before it can ever
|
|
296
|
+
* reach them.
|
|
297
|
+
*
|
|
298
|
+
* Three steps, each answering one objection to the previous:
|
|
299
|
+
*
|
|
300
|
+
* 1. DETREND. Subtract a large-window mean. Without this the detector sees
|
|
301
|
+
* the airbrushed gradient under a sticker as a huge slow ramp and the cut
|
|
302
|
+
* line as a rounding error on top of it. This is the step that exposed the
|
|
303
|
+
* signal in the measurements above.
|
|
304
|
+
* 2. LOCAL RANGE. The doublet's signature is a trough and a ridge within a
|
|
305
|
+
* pixel or two of each other, so the local max-minus-min of the detrended
|
|
306
|
+
* field is large on a cut line and ~0 on flat ink. A plain gradient
|
|
307
|
+
* magnitude fires equally on one-sided edges; the range specifically
|
|
308
|
+
* rewards the paired shape an impression makes.
|
|
309
|
+
* 3. HYSTERESIS. Continuity beats amplitude — see above.
|
|
310
|
+
*/
|
|
311
|
+
export function detectRidges(luma, width, height, opts) {
|
|
312
|
+
const detrendRadius = Math.max(3, Math.round(7 * opts.kernelScale));
|
|
313
|
+
const background = boxBlur(luma, width, height, detrendRadius);
|
|
314
|
+
const dev = new Float32Array(luma.length);
|
|
315
|
+
for (let i = 0; i < dev.length; i++)
|
|
316
|
+
dev[i] = luma[i] - background[i];
|
|
317
|
+
const rangeRadius = Math.max(1, Math.round(opts.kernelScale));
|
|
318
|
+
const response = new Float32Array(luma.length);
|
|
319
|
+
for (let y = 0; y < height; y++) {
|
|
320
|
+
for (let x = 0; x < width; x++) {
|
|
321
|
+
let min = Infinity;
|
|
322
|
+
let max = -Infinity;
|
|
323
|
+
for (let dy = -rangeRadius; dy <= rangeRadius; dy++) {
|
|
324
|
+
const sy = Math.min(height - 1, Math.max(0, y + dy));
|
|
325
|
+
for (let dx = -rangeRadius; dx <= rangeRadius; dx++) {
|
|
326
|
+
const sx = Math.min(width - 1, Math.max(0, x + dx));
|
|
327
|
+
const v = dev[sy * width + sx];
|
|
328
|
+
if (v < min)
|
|
329
|
+
min = v;
|
|
330
|
+
if (v > max)
|
|
331
|
+
max = v;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
response[y * width + x] = max - min;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
const barrier = opts.absolute
|
|
338
|
+
? hysteresis(response, width, height, opts.absolute.low, opts.absolute.high)
|
|
339
|
+
: adaptiveHysteresis(response, width, height, opts.low, opts.high, opts.assist, opts.assistWeight ?? 0);
|
|
340
|
+
let set = 0;
|
|
341
|
+
for (let i = 0; i < barrier.length; i++)
|
|
342
|
+
set += barrier[i];
|
|
343
|
+
return { response, barrier, coverage: set / barrier.length };
|
|
344
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ComponentStats } from "../math/label";
|
|
2
|
+
import type { DecodedRaster, TraceDiagnostics, TraceParams } from "../types";
|
|
3
|
+
export interface SegmentResult {
|
|
4
|
+
/** Per-pixel component id; 0 is background. */
|
|
5
|
+
readonly labels: Int32Array;
|
|
6
|
+
/** Surviving components, in label order. */
|
|
7
|
+
readonly parts: readonly ComponentStats[];
|
|
8
|
+
readonly diagnostics: TraceDiagnostics;
|
|
9
|
+
}
|
|
10
|
+
export declare function segmentSheet(raster: DecodedRaster, params: TraceParams): SegmentResult;
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: The pipeline from pixels to "here are the N stickers" has to be ONE
|
|
3
|
+
* ordered sequence, because several of its steps are only correct in a
|
|
4
|
+
* particular order and each ordering mistake fails silently.
|
|
5
|
+
* WHAT: paper -> prefilter -> quantise -> ridge(+assist) -> flood -> clean ->
|
|
6
|
+
* label -> filter.
|
|
7
|
+
*
|
|
8
|
+
* 🛑 Fusion is implemented as the ridge detector's `assist` parameter rather
|
|
9
|
+
* than a separate `fuse` stage. A standalone module would have had to
|
|
10
|
+
* re-derive the ridge's own local-background field to know what "lower the
|
|
11
|
+
* bar" means, and two copies of that estimate is the drift this codebase keeps
|
|
12
|
+
* paying for (Root Cause #42/#75). The POLICY is documented at the assist
|
|
13
|
+
* branch in trace/ridge; this file only decides whether to supply it.
|
|
14
|
+
*
|
|
15
|
+
* EXPORTS: SegmentResult, segmentSheet
|
|
16
|
+
*
|
|
17
|
+
* @tag domain:sticker-trace
|
|
18
|
+
* @tag layer:shared
|
|
19
|
+
* @tag pattern:none
|
|
20
|
+
* @tag access:isomorphic
|
|
21
|
+
* @tag consumers:index,geometry,cluster
|
|
22
|
+
* @tag sideEffects:none
|
|
23
|
+
*/
|
|
24
|
+
import { labelComponents } from "../math/label.js";
|
|
25
|
+
import { close, curvatureSmooth } from "../math/morphology.js";
|
|
26
|
+
import { backgroundLikeMask, estimatePaper } from "./paper.js";
|
|
27
|
+
import { sameMaterialScore } from "./cross-profile.js";
|
|
28
|
+
import { floodFromBorder } from "./flood.js";
|
|
29
|
+
import { mergeWeakBoundaries } from "./merge.js";
|
|
30
|
+
import { applyPrefilter, toLuminance } from "./prefilter.js";
|
|
31
|
+
import { quantiseBoundaries } from "./quantise.js";
|
|
32
|
+
import { detectLines } from "./line-filter.js";
|
|
33
|
+
import { detectRidges, thresholdAdaptive } from "./ridge.js";
|
|
34
|
+
/**
|
|
35
|
+
* Re-derive per-component stats after a merge.
|
|
36
|
+
*
|
|
37
|
+
* The merge renumbers labels but cannot cheaply maintain areas and boxes — two
|
|
38
|
+
* merged regions' boxes are not the union of their stats unless you track it,
|
|
39
|
+
* and tracking it through union-find is more code than one more linear pass
|
|
40
|
+
* over a buffer already in cache.
|
|
41
|
+
*/
|
|
42
|
+
function recomputeStats(labels, count, width, height) {
|
|
43
|
+
const area = new Int32Array(count + 1);
|
|
44
|
+
const minX = new Int32Array(count + 1).fill(width);
|
|
45
|
+
const minY = new Int32Array(count + 1).fill(height);
|
|
46
|
+
const maxX = new Int32Array(count + 1).fill(-1);
|
|
47
|
+
const maxY = new Int32Array(count + 1).fill(-1);
|
|
48
|
+
const border = new Uint8Array(count + 1);
|
|
49
|
+
for (let y = 0; y < height; y++) {
|
|
50
|
+
for (let x = 0; x < width; x++) {
|
|
51
|
+
const l = labels[y * width + x];
|
|
52
|
+
if (l === 0)
|
|
53
|
+
continue;
|
|
54
|
+
area[l] = area[l] + 1;
|
|
55
|
+
if (x < minX[l])
|
|
56
|
+
minX[l] = x;
|
|
57
|
+
if (y < minY[l])
|
|
58
|
+
minY[l] = y;
|
|
59
|
+
if (x > maxX[l])
|
|
60
|
+
maxX[l] = x;
|
|
61
|
+
if (y > maxY[l])
|
|
62
|
+
maxY[l] = y;
|
|
63
|
+
if (x === 0 || y === 0 || x === width - 1 || y === height - 1)
|
|
64
|
+
border[l] = 1;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const stats = [];
|
|
68
|
+
for (let l = 1; l <= count; l++) {
|
|
69
|
+
if (area[l] === 0)
|
|
70
|
+
continue;
|
|
71
|
+
const bbox = {
|
|
72
|
+
x: minX[l],
|
|
73
|
+
y: minY[l],
|
|
74
|
+
width: maxX[l] - minX[l] + 1,
|
|
75
|
+
height: maxY[l] - minY[l] + 1,
|
|
76
|
+
};
|
|
77
|
+
stats.push({ label: l, area: area[l], bbox, touchesBorder: border[l] === 1 });
|
|
78
|
+
}
|
|
79
|
+
return { labels, count, stats };
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* A component covering more than this fraction of the raster is the SHEET, not
|
|
83
|
+
* a sticker — it means the flood never got in, usually because the barrier
|
|
84
|
+
* sealed the border or the scan has no background at all.
|
|
85
|
+
*
|
|
86
|
+
* Dropping it is right, and reporting it is what makes the failure legible:
|
|
87
|
+
* without the count in diagnostics, "the flood failed" and "this sheet has no
|
|
88
|
+
* stickers" look identical downstream.
|
|
89
|
+
*
|
|
90
|
+
* 🛑 KNOWN UNSUPPORTED, measured rather than assumed: a MONTAGE of several
|
|
91
|
+
* full-bleed sheets in one scan. `@ShayBlader Scan 18` is six sticker sheets in
|
|
92
|
+
* a 2x3 grid, each printed edge-to-edge in a different colour, white gutters
|
|
93
|
+
* between. At `standard` it returns ZERO parts by both models —
|
|
94
|
+
*
|
|
95
|
+
* paper path 6 components, 1 sheet-sized, 5 specks, backgroundCoverage 7.8%
|
|
96
|
+
* art path 1060 components, 1059 below the minimum area
|
|
97
|
+
*
|
|
98
|
+
* — because `estimatePaper` samples the outer frame and the gutters, gets
|
|
99
|
+
* 253,253,253, and reports `paper` for a scan that has no single background
|
|
100
|
+
* colour: the orange panel and the green panel disagree, and one estimate is
|
|
101
|
+
* wrong for five of the six.
|
|
102
|
+
*
|
|
103
|
+
* A projection-profile panel splitter was built for this and REVERTED. Measured
|
|
104
|
+
* over the corpus it was wrong in both directions at once: the montage still
|
|
105
|
+
* read as 1 panel, while single-sheet `driger G` (15 parts today) split into 5
|
|
106
|
+
* and `6894368129` into 2. The threshold had no separation to stand on — the
|
|
107
|
+
* highest non-gutter row reached 0.918 against a 0.92 cut-off, a margin of
|
|
108
|
+
* 0.002. Tightening it is the shape of tuning a constant until the numbers
|
|
109
|
+
* flatter it; the model is wrong for a montage, not the constant.
|
|
110
|
+
*
|
|
111
|
+
* So the honest handling is to DETECT and REPORT it — one sheet-sized component
|
|
112
|
+
* plus a low `backgroundCoverage` is the signature — and tell the admin to scan
|
|
113
|
+
* sheets individually or crop the montage. Every scan the user produces
|
|
114
|
+
* themselves is a single sheet; this one came from a third party.
|
|
115
|
+
*/
|
|
116
|
+
const MAX_PART_FRACTION = 0.6;
|
|
117
|
+
export function segmentSheet(raster, params) {
|
|
118
|
+
const { width, height } = raster;
|
|
119
|
+
const pxPerMm = raster.dpi ? raster.dpi / 25.4 : null;
|
|
120
|
+
const paper = estimatePaper(raster, params.scanType);
|
|
121
|
+
const luma = toLuminance(raster);
|
|
122
|
+
const filtered = applyPrefilter(luma, width, height, params.prefilter, params.prefilterRadius);
|
|
123
|
+
// Quantisation reads the PREFILTERED-era raster conceptually, but operates on
|
|
124
|
+
// colour, so it takes the original pixels. The ordering that matters is that
|
|
125
|
+
// the prefilter has already decided how much halftone survives into the
|
|
126
|
+
// luminance channel the ridge reads; the colour channel is independent and
|
|
127
|
+
// posterises the sheet's real flat regions either way.
|
|
128
|
+
const quant = params.quantiseEnabled
|
|
129
|
+
? quantiseBoundaries(raster, params.quantiseColours)
|
|
130
|
+
: null;
|
|
131
|
+
const ridge = detectRidges(filtered, width, height, {
|
|
132
|
+
low: params.ridgeHysteresisLow,
|
|
133
|
+
high: params.ridgeHysteresisHigh,
|
|
134
|
+
kernelScale: params.ridgeKernelScale,
|
|
135
|
+
...(quant ? { assist: quant.boundary, assistWeight: params.quantiseWeight } : {}),
|
|
136
|
+
});
|
|
137
|
+
/*
|
|
138
|
+
* 🛑 TWO SEGMENTATION MODELS, and the choice is not a tuning preference.
|
|
139
|
+
*
|
|
140
|
+
* A PAPER sheet has real background: the flood starts outside every sticker
|
|
141
|
+
* and anything it cannot reach is a sticker. Interior artwork edges are
|
|
142
|
+
* harmless because the outer cut line stops the flood long before it reaches
|
|
143
|
+
* them.
|
|
144
|
+
*
|
|
145
|
+
* An ART sheet has none. The printed field runs to the raster edge, so the
|
|
146
|
+
* flood starts INSIDE the artwork, gets trapped in every pocket the artwork's
|
|
147
|
+
* own edges enclose, and emits each pocket as a part. Measured: 209 parts
|
|
148
|
+
* against ~12 real on torch-pegases, and a threshold sweep down to 1.0%
|
|
149
|
+
* barrier coverage still gave 36 — monotonic, no minimum. The model is wrong
|
|
150
|
+
* there, not the constants.
|
|
151
|
+
*
|
|
152
|
+
* So an art sheet is segmented by partitioning on the cut lines and then
|
|
153
|
+
* merging back across the weak ones. See trace/merge.
|
|
154
|
+
*/
|
|
155
|
+
let labelled;
|
|
156
|
+
let beforeBridge;
|
|
157
|
+
let merges = 0;
|
|
158
|
+
let sameMaterialDropped = 0;
|
|
159
|
+
/*
|
|
160
|
+
* 1 on the art path, where the flood never runs and the question of "was
|
|
161
|
+
* there anything to flood through" does not arise. Reporting 0 there would
|
|
162
|
+
* read as a failure on every art sheet.
|
|
163
|
+
*/
|
|
164
|
+
let backgroundCoverage = 1;
|
|
165
|
+
if (paper.detectedType === "art") {
|
|
166
|
+
/*
|
|
167
|
+
* 🛑 A LINE filter, not the edge detector the paper path uses.
|
|
168
|
+
*
|
|
169
|
+
* Measured on torch-pegases, as the percentile a known cut-line pixel
|
|
170
|
+
* reaches against a known artwork edge:
|
|
171
|
+
*
|
|
172
|
+
* edge detector (local range) cuts p77.3 artwork p71.3 sep 5.9
|
|
173
|
+
* line filter (Hessian) cuts p69.2 artwork p50.2 sep 19.0
|
|
174
|
+
*
|
|
175
|
+
* The artwork drops from the 71st percentile to the 50th while the cuts
|
|
176
|
+
* hold, which is the whole difference: a groove has large curvature at its
|
|
177
|
+
* centre, a step edge has a zero crossing there.
|
|
178
|
+
*/
|
|
179
|
+
const lines = detectLines(filtered, width, height);
|
|
180
|
+
const lineBarrier = thresholdAdaptive(lines.response, width, height, params.ridgeHysteresisLow, params.ridgeHysteresisHigh);
|
|
181
|
+
const material = sameMaterialScore(raster, lineBarrier, filtered, params.paperTolerance * 2);
|
|
182
|
+
sameMaterialDropped = Math.round(material.meanScore * 1000);
|
|
183
|
+
const open = new Uint8Array(width * height);
|
|
184
|
+
for (let i = 0; i < open.length; i++)
|
|
185
|
+
open[i] = lineBarrier[i] ? 0 : 1;
|
|
186
|
+
const regions = labelComponents(open, width, height);
|
|
187
|
+
beforeBridge = regions.count;
|
|
188
|
+
const merged = mergeWeakBoundaries(regions.labels, regions.count, material.score, width, height, params.mergeStrengthFactor);
|
|
189
|
+
merges = merged.mergesApplied;
|
|
190
|
+
labelled = recomputeStats(merged.labels, merged.regionCount, width, height);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
const backgroundLike = backgroundLikeMask(raster, paper, params.paperTolerance);
|
|
194
|
+
let bgCount = 0;
|
|
195
|
+
for (let i = 0; i < backgroundLike.length; i++)
|
|
196
|
+
if (backgroundLike[i])
|
|
197
|
+
bgCount++;
|
|
198
|
+
backgroundCoverage = bgCount / (width * height);
|
|
199
|
+
const flood = floodFromBorder(backgroundLike, ridge.barrier, width, height, params.seedBandPx);
|
|
200
|
+
// Clean in this order: smooth the silhouette first so the bridge closing is
|
|
201
|
+
// not fighting comb teeth, then bridge. Reversing them bridges the teeth to
|
|
202
|
+
// each other and fuses neighbours.
|
|
203
|
+
let mask = curvatureSmooth(flood.inside, width, height, pxPerMm ? params.smoothMm * pxPerMm : 1);
|
|
204
|
+
beforeBridge = labelComponents(mask, width, height).count;
|
|
205
|
+
if (params.bridgeMm > 0) {
|
|
206
|
+
mask = close(mask, width, height, pxPerMm ? params.bridgeMm * pxPerMm : 2);
|
|
207
|
+
}
|
|
208
|
+
labelled = labelComponents(mask, width, height);
|
|
209
|
+
}
|
|
210
|
+
const minAreaPx = pxPerMm
|
|
211
|
+
? Math.max(16, params.minPartAreaMm2 * pxPerMm * pxPerMm)
|
|
212
|
+
: // No DPI: fall back to a fraction of the raster so the filter still
|
|
213
|
+
// removes speckle rather than being disabled entirely.
|
|
214
|
+
Math.max(16, width * height * 0.00002);
|
|
215
|
+
const maxAreaPx = width * height * MAX_PART_FRACTION;
|
|
216
|
+
let droppedSmall = 0;
|
|
217
|
+
let droppedSheet = 0;
|
|
218
|
+
const parts = [];
|
|
219
|
+
for (const stat of labelled.stats) {
|
|
220
|
+
if (stat.area > maxAreaPx) {
|
|
221
|
+
droppedSheet++;
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
if (stat.area < minAreaPx) {
|
|
225
|
+
droppedSmall++;
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
parts.push(stat);
|
|
229
|
+
}
|
|
230
|
+
// Largest first, so ordinal 1 is the most prominent sticker rather than
|
|
231
|
+
// whichever happened to be scanned top-left. A human renaming parts works
|
|
232
|
+
// down a list; starting with a 4mm registration dot reads as broken.
|
|
233
|
+
parts.sort((a, b) => b.area - a.area);
|
|
234
|
+
return {
|
|
235
|
+
labels: labelled.labels,
|
|
236
|
+
parts,
|
|
237
|
+
diagnostics: {
|
|
238
|
+
workingSize: { x: 0, y: 0, width, height },
|
|
239
|
+
paperColour: paper.detectedType === "paper" ? paper.colour : null,
|
|
240
|
+
ridgeCoverage: ridge.coverage,
|
|
241
|
+
quantiseCoverage: quant?.coverage ?? 0,
|
|
242
|
+
fusedCoverage: ridge.coverage,
|
|
243
|
+
componentsFound: labelled.count,
|
|
244
|
+
droppedBelowMinArea: droppedSmall,
|
|
245
|
+
droppedSheetSized: droppedSheet,
|
|
246
|
+
backgroundCoverage,
|
|
247
|
+
bridgedComponents: merges || Math.max(0, beforeBridge - labelled.count),
|
|
248
|
+
artBackgroundUnsupported: false,
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
}
|