System designHow-to

HMI image element refresh: beat the cache, show the new jpg

An HMI image element caches the first camera jpg. Name each capture uniquely, bind the element to the new name, and every client refreshes without a reload.

LumaSpec Vision10 min read Share on LinkedIn

On this page 9 sections
  1. 01Why does an HMI image element keep showing the old camera jpg?
  2. 02What do you need before you start?
  3. 03How do you push a new capture to every client without a reload?
  4. 04What does the refresh code look like?
  5. 05How much disk does a rolling capture folder need?
  6. 06How do you prove every client updates without a reload?
  7. 07What keeps the jpg stale after you rename it?
  8. 08When should you stream instead of refreshing a file?
  9. 09Questions

You captured a still from the camera, wrote it into the folder the visualization reads, put one image element on the screen — and the element keeps showing the first picture until someone reloads the client. That is the cache doing its job: the element asks for one fixed reference, the client keeps the decoded picture for it, and an overwritten file under the same name never triggers a second fetch. The fix is to make the name part of the data: give every capture its own file name, bind the element's reference to a variable, and let each new name act as the refresh signal that reaches every client on its own cycle. This guide gives you the naming rule, the structured text, the disk sizing and the two-client test.

Why does an HMI image element keep showing the old camera jpg?

The element is bound to one fixed reference — a pool image or a file name — and each web client keeps the picture it decoded for that reference; overwriting the file on disk tells the client nothing, so the old jpg stays until the page itself reloads.

There are two layers to keep apart. Images placed in the project's image pool travel with the application download, so every client holds the copy from download day; replacing the file on the controller later reaches nobody. Files the runtime serves from a plain folder are read on request, but the request is keyed by name, so a new timestamp on a familiar name still comes back from cache. That is why a manual browser refresh appears to fix it: it throws the cache away and re-reads everything — a step no operator should have to repeat on shift, and one that blanks every other screen on that client while it runs.

What do you need before you start?

You need four things: a capture program that writes jpg files into a folder the runtime can serve, one image element per picture, a string variable bound to each element, and about 1 GB of disk for the rolling capture folder this guide ends up sizing.

  • A capture program — the camera SDK's save call or your image-processing task — writing jpg files to a folder the visualization runtime serves over HTTP.
  • One image element per picture, with its reference bound to a STRING variable in the PLC, never to a typed-in literal.
  • Write access for the capture program and read access for the runtime on the same volume, so the rename in the procedure stays atomic.
  • A housekeeping task that trims the folder to the ring depth sized below.

One box can run the whole chain: a vision controller executes the capture, holds the served folder and feeds the web clients, with no separate display PC in the path. A compact unit covers it with headroom for the camera link:

Vision controllersHikrobot MV-VC2140-128G40-1T VC2100 Vision Controller, N97, 8GB+128G SSD+ 1THDDMV-VC2140-128G40-1T
LAN ports
3-4 LAN ports
USB 3 ports
2 USB 3 ports
Light outputs
4 built-in channels
Memory
8 GB
$1,679.00View partBuild a system with it

The MV-VC2140-128G40-1T brings two USB 3 ports, so the camera takes one and a second USB3 sensor stays free, and 8 GB of memory absorbs the capture buffers behind the display.

How do you push a new capture to every client without a reload?

Give every capture its own file name and point the element's reference at that new name — a timestamp or frame counter appended before .jpg — because a client fetches only a reference it has never cached, and the new picture lands on the next visualization cycle of every client, no reload.

  1. Fix the name scheme. cap_20260115_103015_123_0042.jpg: date, time to milliseconds, then the running frame counter. Milliseconds plus counter means two captures in the same second can never collide.
  2. Write through a temp file. The capture program saves to cap_tmp.jpg, then renames to the final name, so a client can only ever open a finished file.
  3. Build the served path in the PLC. Prepend the folder the runtime serves — /img/captures/ in this guide — and copy the complete string into the variable the element is bound to.
  4. Let the variable change do the refresh. No reload, no cache clear, no message to clients: the element sees a reference it has never held, fetches it, repaints.
  5. Trim the folder to the ring depth from the sizing section, on a timer rather than inside the capture cycle.
  6. Keep a diagnostic string with the last written name; when a screen misbehaves, compare it with what the element shows.

