COMPO · 6.02 · PHYSICAL SIZE / A-SERIES / DPI / VIEWING CONTEXT

Physical size,
A-series,
DPI & viewing.

Physical-format layer Topic 6: explicit millimeter dimensions, ISO A-series matching, raster PPI, separate print-device DPI and explicit viewing-distance geometry with angular extent / pixels-per-degree. Без скрытого A-series tolerance, без default viewing distance и без подмены PPI принтерным DPI.

ModuleCompo 6.02
Scopephysical / PPI / DPI / viewing
A-seriesexplicit policy
Viewingexplicit distance
Topic6 · FORMAT
Next6.03

Формат получает физический масштаб

00 / module api

6.02 связывает canvas с миллиметрами, raster sampling density, output-device DPI и explicit viewing distance.

SCOPE

physical size, A-series, PPI/DPI distinction, viewing geometry.

DOES NOT OWN

normalization, typography, safe zones, reflow.

FINALITY

PHYSICAL FORMAT / DENSITY / VIEWING CONTEXT ONLY.

PPI ≠ DPI. Raster PPI может связать pixels с inches. Printer DPI — количество device dots на inch и без explicit dot mapping не определяет физический размер canvas.

PhysicalCanvasMetadata

01 / physical size

Физический размер может быть explicit или вычислен только из достаточного raster mapping evidence.

Physical size

{
  physicalWidthMm,
  physicalHeightMm,

  diagonalMm,
  sizeSource,

  confidence,
  provenance
}

Valid sources

EXPLICIT_DOCUMENT

DERIVED_FROM:
  rasterExtentPx
  + raster PPI

STANDARD_FORMAT_BINDING
  only if explicitly bound

CUSTOM
NO DEVICE-DPI INFERENCE. `300 DPI printer` + `2480×3508 px image` недостаточно, чтобы считать физический размер A4, если не сказано, что raster должен выводиться 1 pixel → declared dot mapping.

Raster PPI

02 / raster density

PPI — плотность raster samples относительно физического размера. Mapping mode всегда explicit: scalar uniform PPI либо независимые ppiX/ppiY.

If physical size + raster size known: ppiX = widthPx / (widthMm / 25.4) ppiY = heightPx / (heightMm / 25.4) uniformityRelativeError = |ppiX - ppiY| / max(ppiX, ppiY)

UNIFORM

Axis densities agree within explicit policy tolerance.

ANISOTROPIC

Axis densities differ materially; do not hide this with one scalar PPI.

Raster + PPI → millimeters

03 / derive size

Обратное преобразование допустимо только для explicit raster PPI.

widthMm = widthPx / ppi × 25.4 heightMm = heightPx / ppi × 25.4 Example: 2480 × 3508 px at 300 PPI ≈ 209.97 × 297.01 mm
DERIVED ≠ STANDARD BINDING. Близость к A4 ещё не означает, что документ канонически A4. A-series match выполняется отдельно по declared policy.

Print DPI отдельно

04 / DPI firewall

DPI хранится как output-device metadata и не смешивается с canvas raster density.

Raster

PPI
pixels / inch

belongs to:
  raster↔physical mapping

Output device

DPI
dots / inch

belongs to:
  printer/device profile

needs dotMappingRef
for pixel↔dot semantics
NO ALIAS. `ppiMean=300` и `printDpi=300` могут численно совпасть, но это разные quantities, owners и evidence chains.

ISO A-series match

05 / A-series

A-series определяется по physical dimensions, orientation сравнивается отдельно. Tolerant policy не имеет права молча выбирать первый класс при нескольких совпадениях.

ClassNominal mm
A0841 × 1189
A1594 × 841
A2420 × 594
A3297 × 420
A4210 × 297
A5148 × 210
EXACT_NOMINAL_MM: unordered pair must match nominal pair exactly TOLERANT_MM: requires explicit tolerance for each side orientation: reported separately multiple matches: AMBIGUOUS_MATCH class = N/A

ViewingContextDescriptor

06 / viewing context

Viewing distance превращает миллиметры в angular size — но только если она explicit.

θ_width = 2 atan( widthMm / (2 × distanceMm) ) θ_height = 2 atan( heightMm / (2 × distanceMm) ) θ_diag = 2 atan( diagonalMm / (2 × distanceMm) ) convert radians → degrees
NO DEFAULT DISTANCE. «Плакат обычно смотрят с 2 метров» — не каноническое правило. Без `viewingDistanceMm` angular metrics = N/A.

