# SmartRIP OPC UA Printing Workflows Technical white paper for TIFF, softproof, direct Meteor output, manual page shooting, and QR-triggered page shooting. Document date: 2026-04-28 Primary source code: - `SmartRip_CLI`: one-shot print workflow for a file. - `SmartRip_PageShooter`: operator-driven on-demand page printing. - `SmartRip_NewPageShooter`: camera-driven QR workflow that triggers page printing. Authoritative interface reference: - Hybrid Helix SmartRIP user guide: https://documentation.hybridhelix.com/sdfe/user-guide-smartrip Local reference material: - `ReadMe.md` - `readme_opc.txt` - `SmartRip_CLI/ReadMe.md` - `SmartRip_NewPageShooter/README.md` - `SmartRip_NewPageShooter/QUICKSTART.md` ## Abstract SmartRIP is a headless industrial raster image processor exposed through an OPC UA server. It allows a printer controller, production workflow, or engineering tool to load PDF jobs, configure media and rendering parameters, start a print run, and monitor job progress without operating a separate RIP user interface. The sample applications in this repository demonstrate three integration patterns: 1. A command-line print workflow that rasterizes a complete job or page range. 2. An interactive page shooter that renders individual pages on demand. 3. A QR-driven page shooter that waits for a camera to identify the page number to render. The same OPC UA sequence underpins all three: connect to SmartRIP, ensure no stale print run is active, configure the `Prepare` node, start the `Print` node's print run, call `StartPrinting(pageRange)`, then poll print status until completion. Output can be generated as TIFF files, softproof output, or sent through a direct Meteor output plugin to Meteor print electronics. This white paper explains the architecture, prerequisites, node model, workflows, implementation details, diagnostics, performance considerations, and best practices required for robust engineering integration. ## Introduction Industrial digital printers must combine file interpretation, color management, screening, printhead compensation, and real-time electronics control. A production printer controller usually owns the operator interface and machine state, while a RIP is responsible for converting input files such as PDF into raster data suitable for the print engine. SmartRIP is designed for this embedded role. It runs in the background and exposes its capabilities through OPC UA, allowing a Smart Print Controller or another automation client to drive it programmatically. This removes the need for operators to manage a separate RIP application, while still providing standard industrial communication semantics, discoverable nodes, typed method calls, structured status, and certificate-based security. Meteor boards are the print electronics layer used to drive printheads. In a file-based workflow, SmartRIP renders TIFF files to disk and downstream software consumes those files. In a direct-to-Meteor workflow, SmartRIP uses a Meteor output plugin so raster data can flow toward the Meteor print engine without writing intermediate TIFF data as the main transport. This reduces disk I/O, lowers workflow complexity, and can improve throughput, especially for variable data printing. The marketing positioning is technically consistent with the integration model: - SmartRIP integrates PDF rendering, screening, and color management behind a controllable interface. - SmartRIP can be driven through OPC UA from the printer manufacturer interface. - GPU acceleration may be used by the RIP to reduce CPU load where enabled and licensed. - Direct output plugins can avoid intermediate TIFF files and connect the raster pipeline closer to print electronics. ## System Architecture ### Logical Components The sample system consists of the following engineering components. | Component | Responsibility | | --- | --- | | Smart Print Controller | The host application, CLI, or printer HMI that owns the workflow and calls OPC UA. In this repository, the C# command-line tools act as the controller. | | OPC UA communication layer | The typed client interface between controller and SmartRIP. Implemented by `OpcUaService` using `Opc.UaFx.Client`. | | SmartRIP OPC UA server | The SmartRIP service endpoint, normally `opc.tcp://localhost:26942/smartrip`, exposing nodes such as `App`, `Media`, `Prepare`, `Print`, `Meteor`, and `Status`. | | SmartRIP render pipeline | PDF loading, media selection, color management, screening, optional GPU rendering, and output plugin dispatch. | | Output plugin | The selected output type, such as `Tiff`, `SoftProof`, or an installed Meteor output plugin. | | Meteor board and MeteorRouter | The print electronics path for direct device output. The official interface exposes Meteor-specific state and control under the `Meteor` and `Status` nodes. | | Camera and QR reader | Used only by `SmartRip_NewPageShooter`; OpenCV reads QR payloads and places page numbers into a work queue. | ### Architecture Diagram ```mermaid flowchart LR HMI["Smart Print Controller / CLI / HMI"] --> Client["C# OPC UA Client
OpcUaService"] Client --> Endpoint["SmartRIP OPC UA Server
opc.tcp://localhost:26942/smartrip"] Endpoint --> App["App Node
version, log, exit"] Endpoint --> Media["Media Node
installed .smd media"] Endpoint --> Prepare["Prepare Node
job and render settings"] Endpoint --> Print["Print Node
run lifecycle and progress"] Endpoint --> Meteor["Meteor Node
Meteor-specific control"] Endpoint --> Status["Status Node
Meteor runtime counters"] Prepare --> Pipeline["SmartRIP Render Pipeline
PDF, color, screening, GPU"] Print --> Pipeline Pipeline --> Tiff["TIFF Files"] Pipeline --> SoftProof["SoftProof Output"] Pipeline --> Direct["Meteor Output Plugin"] Direct --> Board["Meteor Board / Print Engine"] Board --> Heads["Printheads"] ``` ### Data Flow 1. The controller validates input paths and command parameters. 2. `OpcUaService` connects to SmartRIP at `opc.tcp://localhost:26942/smartrip`. 3. The controller writes job-ticket settings to the `Prepare` node. 4. The controller loads the PDF by calling `Prepare/LoadJobFromPath(jobName, filePath)`. 5. The controller starts a print run by calling `Print/PrintRunStart()`. 6. The controller waits until `Print/PrintRunState` reports a ready state, normally `Started`. 7. The controller calls `Print/StartPrinting(pageRange)`. 8. SmartRIP renders the requested pages and sends output to the selected plugin. 9. The controller monitors `Print/JobState`, `Print/PagesProcessed`, `Print/PagesTotal`, and, when direct Meteor output is active, `Status` and `Meteor` nodes. 10. The controller calls `Print/PrintRunStop()` at the end of the run or when the session exits. ## Prerequisites and Requirements ### Hardware - Windows workstation or industrial PC running SmartRIP. - CPU and memory sized for the input PDF complexity, resolution, color channels, screening, and throughput target. - GPU hardware and compatible driver if GPU rendering is enabled. - Disk capacity and write bandwidth for TIFF or softproof output workflows. - Meteor print electronics and MeteorRouter for direct-to-Meteor workflows. - Camera for `SmartRip_NewPageShooter` QR triggering. - Network connectivity if the controller and SmartRIP server are not on the same host. ### Software - SmartRIP installed and licensed. - SmartRIP OPC UA endpoint enabled and reachable at the configured endpoint. - Smart media definitions (`.smd`) installed through Smart Media Manager, MediaBridge, or OPC UA `Media` methods. - .NET SDK: - `SmartRip_CLI` targets `net9.0`. - `SmartRip_PageShooter` targets `net9.0`. - `SmartRip_NewPageShooter` targets `net8.0`. - NuGet dependencies: - `Opc.UaFx.Client` - `NClap` - `OpenCvSharp4`, `OpenCvSharp4.runtime.win`, and `System.Management` for `SmartRip_NewPageShooter`. ### Configuration - SmartRIP must trust the OPC UA client certificate, and the client must trust SmartRIP's certificate where security is enabled. - At least one media entry must be available under `Media/MediaNames`. - The selected `Prepare/MediaName` must exactly match an installed media entry. - `Prepare/OutputType` must match one of `Prepare/AvailableOutputTypes`. - `Prepare/OutputPath` must be writable by the SmartRIP process for disk-based output types such as `Tiff` and commonly for softproof workflows. - For direct Meteor output, the Meteor output plugin must be installed and visible as an available output type or plugin path for the deployment. ## OPC UA Communication Setup ### Server and Client Roles SmartRIP is the OPC UA server. The C# applications are OPC UA clients. The official default endpoint is: ```text opc.tcp://localhost:26942/smartrip ``` The sample code uses namespace index `2` for SmartRIP nodes. Examples: ```text ns=2;s=App/VersionNumber ns=2;s=Media/MediaNames ns=2;s=Prepare/OutputType ns=2;s=Print/PrintRunState ``` Method calls use an object node and a method node. For example, `StartPrinting` is called on object `Print` with method `Print/StartPrinting`: ```csharp var response = client.CallMethod( new OpcNodeId("Print", 2), new OpcNodeId("Print/StartPrinting", 2), pageRange); ``` ### Address Space and Nodes The official documentation defines a root `SmartRIPSet` containing major node groups. The code in this repository uses these groups: | Node | Role | Used by sample code | | --- | --- | --- | | `App` | Application version, log access, application exit, log writes. | `GetVersion()` reads `App/VersionNumber`. | | `Media` | Installed media library and `.smd` media management. | `GetAvailableMedia()`, `InstallMediaFromPath()`, `UninstallMedia()`. | | `Prepare` | Job input and settings before printing. | `LoadJobFromPath()`, `SetPrepareSettings()`, `SetSelectedMedia()`. | | `Print` | Print run lifecycle, page-range submission, thumbnailing, status. | `PrintRunStart()`, `StartPrintWithoutWaiting(pageRange)`, `EnsurePrintRunStopped()`, `GetPrintProgress()`. | | `Meteor` | Meteor-specific ownership, parameters, signals, head power, errors. | Not wrapped in the current C# sample, but required for direct Meteor integrations that need electronics control. | | `Status` | Meteor runtime status counters, queue levels, encoder/PD counts. | Not wrapped in the current C# sample, but should be monitored in direct Meteor production systems. | ### Data Models Relevant to Printing The sample code models prepare settings with `PrepareSettings`: ```csharp public class PrepareSettings { public string[] AvailableOutputTypes { get; set; } public int CopyCount { get; set; } public bool EnableScreening { get; set; } public string OutputPath { get; set; } public string OutputType { get; set; } public string PageRange { get; set; } } ``` Officially, `pageRange` is not written as `Prepare/PageRange` on the current SmartRIP interface. It is the input argument to `Print/StartPrinting(String pageRange)`. The local `PageRange` property is therefore best understood as application state used to pass the string into `StartPrinting`. The completed job metadata model is `SmartRipJobMetadata`. It serializes useful audit data such as input filename, media, output type, copy count, screening flag, page range, output folder, thumbnail path, and creation time. ### Security Considerations OPC UA communication requires client and server application certificates. A production deployment should: - Generate stable application certificates for controller and SmartRIP. - Place each peer certificate in the correct trusted store. - Avoid trusting arbitrary unknown certificates in production. - Use encryption and signing policies appropriate for the machine network. - Treat `App/Exit()` as privileged because it can shut down SmartRIP. - Restrict access to `Media/InstallMediaFromPath`, `Media/UninstallMedia`, and Meteor methods to trusted engineering or controller clients. - Avoid exposing the OPC UA endpoint beyond the protected printer-control network. The sample code demonstrates client-side certificate behavior indirectly through the `Opc.UaFx.Client` stack and stores generated under output folders such as `CertificateStores`. Production installers should manage certificate placement explicitly. ## Printing Workflow ### Standard Print Sequence The official workflow is: 1. Install and select media. 2. Prepare the job. 3. Start the print run. 4. Submit printing with `StartPrinting(pageRange)`. 5. Monitor progress. 6. Stop the print run. The sample applications expand that into an implementation sequence: ```mermaid sequenceDiagram participant C as Controller participant O as OpcUaService participant S as SmartRIP OPC UA participant R as Render Pipeline participant P as Output Plugin C->>O: Open() O->>S: Connect C->>O: EnsurePrintRunStopped() O->>S: Read Print/PrintRunState O->>S: Call Print/PrintRunStop() if needed C->>O: LoadJobFromPath(jobName, pdfPath) O->>S: Call Prepare/LoadJobFromPath(jobName, pdfPath) O->>S: Call Print/StartThumbnailing(256) O->>S: Poll Print/JobThumbnail C->>O: SetPrepareSettings(...) O->>S: Write Prepare/CopyCount, EnableScreening, OutputPath, OutputType C->>O: SetSelectedMedia(mediaName) O->>S: Write Prepare/MediaName C->>O: PrintRunStart() O->>S: Call Print/PrintRunStart() C->>O: Wait until PrintRunState == Started C->>O: StartPrintWithoutWaiting(pageRange) O->>S: Call Print/StartPrinting(pageRange) S->>R: Render selected pages R->>P: Send raster output C->>O: Poll progress O->>S: Read JobState, PagesProcessed, PagesTotal, PrintRunState C->>O: EnsurePrintRunStopped() ``` ### Job Preparation Job preparation configures SmartRIP before the print run is active. The official documentation states that requests to modify configuration are locked once a print run becomes active. In practice: - Stop any previous print run before changing prepare settings. - Load the job before print submission. - Write output type, output path, copy count, screening, and media while the print run is stopped. - Use the `StartPrinting(pageRange)` method argument for page selection. Typical settings: | Setting | OPC node | Notes | | --- | --- | --- | | Media | `Prepare/MediaName` | Must match an installed media from `Media/MediaNames`. | | Output type | `Prepare/OutputType` | Must match `Prepare/AvailableOutputTypes`. Common values in the sample are `Tiff` and `SoftProof`. Meteor output depends on installed plugins. | | Output path | `Prepare/OutputPath` | Required for file-based output such as TIFF. It may be ignored or plugin-specific for direct Meteor output. | | Copy count | `Prepare/CopyCount` | Integer number of collated job copies. | | Screening | `Prepare/EnableScreening` | `true` enables screening. `false` produces unscreened rendered output where supported. | | GPU | `Prepare/EnableGPU` | Documented by the official interface, but not currently wrapped by the sample code. | | Page range | method input | Passed to `Print/StartPrinting(pageRange)`, not written as a `Prepare` node. | ### Page Range Syntax `StartPrinting(String pageRange)` uses standard page range syntax: | Value | Effect | | --- | --- | | `""`, `all`, `1-` | Print all pages. | | `3` | Print page 3 only. | | `1-5` | Print pages 1 through 5. | | `3-` | Print page 3 through the end of the document. | | `1-3,5,7-9` | Print pages 1, 2, 3, 5, 7, 8, and 9. | | `odd` | Print odd-numbered pages. | | `even` | Print even-numbered pages. | ### TIFF Output Workflow TIFF is the simplest file-based output. 1. Read `Prepare/AvailableOutputTypes` and confirm `Tiff`. 2. Set `Prepare/OutputType = "Tiff"`. 3. Set `Prepare/OutputPath` to a writable output folder. 4. Set `Prepare/CopyCount`. 5. Set `Prepare/EnableScreening`. 6. Set `Prepare/MediaName`. 7. Call `Prepare/LoadJobFromPath(jobName, pdfPath)`. 8. Call `Print/PrintRunStart()`. 9. Poll `Print/PrintRunState` until `Started`. 10. Call `Print/StartPrinting(pageRange)`. 11. Poll `Print/JobState` until `Success`, `Failed`, or `Cancelled`. 12. Call `Print/PrintRunStop()`. Example command from `SmartRip_CLI`: ```powershell .\SmartRip_CLI.exe print "C:\Jobs\Vdp_job_output.pdf" "C:\Output\SmartRip" ` -MediaName "Default KCMY Press Profile (Incomplete)" ` -OutputType Tiff ` -CopyCount 1 ` -EnableScreening ` -PageRange "1-" ``` ### Softproof Workflow Softproof is a file-based proofing output mode where the output type is `SoftProof`, assuming it appears in `Prepare/AvailableOutputTypes`. Correct current-interface sequence: 1. Stop existing print run. 2. Load job with `Prepare/LoadJobFromPath(jobName, filePath)`. 3. Set `Prepare/OutputType = "SoftProof"`. 4. Set `Prepare/OutputPath` to a softproof folder. 5. Set `Prepare/CopyCount = 1`. 6. Set `Prepare/EnableScreening` according to proofing intent. 7. Set `Prepare/MediaName`. 8. Call `Print/PrintRunStart()`. 9. Poll `Print/PrintRunState` until `Started`. 10. Call `Print/StartPrinting(pageRange)`, for example `"1"` for a single-page softproof. 11. Poll the output folder or `Print/JobState` until the proof output is available. 12. Stop the print run. Important implementation note: some legacy helper code in the repository's `GenerateSoftproofPreview()` methods writes `Prepare/PageRange` and calls `StartPrinting()` without a `pageRange` argument. That pattern is not aligned with the current official interface. Production softproof code should pass page selection into `StartPrinting(pageRange)`. ### Direct Meteor Output Workflow Direct Meteor output depends on a Meteor output plugin and media configuration suitable for the target printer. The exact `OutputType` string is installation-specific and must be discovered through `Prepare/AvailableOutputTypes` or plugin documentation. Do not hard-code `Meteor` unless the deployed system exposes that exact output type. Recommended sequence: 1. Confirm SmartRIP can reach MeteorRouter and the board hardware. 2. Confirm the direct Meteor output plugin appears in `Prepare/AvailableOutputTypes`. 3. Set `Prepare/OutputType` to the Meteor output plugin name. 4. Set media, copy count, screening, and other prepare settings. 5. Load the job with `Prepare/LoadJobFromPath`. 6. Call `Print/PrintRunStart()`. 7. Poll `Print/PrintRunState` until `Started`. 8. Read Meteor state: - `Meteor/IsEnabled` - `Meteor/IsRouterConnected` - `Meteor/IsBootCycleComplete` - `Meteor/IsPrinterInterfaceAcquired` 9. If the integration needs low-level electronics control, use `Meteor` methods such as: - `AcquirePrinterInterface()` - `ReleasePrinterInterface()` - `SetHeadPower(Boolean power)` - `SetParam(...)` - `SetParamEx(...)` - `SetSignal(...)` - `UpdateXOffsets()` - `ForcePD()` 10. Call `Print/StartPrinting(pageRange)`. 11. Monitor print progress under `Print` and Meteor status under `Status`. 12. Call `Print/PrintRunStop()` when the run is complete. Direct Meteor output shifts performance risk from disk throughput to synchronization, buffering, device ownership, router connectivity, and real-time board status. The controller should monitor both RIP state and Meteor runtime counters such as buffer level, queued documents, print count, PD count, and printer status. ### On-Demand Page Shooter Workflow `SmartRip_PageShooter` loads the job and media once, then prompts the operator for page numbers. It keeps the print run open after the first page so subsequent pages can be submitted faster. ```mermaid flowchart TD A["Start PageShooter"] --> B["Connect and validate SmartRIP"] B --> C["Stop previous print run"] C --> D["Load job and thumbnail"] D --> E["Read prepare settings and select media"] E --> F["Wait for user page input"] F --> G{"Blank input?"} G -->|Yes| H["Stop print run if opened, exit"] G -->|No| I["Create rip/page_N output folder"] I --> J["Write prepare settings for folder/output"] J --> K["Open print run if first page"] K --> L["Call StartPrinting(pageNumber)"] L --> M["Poll JobState"] M --> F ``` ### QR-Triggered Page Shooter Workflow `SmartRip_NewPageShooter` replaces manual page entry with OpenCV QR detection. 1. Start command `pageshooter`. 2. Optionally list cameras with `-l`. 3. Initialize SmartRIP context using `PageShooterWorkflow.Initialize`. 4. Start `QrCameraReader` in a background task. 5. Decode JSON payloads such as `{"Page": 7}`. 6. Deduplicate repeated camera reads for a short window. 7. Queue the page number. 8. Print each queued page through `PageShooterWorkflow.PrintPage`. 9. On `Ctrl+C`, cancel the camera loop, complete the queue, stop the print run, and dispose resources. Example command: ```powershell dotnet run --project .\SmartRip_NewPageShooter -- pageshooter ` "C:\Jobs\MyFile.pdf" ` "C:\Jobs\Output" ` -m "Default KCMY Press Profile (Incomplete)" ` -o Tiff ` -c 1 ` -s ` -p ` -i 0 ``` ## Implementation Details ### Project Roles | Project | Purpose | Primary workflow file | | --- | --- | --- | | `SmartRip_CLI` | Print a file or page range from the command line. Also supports media install, uninstall, list, and version. | `PrintWorkflow.cs` | | `SmartRip_PageShooter` | Load one job and let an operator type pages to render on demand. | `Program.cs` | | `SmartRip_NewPageShooter` | Load one job and render pages when the camera sees a QR payload containing the page number. | `PageShooterWorkflow.cs`, `QrCameraReader.cs` | ### Key OPC UA Wrapper Pattern All three projects use an `OpcUaService` wrapper. The wrapper: - Creates an `OpcClient`. - Configures larger transport quotas for thumbnails and job-related data. - Connects lazily through `ConnectIfNeeded()`. - Reads and writes SmartRIP nodes. - Calls SmartRIP methods with `OpcNodeId(object, namespaceIndex)` and `OpcNodeId(method, namespaceIndex)`. - Converts loosely typed OPC values into C# primitives. Representative snippet: ```csharp var response = _client.CallMethod( new OpcNodeId("Print", 2), new OpcNodeId("Print/StartPrinting", 2), pageRange); if (response.Length == 0 || !Convert.ToBoolean(response[0])) { Console.WriteLine("[OPC] StartPrinting failed: device returned false."); return false; } ``` This aligns with the official method signature `StartPrinting(String pageRange) -> Boolean`. ### Setting Prepare Parameters Representative file-based prepare settings: ```csharp prepare.OutputType = "Tiff"; prepare.OutputPath = ripDir; prepare.CopyCount = copyCount; prepare.EnableScreening = enableScreening; opc.SetPrepareSettings(prepare); opc.SetSelectedMedia(mediaName); ``` `SetPrepareSettings()` writes: - `Prepare/CopyCount` - `Prepare/EnableScreening` - `Prepare/OutputPath` - `Prepare/OutputType` The media write is intentionally separate: ```csharp _client.WriteNode("ns=2;s=Prepare/MediaName", new OpcValue(media)); ``` ### Loading a Job and Thumbnail The sample code loads a PDF and then requests a thumbnail: ```csharp _client.CallMethod( new OpcNodeId("Prepare", 2), new OpcNodeId("Prepare/LoadJobFromPath", 2), jobName, filePath); var thumbResponse = _client.CallMethod( new OpcNodeId("Print", 2), new OpcNodeId("Print/StartThumbnailing", 2), pixelSize); ``` The thumbnail payload is read from `Print/JobThumbnail`. The code accepts base64 strings and, in some branches, byte arrays. Transport quotas are raised because image payloads can exceed default OPC UA client sizes. ### Starting and Monitoring a Print Run The print run must be started before printing: ```csharp _client.CallMethod( new OpcNodeId("Print", 2), new OpcNodeId("Print/PrintRunStart", 2)); ``` Then the code polls: ```csharp int done = ToInt(_client.ReadNode("ns=2;s=Print/PagesProcessed")?.Value); int total = ToInt(_client.ReadNode("ns=2;s=Print/PagesTotal")?.Value); string job = ToStr(_client.ReadNode("ns=2;s=Print/JobState")?.Value); string run = ToStr(_client.ReadNode("ns=2;s=Print/PrintRunState")?.Value); ``` Production code should treat these documented terminal states as terminal: - Success: `Success` - Failure: `Failed` - Cancellation: `Cancelled` The existing samples also check `Error`, which may reflect older behavior or local logging terminology. A robust implementation should support both where required by deployed server versions. ### Metadata Output `SmartRip_CLI` writes `job.json` after a successful print: ```json { "FileName": "Vdp_job_output.pdf", "Media": "Default KCMY Press Profile (Incomplete)", "OutputType": "Tiff", "CopyCount": 1, "EnableScreening": true, "PageRange": "1-", "OutputFolder": "C:\\Output\\SmartRip\\Vdp_job_output_yyyyMMdd_HHmmss", "Thumbnail": "...\\thumbnail.png", "Created": "..." } ``` This metadata is useful for traceability and should be extended in production with SmartRIP version, media version, output plugin version, controller software version, and a job ID from the printer management system. ## Error Handling and Diagnostics ### Common Issues | Symptom | Likely cause | Corrective action | | --- | --- | --- | | Cannot connect to SmartRIP | SmartRIP not running, endpoint blocked, wrong host/port, certificate trust failure. | Verify `opc.tcp://localhost:26942/smartrip`, firewall, certificate stores, and SmartRIP process state. | | `BadNodeIdUnknown` | Node name does not exist or is not valid for this SmartRIP version. | Verify against official docs and UaExpert. Do not write `Prepare/PageRange` on current interface. | | `The client did not specify all input arguments` | Method called without required arguments. | Call `Print/StartPrinting` with `pageRange`. | | `PrintRunState` remains `Starting` | Media/job incompatibility, plugin failure, hardware initialization problem. | Check SmartRIP log through `App/LogFile` or local logs. Confirm media and plugin. | | `JobState` remains `NotStarted` after `StartPrinting` | Method call failed, returned false, or was not called with page range. | Check method response boolean and log exception immediately. | | No output TIFF files | Wrong `OutputPath`, SmartRIP lacks write permission, wrong `OutputType`, plugin failure. | Check output folder ACLs, `Prepare/OutputType`, and SmartRIP logs. | | QR pages repeat | Camera sees the same QR repeatedly. | Use dedupe window as implemented in `QrCameraReader`. | | Camera does not open | Wrong OpenCV index or backend. | Run `pageshooter -l`, test DSHOW/MSMF backends. | | Meteor output stalls | Router disconnected, board not booted, interface ownership released, insufficient buffer. | Read `Meteor` and `Status` nodes, inspect print engine error, confirm cabling and MeteorRouter. | ### Diagnostics Built Into the Samples - Console logs show every major workflow state. - `GetVersion()` reads `App/VersionNumber` to confirm basic connectivity. - Media utilities verify installed media. - `LogWrite()` prints each prepare write result. - `GetPrintProgress()` reads job/run state and page counters. - Page shooters isolate page failures and continue scanning or prompting when possible. ### Recommended Production Diagnostics - Read `App/LogFile` for SmartRIP-side errors. - Store all OPC method return values and exceptions with timestamp and job ID. - Log `Prepare/AvailableOutputTypes` at startup. - Log selected media and media version if available from the media management system. - For Meteor output, log: - `Meteor/IsEnabled` - `Meteor/IsRouterConnected` - `Meteor/IsBootCycleComplete` - `Meteor/IsPrinterInterfaceAcquired` - `Meteor/GetPrintEngineError()` - `Status/BufferLevel` - `Status/DocsQueuedLane1` - `Status/DocsQueuedLane2` - `Status/PdCount` - `Status/PrintCount` ## Performance Considerations ### Latency The page shooters are designed to reduce per-page latency by avoiding full job reloads. `SmartRip_PageShooter` now opens the print run on the first page shoot and stops it when the session exits. This avoids the previous stop/start cycle before every page and can materially reduce command latency. The tradeoff is that prepare configuration is locked once the print run is active according to the official documentation. For on-demand page output, the safe production strategy is: - Configure all static job settings before starting the run. - Use `StartPrinting(pageRange)` to select the page or range. - Only change `OutputPath` between pages if the deployed SmartRIP version permits it during an active run. If not, use a single output folder and sort output by filename/page metadata, or stop/restart between pages. ### Throughput Throughput depends on: - PDF complexity and variable data volume. - Resolution, color channels, spot colors, screening, and color management. - CPU/GPU rendering configuration. - Output plugin behavior. - Disk throughput for TIFF/softproof. - Meteor router and board buffer behavior for direct output. For variable data printing, avoid unnecessary disk writes where a direct output plugin can stream raster data to the print electronics. If TIFF output is required, use fast local NVMe storage and ensure output folders are not scanned by antivirus in real time. ### Buffering and Real-Time Constraints TIFF output is batch/file oriented. Direct Meteor output is more real-time. Production code should: - Monitor Meteor buffer level and queued document counters. - Avoid submitting page ranges faster than the board and router can consume them. - Treat hardware PD and encoder signals as the final print synchronization layer. - Separate job submission latency from physical print trigger timing. - Avoid blocking camera acquisition or printer HMI responsiveness while waiting for RIP completion. ### OPC UA Payload Size Thumbnails and file chunks can exceed default OPC UA message limits. The sample constructor raises: - `MaxMessageSize` - `MaxByteStringLength` - `MaxArrayLength` - `MaxStringLength` - `MaxBufferSize` - `OperationTimeout` For job file chunk upload or larger thumbnails, tune quotas and timeouts explicitly and test with worst-case files. ## Best Practices 1. Treat the official SmartRIP documentation as the contract. Verify method signatures in UaExpert when integrating with a new SmartRIP version. 2. Do not write page range as a prepare node on the current interface. Pass it to `StartPrinting(pageRange)`. 3. Read `Prepare/AvailableOutputTypes` and validate output type before writing. 4. Stop the print run before changing job configuration unless the deployed version explicitly supports the change while active. 5. Check every method return value. `PrintRunStart`, `PrintRunStop`, `StartPrinting`, `StartThumbnailing`, media install, and uninstall return values should be logged and acted on. 6. Poll `PrintRunState` after `PrintRunStart` and `PrintRunStop`; both are asynchronous. 7. Poll `JobState` after `StartPrinting`; this call returns when the job is submitted, not when rendering is finished. 8. Handle `Success`, `Failed`, and `Cancelled`; also support `Error` where older sample code or deployed systems use it. 9. Keep OPC UA logic inside a service wrapper like `OpcUaService`; keep workflow orchestration outside it. 10. Keep path normalization centralized, as in `PathUtils.ExpandPath`. 11. Use a single long-lived OPC session for interactive page shooting where possible. 12. For camera triggering, use a queue between QR detection and print submission to avoid coupling camera frame rate to RIP latency. 13. For direct Meteor workflows, monitor both SmartRIP `Print` state and Meteor `Status` state. 14. Use explicit cancellation and cleanup on `Ctrl+C`, including `PrintRunStop`. 15. Generate metadata for audit and production traceability. 16. Document the exact media, output plugin, SmartRIP version, and controller version used for production qualification. ## Conclusion SmartRIP's OPC UA interface provides a clean integration point for industrial printer controllers. The repository demonstrates three useful patterns: single-job command-line printing, manual page-on-demand printing, and QR-triggered page printing. The same core workflow applies to TIFF output, softproof output, and direct Meteor output: configure `Prepare`, start the `Print` run, call `StartPrinting(pageRange)`, monitor progress, and stop the run cleanly. The most important integration detail is ownership of the page range. On the current official interface, page selection is a `StartPrinting` argument, not a `Prepare` property. Production integrations should also validate output types dynamically, check all Boolean method responses, and extend diagnostics for direct Meteor status. With those constraints respected, SmartRIP can be used as a background rendering, screening, color-management, and device-output component inside a printer manufacturer's own management software. ## Appendix A: Function-Level Implementation Reference This appendix maps the sample program functions to their engineering roles and the official OPC UA concepts they implement. Functions with the same name in multiple `OpcUaService` files have equivalent intent unless noted. ### Common Model Functions | File | Function or member | Explanation | | --- | --- | --- | | `Models/PrepareSettings.cs` | `AvailableOutputTypes` | Mirrors `Prepare/AvailableOutputTypes`; used to discover legal output plugins. | | `Models/PrepareSettings.cs` | `CopyCount` | Mirrors `Prepare/CopyCount`; collated copies. | | `Models/PrepareSettings.cs` | `EnableScreening` | Mirrors `Prepare/EnableScreening`; controls screened versus unscreened output. | | `Models/PrepareSettings.cs` | `OutputPath` | Mirrors `Prepare/OutputPath`; required for disk-based output. | | `Models/PrepareSettings.cs` | `OutputType` | Mirrors `Prepare/OutputType`; must match `AvailableOutputTypes`. | | `Models/PrepareSettings.cs` | `PageRange` | Local application state used as the `StartPrinting(pageRange)` argument. | | `Models/SmartRipJobMetadata.cs` | `ToJson()` | Serializes job audit metadata with `Newtonsoft.Json`. | ### `OpcUaService` Functions | Function | OPC UA node or local role | Explanation | | --- | --- | --- | | `OpcUaService()` | Client setup | Creates `OpcClient` for `opc.tcp://localhost:26942/smartrip` and configures transport quotas/timeouts. | | `ConnectIfNeeded()` | Session management | Connects the OPC UA client if not already connected. Logs connection failure. | | `Open()` | Session helper | Calls `ConnectIfNeeded()` and returns a no-op disposable so workflows can use `using (opc.Open())`. | | `NullScope.Dispose()` | Local helper | No-op cleanup placeholder used by `Open()`. | | `GetAvailableMedia()` | `Media/MediaNames` | Reads installed media names. Handles multiple possible array representations. | | `GetSelectedMedia()` | `Prepare/MediaName` | Reads the current selected media name. | | `SetSelectedMedia(media)` | `Prepare/MediaName` | Stops any active run, writes the media name, and reads it back for confirmation. | | `EnsurePrintRunStopped()` | `Print/PrintRunState`, `Print/PrintRunStop()` | Reads run state, calls stop if needed, and polls until stopped. | | `WaitForThumbnail(timeoutMs, pollIntervalMs, jobName)` | `Print/JobThumbnail` | Polls for thumbnail data after `StartThumbnailing`, decodes it, and writes a PNG into `wwwroot/preview`. | | `LoadJobFromPath(jobName, filePath, pixelSize)` | `Prepare/LoadJobFromPath`, `Print/StartThumbnailing` | Ensures stopped state, loads the PDF path, requests a thumbnail, then waits for thumbnail output. | | `PrintRunStart()` | `Print/PrintRunStart()` | Starts the asynchronous print run. The caller must poll until `PrintRunState` becomes `Started`. | | `GetPrintProgress()` | `Print/PagesProcessed`, `Print/PagesTotal`, `Print/JobState`, `Print/PrintRunState` | Reads the standard progress tuple used by all workflows. | | `EnsurePrintRunStarted()` | `Print/PrintRunState`, `Print/PrintRunStart()` | Polls until the run is ready and attempts restart if the run is stopped. Current official ready state is `Started`; some local code also accepts `Active` for compatibility. | | `StartPrintWithoutWaiting(pageRange)` | `Print/StartPrinting(String pageRange)` | Submits the prepared job/page range. In the corrected PageShooter service, it checks the returned Boolean. | | `StartPrintWithoutWaiting()` | Local compatibility overload | PageShooter-only overload that defaults to `all`; prefer the explicit page-range overload. | | `GetPrepareSettings()` | `Prepare/*` properties | Reads available output types, copy count, screening, output path, output type, and, in some project versions, legacy page range. | | `SetPrepareSettings(p)` | `Prepare/CopyCount`, `Prepare/EnableScreening`, `Prepare/OutputPath`, `Prepare/OutputType` | Writes prepare settings. Current-interface code should not write `Prepare/PageRange`. | | `InitializeDefaultPrepareSettings()` | Local convenience | Writes default TIFF settings into a fixed output folder. Useful for testing, not required by official workflow. | | `LogWrite(name, status)` | Local diagnostics | Logs OPC write status and returns success/failure. | | `ReadStringArrayNode(nodeId)` | Local conversion | Reads a string-array node such as `Prepare/AvailableOutputTypes`. | | `ToInt(v)` | Local conversion | Converts OPC values to `int`, returning zero on conversion failure. | | `ToStr(v)` | Local conversion | Converts OPC values to `string`, returning empty string on null. | | `ToBool(v)` | Local conversion | Converts OPC values to `bool`, returning false on conversion failure. | | `Dispose()` | Session cleanup | Disconnects and disposes the OPC UA client. | | `GenerateSoftproofPreview(jobName, filePath)` | Softproof helper | Legacy helper that demonstrates softproof output. It should be updated to call `StartPrinting(pageRange)` with an argument on the current official API. | | `GetVersion()` | `App/VersionNumber` | Reads SmartRIP version for health checks. | | `InstallMediaFromPath(smdPath)` | `Media/InstallMediaFromPath` | Installs an `.smd` file accessible to the server and returns installed media name. | | `UninstallMedia(mediaName)` | `Media/UninstallMedia` | Removes an installed media entry and returns Boolean method result. | ### `SmartRip_CLI` Functions | File | Function | Explanation | | --- | --- | --- | | `Program.cs` | `Main(args)` | NClap entry point. Parses top-level command and executes the selected command group. | | `Commands/PrintCommand.cs` | `Execute()` | Expands paths and calls `PrintWorkflow.Start(...)` with media, output type, copy count, screening, and page range. | | `Commands/InstallCommand.cs` | `Execute()` | Opens OPC connection and calls `InstallMediaFromPath`. Note: the current source appears to invert success/failure return codes; verify before production use. | | `Commands/MediaCommand.cs` | `Execute()` | Opens OPC connection and lists `Media/MediaNames`. | | `Commands/UninstallCommand.cs` | `Execute()` | Opens OPC connection and calls `UninstallMedia`. | | `Commands/VersionCommand.cs` | `Execute()` | Opens OPC connection and reads `App/VersionNumber`. | | `PrintWorkflow.cs` | `Start(...)` | Full one-shot print sequence: validate PDF, create folders, stop run, load job, thumbnail, write prepare settings, set media, start run, submit page range, wait, write metadata. | | `PrintWorkflow.cs` | `EnsurePrintRunStarted(opc)` | Polls `PrintRunState` after `PrintRunStart`. | | `PrintWorkflow.cs` | `WaitForPrint(opc)` | Polls `JobState` and page counters until success/failure/timeout. | | `PathUtils.cs` | `ExpandPath(path)` | Converts relative paths to executable-relative absolute paths and normalizes them. | ### `SmartRip_PageShooter` Functions | File | Function | Explanation | | --- | --- | --- | | `Program.cs` | `Main(args)` | Interactive console workflow. Validates arguments, loads job, sets media, then repeatedly asks for a page number. | | `Program.cs` | `TryParseArguments(args, out options, out error)` | Supports both positional and named argument forms for PDF, media, output directory, output type, copy count, and screening. | | `Program.cs` | `PrintUsage()` | Prints command usage. | | `Program.cs` | `IsMediaListCommand(arg)` | Recognizes media-list command aliases. | | `Program.cs` | `ListAvailableMedia()` | Opens OPC connection and prints installed media names. | | `Program.cs` | `WaitForPrint(opc)` | Polls print progress after each submitted page. | | `Program.cs` | `EnsurePrintRunOpen(opc)` | Starts the print run if not already open. This allows faster page shooting by keeping the run alive. | | `Program.cs` | `WaitForPrintRunOpen(opc)` | Polls until run state is `Started` or compatible active state. | | `Program.cs` | `IsPrintRunOpen(runState)` | Local predicate for ready run states. | | `Program.cs` | `AppOptions` | Parsed command options container. | ### `SmartRip_NewPageShooter` Functions | File | Function | Explanation | | --- | --- | --- | | `Program.cs` | `Main(args)` | NClap entry point registering `pageshooter`, media, install, uninstall, and version commands. | | `Commands/PageShooterCommand.cs` | `Execute()` | Validates options, lists cameras if requested, initializes SmartRIP context, starts QR reader, consumes queued page numbers, and calls `PageShooterWorkflow.PrintPage`. | | `PageShooterWorkflow.cs` | `Context.Dispose()` | Best-effort stop of print run and OPC disposal when the page-shooter session ends. | | `PageShooterWorkflow.cs` | `Initialize(...)` | Validates PDF/copy count, creates output folders, connects to SmartRIP, stops stale run, loads job and thumbnail, reads prepare settings, resolves media, and starts the print run once. | | `PageShooterWorkflow.cs` | `PrintPage(ctx, page, cancellationToken)` | Validates page number, ensures run active, creates per-page folder, writes page-specific output path, calls `StartPrinting(pageRange)`, and waits for completion. | | `PageShooterWorkflow.cs` | `EnsurePrintRunStarted(opc, cancellationToken)` | Polls run state with cancellation support. | | `PageShooterWorkflow.cs` | `WaitForPrint(opc, cancellationToken)` | Polls progress with cancellation support. | | `PageShooterWorkflow.cs` | `EnsurePrintRunActive(opc, cancellationToken)` | Restarts the print run if it dropped before a page submission. | | `PageShooterWorkflow.cs` | `NormalizeOutputType(outputType)` | Accepts `None`, `SoftProof`, or `Tiff`, case-insensitively; defaults to `Tiff`. Production direct-Meteor workflows should extend this to use `AvailableOutputTypes`. | | `PageShooterWorkflow.cs` | `ResolveMedia(opc, mediaName)` | Uses supplied media if present, else current selected media, else first installed media. | | `QrCameraReader.cs` | `QrCameraReader(...)` | Captures queue, cancellation token, camera index, and preview flag. | | `QrCameraReader.cs` | `Start()` | Starts QR reading on a background task. | | `QrCameraReader.cs` | `ReadLoop()` | Opens camera, reads frames, decodes QR payloads, draws preview if enabled, deduplicates payloads, parses page numbers, and queues pages. | | `QrCameraReader.cs` | `GetStablePoints(payload, points)` | Smooths QR polygon overlay coordinates for preview display. | | `QrCameraReader.cs` | `DrawPreviewOverlay(frame, payload, points)` | Draws QR boundary and label in the preview window. | | `QrCameraReader.cs` | `DrawPayloadLabel(frame, payload, polygon)` | Draws readable payload text over the preview frame. | | `QrCameraReader.cs` | `IsDuplicatePayload(payload)` | Suppresses repeated QR reads inside a two-second dedupe window. | | `QrCameraReader.cs` | `TryParsePage(payload, out page)` | Parses QR JSON and accepts numeric or string `Page` values greater than zero. | | `QrCameraReader.cs` | `Dispose()` | Waits briefly for the reader task and closes OpenCV windows. | | `CameraUtils.cs` | `ProbeOpenCvCameras(maxDevices)` | Tests OpenCV indices and returns cameras that can deliver a frame. | | `CameraUtils.cs` | `GetWindowsCameraDevices()` | Uses WMI to list Windows camera/image devices. | | `CameraUtils.cs` | `CreateVideoCapture(cameraIndex)` | Tries DSHOW, MSMF, then ANY on Windows; returns the first opened capture. | | `CameraUtils.cs` | `CanReadFrame(capture)` | Confirms the capture can read a non-empty frame. | | `CameraUtils.cs` | `GetCaptureApis()` | Enumerates preferred OpenCV capture backends. | | `PrintWorkflow.cs` | `PageShooterContext.Dispose()` | Legacy support context cleanup. | | `PrintWorkflow.cs` | `InitializePageShooter(...)` | Older page-shooter initializer retained for support/reference. | | `PrintWorkflow.cs` | `PrintSinglePage(...)` | Older single-page workflow retained for support/reference. | | `PrintWorkflow.cs` | `WaitForPrint(opc)` | Legacy polling helper. | | `PathUtils.cs` | `ExpandPath(path)` | Same role as in `SmartRip_CLI`: normalize paths. | ## Appendix B: OPC UA Call Inventory Used by the Samples ### Reads ```text App/VersionNumber Media/MediaNames Prepare/AvailableOutputTypes Prepare/CopyCount Prepare/EnableScreening Prepare/MediaName Prepare/OutputPath Prepare/OutputType Print/JobState Print/JobThumbnail Print/PagesProcessed Print/PagesTotal Print/PrintRunState ``` ### Writes ```text Prepare/CopyCount Prepare/EnableScreening Prepare/MediaName Prepare/OutputPath Prepare/OutputType ``` ### Methods ```text Media/InstallMediaFromPath(String smdPath) -> String Media/UninstallMedia(String mediaName) -> Boolean Prepare/LoadJobFromPath(String jobName, String filePath) -> Boolean Print/PrintRunStart() -> Boolean Print/PrintRunStop() -> Boolean Print/StartPrinting(String pageRange) -> Boolean Print/StartThumbnailing(Int32 pixelSize) -> Boolean ``` ### Additional Meteor Methods Relevant to Direct Output The current C# samples do not wrap these methods, but direct-to-Meteor production integrations should understand them: ```text Meteor/AcquirePrinterInterface() -> Boolean Meteor/ReleasePrinterInterface() -> Boolean Meteor/SetHeadPower(Boolean power) -> Boolean Meteor/SetParam(...) -> Boolean Meteor/SetParamEx(...) -> Boolean Meteor/SetSignal(...) -> Boolean Meteor/UpdateXOffsets() -> Boolean Meteor/ForcePD() -> Boolean Meteor/GetPrintEngineError() -> String Print/RunPluginCommand(String pluginName, String command) -> String ``` ## Appendix C: Example UaExpert Manual Replay 1. Connect to `opc.tcp://localhost:26942/smartrip`. 2. Read `Print/PrintRunState`. 3. If not `Stopped`, call `Print/PrintRunStop()` and poll until stopped. 4. Call `Prepare/LoadJobFromPath(jobName, filePath)`. 5. Optional: call `Print/StartThumbnailing(256)` and read `Print/JobThumbnail`. 6. Write: - `Prepare/MediaName` - `Prepare/OutputType` - `Prepare/OutputPath` - `Prepare/CopyCount` - `Prepare/EnableScreening` 7. Call `Print/PrintRunStart()`. 8. Poll `Print/PrintRunState` until `Started`. 9. Call `Print/StartPrinting(pageRange)`. 10. Poll: - `Print/JobState` - `Print/PagesProcessed` - `Print/PagesTotal` - `Print/PrintRunState` 11. Stop the print run with `Print/PrintRunStop()`.