What does the refresh code look like?

Three lines of structured text do the work: increment a counter, build the name from it, copy the served path into the variable the element is bound to. The declaration block fixes types and start values, and the test at the end proves the element follows without a reload.

VAR
    frameCount : UDINT := 0;        // running capture counter, e.g. cap_0042.jpg
    fileName   : STRING(48) := '';  // per-capture file name
    imageRef   : STRING(255) := ''; // served path, bound to the image element
END_VAR

frameCount := frameCount + 1;
fileName   := CONCAT(CONCAT('cap_', UDINT_TO_STRING(frameCount)), '.jpg');
imageRef   := CONCAT('/img/captures/', fileName);

Every variable here is an example name of my own — the contract is a type, a start value of zero or empty, and the element bound to imageRef. The two string calls are the standard conversion and concatenation functions of IEC 61131-3 structured text; your runtime's library names may differ, the shape does not.

For an operator-readable archive, build the name from the real-time clock instead — cap_20260115_103015_123.jpg for 15 January 2026, 10:30:15.123 — and keep the counter as the tie-breaker. If you also stamp the pixels, keep that decision separate: text overlay on a live camera image without altering the frame shows how to annotate without touching the capture.

The test that proves it: open two browser clients on two machines, trigger two captures about 1 s apart, and confirm three things — the element repaints twice on both clients with no reload, the folder holds exactly the two new names, and the logged imageRef at each cycle matches the file the clients display.

How much disk does a rolling capture folder need?

Size the folder from the file size and the history you want: a 4000 × 3000 color still is about 36 MB raw and roughly 3.6 MB as a jpg, so a 200-file ring costs about 720 MB and holds 100 s of history at the 2 Hz refresh this guide assumes.

raw MB = width px × height px × 3 B ÷ 1,000,000 jpg MB ≈ raw MB ÷ 10 ring MB = jpg MB × files kept history s = files kept ÷ refresh rate

The arithmetic, step by step: 4000 × 3000 × 3 = 36,000,000 bytes, about 36 MB raw. Machine-vision content at jpg quality 85 compresses close to 10:1, so budget 3.6 MB per file — an estimate that moves with texture and quality setting, roughly halving for flat parts. A 200-file ring then costs 200 × 3.6 MB ≈ 720 MB and holds 200 ÷ 2 = 100 s at 2 Hz. Ten minutes of history at the same rate needs 1,200 files, about 4.3 GB.

Shrink before you save and the numbers divide by four: a 2000 × 1500 image is 9 MB raw, near 0.9 MB as jpg, so the same ring drops to about 180 MB. Match the saved size to what the element actually shows — scale a camera image to fit an HMI widget the right way walks that decision — and the RAM side of the same sizing sits in camera frame pool out of memory: size buffers for high-res stills.

On the capture side, a 12 MP USB3 still camera — the area scan cameras range is where those live — plugs into the controller port you freed for it:

Area scan cameras12 MP USB3 area scan camera, IMX226, 1/1.7" rolling shutter, 30 fps, 4000 × 3000 resolution (LS-CMR-0166)LS-CMR-0166
Sensor format
1/1.7"
Interface
USB3
Resolution
12 MP
Shutter
Rolling
$560.00View partBuild a system with it

The LS-CMR-0166 captures 4000 × 3000 stills at up to 30 fps. Throttle the save call down to the display refresh you chose and the folder math above holds exactly.

How do you prove every client updates without a reload?

Open two clients on two machines, trigger captures about 2 s apart, and watch the element: each client must repaint on every capture with no reload, no cleared cache and no touch on the runtime; then leave it running an hour and check the folder stayed at ring size.

  1. Open two clients on two different machines — one on the controller's own display, one across the network.
  2. Trigger a capture and log imageRef with a timestamp in the same cycle.
  3. Confirm both elements repaint with the new picture, and compare the file on disk with what each client shows.
  4. Repeat for a dozen captures, then check the folder holds exactly the ring and no client was touched.