Raster sampling в угловых единицах

07 / pixels per degree

Если известны raster pixels и angular extent, можно описать sampling density относительно зрения.

pixelsPerDegreeX = widthPx / angularWidthDeg pixelsPerDegreeY = heightPx / angularHeightDeg
DESCRIPTOR ONLY. 6.02 не превращает PPD в readability verdict и не выбирает размер шрифта. Это только viewing/sampling context для будущих owner-модулей.

Conflict detection

08 / consistency

Когда известны physical size, raster size и explicit PPI, они должны описывать один и тот же mapping.

Observed from size: ppiX_obs ppiY_obs Declared: ppi_declared If mappingMode = UNIFORM_PIXEL_DENSITY then both: ppiX_obs ≈ ppi_declared ppiY_obs ≈ ppi_declared within explicit ppiUniformityRelativeTolerance Otherwise: CONFLICT not silent averaging.

Viewing/scale invariants

09 / invariants

Physical viewing geometry имеет собственные scale laws.

Same physical size, distance ↑ → angular size ↓ Scale physical dimensions and viewing distance by same k > 0: angular size unchanged Raster pixels fixed, physical size ↑: PPI ↓ Physical size fixed, raster pixels ↑: PPI ↑

Что остаётся чужим

10 / ownership firewall

Physical context не превращает 6.02 в owner layout/readability решений.

ConceptOwner
canvas extent/aspect ratio6.00
orientation behavior6.01
physical/PPI/DPI/viewing context6.02
normalization6.03
adaptation/reflow6.04
safe/bleedTopic 7
typography/readability scoringfuture text/perception owners

Visual Lab

11 / visual lab

Один raster может иметь разные физические и viewing contexts.

A · RASTER → PHYSICAL 2480×3508 px @300 PPI ≈210×297 mm B · PPI ≠ DPI raster: 300 PPI printer: 1200 DPI different quantities C · VIEWING DISTANCE explicit distance → angular extent A-series class comes from physical mm + explicit match policy same physical size + farther distance → smaller visual angle 6.02 does not set typography, margins, safe zones or layout

Reference physical/viewing tests

12 / deterministic tests

Проверяем mm↔PPI conversion, A-series matching, PPI/DPI firewall, angular geometry, scale laws, missing evidence и ownership.

Tests not run yet.

DATA FOR LAYOUT ENGINE

13 / machine contract

Machine-readable 6.02 contract.

