## 4 Digital Watermarking System for JPEGs
### Watermark Embedding Process  
The embedding process consists of sequential stages from image preparation to watermark insertion, as illustrated in Figure 3. This process employs adaptive threshold based on image characteristics to optimise embedding strength.  
Algorithm 1 details the channel-specific watermark embedding process, which applies the adaptive threshold to optimise watermark strength based on image characteristics. The main watermark embedding procedure is presented in Algorithm 2, which coordinates the processing of different channels and image types through the watermarking process.  
Figure 3: Watermark embedding workflow: (1) Make a copy of disk image for watermarking, (2) load copy disk image, (3) locate JPEG files, (4) determine image type, (5) initialise PRNG with key, (6) for each JPEG, (7) select \(8\times 8\) blocks using PRNG, (8) calculate adaptive threshold using JND, (9) apply DCT to selected blocks in each channel, (10) embed watermark bits in DCT coefficients and apply inverse DCT, (11) apply DWT and embed the watermark in the HL subband, (12) apply inverse DWT, (13) extract ORB features, (14) write modified JPEGs back to the copy disk image.  
Figure 2: Zigzag scanning pattern for DCT coefficient selection. The matrix shows the sequence of coefficient scanning (**left**) and corresponding traversal pattern (**right**). The orange dot highlights coefficient position (4,4), where watermark bits are embedded, selected for its optimal balance between robustness and imperceptibility.  
```
1:C, WatermarkPattern, ZigzagPattern, PRNG
2:Extract ORB features from channel C
3:num_blocks \(\leftarrow\) min(64, total_blocks in C)
4:block_locations \(\leftarrow\) SelectRandomBlocks(num_blocks, PRNG)
5:for each selected block do
6: Apply DCT to block at location
7: Embed watermark bit in DCT coefficient (4,4):
8:if WatermarkPattern[i] = 1 then
9: DCT_Coeffs[4,4] += DCT_WATERMARK_STRENGTH * PerceptualMask
10:else
11: DCT_Coeffs[4,4] -= DCT_WATERMARK_STRENGTH * PerceptualMask
12:endif
13: Apply inverse DCT
14:endfor
15:for each colour channel do
16: Apply DWT
17: Embed watermark in HL subband:
18:for i = 0 to min(WatermarkPattern.length, HL_size/2) do
19: row = (i * 2) / HL_width
20: col = (i * 2) % HL_width
21:if WatermarkPattern[i] = 1 then
22: HL[row, col] += DWT_WATERMARK_STRENGTH * PerceptualMask
23:else
24: HL[row, col] = DWT_WATERMARK_STRENGTH * PerceptualMask
25:endif
26:HL[row, col] \(\leftarrow\) AdaptiveQuantise(HL[row, col])
27:endfor
28: Apply inverse DWT
29:endfor
```  
**Algorithm 1** ProcessChannel: Channel-Specific Watermark Embedding  
```
1:Image (from disk image or stand-alone file), Key, WatermarkPattern
2:WatermarkedImage
3:Determine ImageType (YCbCr JPEG in disk image, RGB, or greyscale)
4:if image is from disk image then
5: Locate JPEG files using markers (FFD8 FF to FFD9)
6:endif
7:Initialise PRNG with Key
8: ZigzagPattern \(\leftarrow\) GenerateZigzagPattern(8 \(\times\) 8)
9:ifImageType = YCbCr JPEG in disk image then
10: for each channel C in (Y, Cb, Cr) do
11: ProcessChannel(C, WatermarkPattern, ZigzagPattern, PRNG)
12:endfor
13:else if ImageType = RGB then
14:for each channel C in (R, G, B) do
15: ProcessChannel(C, WatermarkPattern, ZigzagPattern, PRNG)
16:endfor
17:else
18: ProcessChannel(Image, WatermarkPattern, ZigzagPattern, PRNG)
19:endif
20:if image is from disk image then
21: Write modified JPEG data back to the original location
22:endif
23:return WatermarkedImage
```  
**Algorithm 2** EmbedWatermark: Main Watermark Embedding Procedure