A third check catches the sneaky failure: open a brand-new client mid-run. It must show the newest capture immediately, because that name has never been in anyone's cache. If the refresh-on-reload behavior ever returns, a literal binding has crept back into the element. Where a polled URL is your only display option, the same timing questions apply — IP camera snapshot URL on an HMI: refresh rates and setup works through the polling variant.

What keeps the jpg stale after you rename it?

Four causes account for nearly every stubborn case: the element still points at the old literal, the file is written while a client reads it, two captures share one name, or the runtime serves the compiled pool folder while the capture program writes somewhere else.

  • Literal instead of variable. The old name is typed into the element, so no variable change reaches it. Rebind the reference.
  • Same-second collision. A stamp with seconds resolution collides 30 times per second at a 30 fps save rate; milliseconds plus the counter close the window.
  • Half-written reads. Saving straight to the final name lets a fast client open a partial jpg; the temp-then-rename step removes that window.
  • Wrong folder. The capture program writes to a directory the runtime does not serve. Request one file directly by its served address — http://10.0.0.12/img/captures/cap_17.jpg, with your controller's address in place of the example — and what loads there is exactly what a client can load.
  • Counter wraparound. A 32-bit unsigned counter wraps after 4,294,967,295 captures; at 30 writes per second that is 4,294,967,295 ÷ (30 × 86,400 × 365) ≈ 4.5 years. Wrap it deliberately with MOD against the ring depth and let the timestamp keep names unique.

When should you stream instead of refreshing a file?

Above about 5 new pictures per second, stop pushing files: decode cost, disk wear and network traffic grow with every write, while a stream serves continuous live video without touching the disk. Below that rate the file pattern is simpler and keeps every client in step.

Display path Best for Practical rate Cost per update
Renamed jpg per capture proof stills, alarm snapshots, review screens 0.5-5 per second one file write, one fetch
Snapshot URL with a counter in the query a single kiosk client 1-2 per second one capture per poll
RTSP or GVSP-to-RTSP stream continuous live view 15-30 per second continuous decode, no disk

The stream row wins when an operator wants motion rather than evidence: display an RTSP camera stream in an HMI: snapshot URL or VLC and GigE Vision camera on an HMI: bridge GVSP to RTSP cover the two ways in, and live camera image in an HMI runtime: snapshots vs streams is the decision page between them. If your display target is a PLC HMI object rather than a web client, smart camera image in a PLC HMI: what actually displays live maps which objects repaint at all. Panel hardware that only accepts a static image path follows the same file rule; JPG image display on HMI touch screens walks one platform's behavior end to end.

If capture and screen already share a box, start from the vision controller range above and match camera ports to your sensor count, or open /configure/ to step through camera, lens and controller, or describe the layout through /contact/ and we will check the parts against your refresh rate.

Questions

How many new pictures per second can the file pattern deliver?

Plan on 2 per second as the comfortable rate for full-size 12 MP jpgs and 5 per second as the ceiling. Each cycle needs a save, a rename and one client update; on an SSD those are milliseconds, but fetching and decoding a 3.6 MB file on a busy client dominates. Above that, stream.

How long should the image reference string be?

Declare at least 255 characters. A time stamp to milliseconds is 23 characters, the cap_ prefix and .jpg extension add 9, and a nested served folder can add 60 more. A truncated reference points at a file that does not exist, and the element freezes on the last picture it decoded.

Can two image elements show two cameras on one screen?

Yes. Bind each element to its own reference variable and give each camera a separate folder or name prefix, such as cam1_cap_47.jpg and cam2_cap_12.jpg. One shared variable forces both elements onto the same picture; per-element strings cost nothing beyond the extra declarations.

Does the trick work on a panel that only accepts a fixed image path?

Only where the panel re-reads the file on a timer. Most panel image objects behave like a browser element and keep the first decode; if the object takes a URL per update, append the frame counter to that URL instead. When nothing re-reads, put a small client in front and drive it with this pattern.

What keeps the capture folder from filling up over months?

Run a housekeeping task on a 60 s timer that deletes everything older than the ring depth. At the worked sizes that holds a 200-file folder near 720 MB indefinitely, and an alarm at 80 percent disk use catches a runaway capture rate before the first failed write leaves clients on a stale picture.