{
  "module": "Compo 6.02",
  "name": "physical_size_a_series_dpi_and_viewing_context",
  "version": "1.1-corrective",
  "canonical_main_title": "Physical size, A-series, DPI, viewing context",
  "topic": "06_ФОРМАТ_ПОСТЕРА_И_СООТНОШЕНИЕ_СТОРОН",
  "scope": "PHYSICAL_CANVAS_SIZE_RASTER_DENSITY_PRINT_DPI_STANDARD_FORMAT_AND_VIEWING_GEOMETRY",
  "consumes": [
    "Compo6.00.CanvasDescriptor",
    "Compo6.00.rasterExtentPx?",
    "PhysicalSizeInput?",
    "RasterDensityInput?",
    "PrintDeviceDensityInput?",
    "ViewingContextInput?",
    "PhysicalFormatPolicy"
  ],
  "provides": [
    "PhysicalCanvasMetadata",
    "AseriesMatchResult",
    "RasterDensityResult",
    "PrintDeviceDensityDescriptor",
    "ViewingContextDescriptor",
    "MetricResult[canvas.physical.widthMm]",
    "MetricResult[canvas.physical.heightMm]",
    "MetricResult[canvas.physical.diagonalMm]",
    "MetricResult[canvas.physical.ppiX]",
    "MetricResult[canvas.physical.ppiY]",
    "MetricResult[canvas.physical.ppiMean]",
    "MetricResult[canvas.physical.angularWidthDeg]",
    "MetricResult[canvas.physical.angularHeightDeg]",
    "MetricResult[canvas.physical.angularDiagonalDeg]",
    "MetricResult[canvas.physical.pixelsPerDegreeX]",
    "MetricResult[canvas.physical.pixelsPerDegreeY]",
    "MetricResult[canvas.physical.confidence]",
    "physicalMetadataRef for CanvasDescriptor",
    "PhysicalFormatCorrectionRequest[]"
  ],
  "owns_metrics": [
    "canvas.physical.widthMm",
    "canvas.physical.heightMm",
    "canvas.physical.diagonalMm",
    "canvas.physical.ppiX",
    "canvas.physical.ppiY",
    "canvas.physical.ppiMean",
    "canvas.physical.angularWidthDeg",
    "canvas.physical.angularHeightDeg",
    "canvas.physical.angularDiagonalDeg",
    "canvas.physical.pixelsPerDegreeX",
    "canvas.physical.pixelsPerDegreeY",
    "canvas.physical.confidence"
  ],
  "descriptors_only": [
    "canvas.physical.sizeSource",
    "canvas.physical.aSeriesClass",
    "canvas.physical.aSeriesOrientation",
    "canvas.physical.ppiUniformityStatus",
    "canvas.physical.printDpi",
    "canvas.physical.viewingDistanceMm",
    "canvas.physical.viewingContextRef",
    "canvas.physical.status"
  ],
  "physical_size_input_schema": {
    "physicalWidthMm": "finite >0",
    "physicalHeightMm": "finite >0",
    "source": "EXPLICIT_DOCUMENT|DERIVED_FROM_RASTER_AND_PPI|STANDARD_FORMAT_BINDING|CUSTOM",
    "confidence": "0..1",
    "provenance": "object"
  },
  "raster_density_input_schema": {
    "mappingMode": "UNIFORM_PIXEL_DENSITY|INDEPENDENT_AXIS_DENSITY",
    "UNIFORM_PIXEL_DENSITY": "requires scalar ppi >0; optional ppiX/ppiY may be supplied only as consistency evidence and must both agree with scalar ppi within policy tolerance",
    "INDEPENDENT_AXIS_DENSITY": "requires ppiX>0 and ppiY>0; scalar ppi is forbidden because it would hide anisotropy",
    "provenance": "object",
    "rule": "density representation is explicit; no partial one-axis density"
  },
  "print_device_density_input_schema": {
    "dpi": "finite >0",
    "deviceRef": "optional output device/profile ref",
    "dotMappingRef": "optional explicit pixel-to-dot mapping",
    "provenance": "object",
    "important": "DPI describes output device dots per inch and is not interchangeable with raster PPI",
    "validation": "dpi must be finite >0 when supplied"
  },
  "viewing_context_input_schema": {
    "viewingContextRef": "string",
    "viewingDistanceMm": "finite >0",
    "viewerMode": "SINGLE_VIEWER|ESTIMATED_DISTANCE|CUSTOM",
    "confidence": "0..1",
    "provenance": "object",
    "no_default_distance": "missing distance means angular metrics N/A",
    "validation": "viewingContextRef + viewingDistanceMm + confidence are required when viewing context is supplied"
  },
  "physical_format_policy": {
    "aSeriesMatchMode": "EXACT_NOMINAL_MM|TOLERANT_MM",
    "aSeriesToleranceMm": "required finite >=0 only for TOLERANT_MM",
    "ppiUniformityRelativeTolerance": "finite >=0",
    "provenance": "STANDARD|STYLE_PRESET|EMPIRICAL|INITIAL_HEURISTIC"
  },
  "a_series_nominal_mm": {
    "standard": "ISO 216 nominal dimensions",
    "orientation_independent_match": true,
    "sizes": {
      "A0": [
        841,
        1189
      ],
      "A1": [
        594,
        841
      ],
      "A2": [
        420,
        594
      ],
      "A3": [
        297,
        420
      ],
      "A4": [
        210,
        297
      ],
      "A5": [
        148,
        210
      ],
      "A6": [
        105,
        148
      ],
      "A7": [
        74,
        105
      ],
      "A8": [
        52,
        74
      ],
      "A9": [
        37,
        52
      ],
      "A10": [
        26,
        37
      ]
    },
    "important": "nominal integer-mm table; no hidden fuzzy matching"
  },
  "a_series_semantics": {
    "EXACT_NOMINAL_MM": "unordered physical dimension pair must equal nominal integer-mm pair exactly",
    "TOLERANT_MM": "each unordered side may deviate by <= explicit aSeriesToleranceMm",
    "orientation": "PORTRAIT if physicalHeightMm>physicalWidthMm; LANDSCAPE if width>height; SQUARE is not an A-series nominal case",
    "no_physical_size": "aSeriesClass=N_A",
    "match_is_descriptor": "A4/A3/etc. is not a quality score",
    "ambiguous_tolerant_match": "if an explicit tolerance matches more than one nominal A-series class, result is AMBIGUOUS_MATCH and no class is guessed"
  },
  "raster_physical_mapping": {
    "derive_size_from_uniform_ppi": "widthMm = widthPx / ppi * 25.4; heightMm = heightPx / ppi * 25.4",
    "derive_axis_ppi_from_size": "ppiX = widthPx / (widthMm/25.4); ppiY = heightPx / (heightMm/25.4)",
    "uniformity_relative_error": "abs(ppiX-ppiY)/max(ppiX,ppiY)",
    "uniform_status": "UNIFORM|ANISOTROPIC|N_A",
    "ppiMean": "arithmetic mean of ppiX/ppiY only when both are valid; descriptor, not printer DPI",
    "conflict": "if explicit physical size + explicit uniform ppi + raster dimensions disagree beyond declared tolerance => INVALID/CONFLICT",
    "derive_size_from_independent_axis_ppi": "widthMm = widthPx/ppiX*25.4; heightMm = heightPx/ppiY*25.4",
    "independent_axis_conflict": "when physical size is also explicit, observed ppiX/ppiY must agree with declared independent axis densities within explicit policy tolerance",
    "mapping_mode_required": "density evidence without explicit mappingMode is INVALID rather than guessed"
  },
  "ppi_dpi_firewall": {
    "PPI": "pixels per inch; raster-to-physical sampling density",
    "DPI": "printer/output device dots per inch",
    "physical_size_inference": "PPI may infer size from raster pixels; DPI may not unless dotMappingRef explicitly defines pixel-to-dot mapping",
    "forbidden_alias": "canvas.physical.ppiMean != canvas.physical.printDpi",
    "quality_warning": "higher PPI or DPI is not automatically better without task/output context"
  },
  "viewing_geometry": {
    "angularWidthDeg": "2*atan(widthMm/(2*viewingDistanceMm))*180/pi",
    "angularHeightDeg": "2*atan(heightMm/(2*viewingDistanceMm))*180/pi",
    "angularDiagonalDeg": "2*atan(diagonalMm/(2*viewingDistanceMm))*180/pi",
    "pixelsPerDegreeX": "rasterWidthPx/angularWidthDeg when both exist",
    "pixelsPerDegreeY": "rasterHeightPx/angularHeightDeg when both exist",
    "distance_increase": "angular extents decrease monotonically as viewing distance increases",
    "common_physical_scale_with_distance": "scaling physical size and viewing distance by same factor preserves angular extent"
  },
  "ownership_map": {
    "6.00": "raw canvas geometry / aspect ratio / raster extent slot",
    "6.01": "square/portrait/landscape behavior",
    "6.02": "physical size / A-series / raster PPI / print DPI descriptor / viewing geometry",
    "6.03": "normalization and scale-invariance contract",
    "6.04": "adaptation hooks and tests"
  },
  "handoff_contracts": {
    "to_6.03": "physical metrics are context descriptors; 6.03 decides which normalized coordinate contracts are canonical",
    "to_6.04": "changes in physical size/PPI/viewing context become adaptation/recompute evidence",
    "to_typography_future": "pixels-per-degree/angular extent may be consumed later; 6.02 does not set font sizes",
    "to_topic7": "physical safe/bleed conversion may consume 6.02 physical size but safe/bleed ownership remains Topic7"
  },
  "metric_policy": {
    "physical_size": "descriptor only",
    "ppi": "descriptor only",
    "dpi": "device descriptor only",
    "angular_extent": "viewing-geometry descriptor only",
    "pixels_per_degree": "sampling/viewing descriptor only",
    "direct_scoring": "FORBIDDEN in 6.02",
    "higher_ppi_is_better": "FORBIDDEN",
    "higher_dpi_is_better": "FORBIDDEN",
    "larger_physical_size_is_better": "FORBIDDEN",
    "larger_angular_extent_is_better": "FORBIDDEN"
  },
  "hard_constraints": [
    "one metric = one owner",
    "6.02 must consume 6.00 raster extent/canvas identity and must not recompute canvas aspect geometry from content",
    "physicalWidthMm and physicalHeightMm must be positive finite when present",
    "no physical size may be invented from DPI alone",
    "PPI and DPI are distinct concepts and may never be aliased",
    "uniform scalar PPI may derive physical size only when raster pixel dimensions are known",
    "physical size + raster dimensions may derive ppiX/ppiY",
    "explicit uniform PPI conflicting with physical size/raster mapping beyond policy tolerance is invalid",
    "anisotropic ppiX/ppiY must be reported explicitly and not averaged into a fake uniform mapping",
    "A-series matching requires explicit physical dimensions and explicit match policy",
    "tolerant A-series matching requires explicit tolerance; no hidden mm tolerance",
    "A-series classification is orientation-insensitive with orientation reported separately",
    "viewing angular metrics require explicit viewingDistanceMm and physical size; no default viewing distance",
    "pixelsPerDegree requires both raster pixels and valid angular extent",
    "6.02 must not prescribe typography size, line length, margin, grid, safe area, object size, or layout",
    "physical size/viewing context do not replace 6.03 normalization contract",
    "stateful adaptation to physical/viewing changes remains 6.04",
    "safe/bleed ownership remains Topic7",
    "grid occupancy remains Topic8",
    "global balance/hierarchy/eye-flow remain future owners",
    "N/A != 0",
    "no beautyScore",
    "RasterDensityInput.mappingMode is mandatory when density evidence is supplied",
    "INDEPENDENT_AXIS_DENSITY requires both ppiX and ppiY and forbids scalar ppi aliasing",
    "TOLERANT_MM A-series matching that matches multiple nominal classes yields AMBIGUOUS_MATCH rather than selecting the first table entry",
    "print-device DPI must be positive finite when present",
    "viewing context must carry an explicit ref, positive distance and confidence when present"
  ],
  "initial_heuristics": {
    "reference_ppi_uniformity_relative_tolerance": {
      "value": 0.005,
      "provenance": "STYLE_PRESET",
      "note": "not a global default"
    },
    "numeric_epsilon": {
      "value": 1e-12,
      "provenance": "IMPLEMENTATION_HEURISTIC"
    }
  },
  "correction_policy": {
    "foreign_canvas_or_content_mutation": "FORBIDDEN",
    "missing_physical_size": "request explicit size or raster+PPI mapping",
    "ppi_physical_conflict": "request document/export pipeline owner correction",
    "dpi_ppi_confusion": "request explicit raster PPI or device dot-mapping; do not infer",
    "a_series_match_policy_missing": "request PhysicalFormatPolicy",
    "viewing_distance_missing": "request explicit ViewingContextInput",
    "normalization_issue": "route to Compo6.03",
    "adaptation_issue": "route to Compo6.04",
    "safe_bleed_issue": "route to Topic7"
  },
  "deferred_inputs": [
    "Compo6.03 normalization / scale-invariance contract",
    "Compo6.04 adaptation hooks / regression",
    "Topic7 physical safe/bleed conversion",
    "future typography/readability modules using angular metrics",
    "future global balance/hierarchy/eye-flow"
  ],
  "recompute_when": [
    "physical width/height changes",
    "raster extent changes",
    "PPI mapping changes",
    "print DPI/device profile changes",
    "A-series match policy changes",
    "viewing distance/context changes"
  ],
  "finality": "PHYSICAL_FORMAT_DENSITY_AND_VIEWING_CONTEXT_ONLY"
}
ARCHITECTURE CHECKPOINT · 6.02 OWNS PHYSICAL MM SIZE, A-SERIES MATCHING, RASTER PPI, PRINT-DPI DESCRIPTOR AND EXPLICIT VIEWING GEOMETRY. PPI ≠ DPI. DPI ALONE CANNOT INFER CANVAS SIZE. A-SERIES NEEDS PHYSICAL DIMENSIONS + EXPLICIT MATCH POLICY. VIEWING ANGLES NEED EXPLICIT DISTANCE. 6.02 DOES NOT SET TYPOGRAPHY, MARGINS, SAFE ZONES, NORMALIZATION OR REFLOW. 6.03 OWNS NORMALIZATION; 6.04 ADAPTATION; TOPIC7 SAFE/BLEED. NO BEAUTYSCORE.
VISITS / ...