{"id":670,"date":"2025-05-11T04:27:30","date_gmt":"2025-05-11T02:27:30","guid":{"rendered":"https:\/\/renor.it\/invisible-watermark-in-jpeg-with-php-8\/"},"modified":"2025-12-20T15:53:53","modified_gmt":"2025-12-20T14:53:53","slug":"invisible-watermark-in-jpeg-with-php-8","status":"publish","type":"post","link":"https:\/\/renor.it\/en\/blog\/sviluppo-software-programmazione\/invisible-watermark-in-jpeg-with-php-8\/","title":{"rendered":"Invisible Watermark in JPEG with PHP 8"},"content":{"rendered":"<h2 class=\"wp-block-heading\">Protect your images by modifying the coefficients, without damaging them<\/h2>\n<p>Publishing photographs online has become essential for photographers, e-commerce sites, and bloggers, but according to the latest studies on image theft, over 70% of visual content is reshared without credit or authorization. A visible watermark certainly protects the author, but to make it truly effective against intellectual property theft, it often ruins the aesthetic of the shot with an unsightly \u201cpatch\u201d! <\/p>\n<p>In contrast, an \u201cinvisible\u201d watermark embedded in the coefficients of the Discrete Cosine Transform (DCT), on which the JPEG format is based, preserves perceived quality and can withstand resizing or light compression.<\/p>\n<p>By encoding the information in the <strong>sign<\/strong> of specific low-frequency coefficients, it is possible to ensure an effective compromise between invisibility and robustness.<\/p>\n<p>In this open-source project, available in my GitHub repository: <a href=\"https:\/\/github.com\/thesimon82\/php-dct-invisible-watermark\">https:\/\/github.com\/thesimon82\/php-dct-invisible-watermark<\/a>, written in PHP 8.3 and based on GD\/Imagick for pixel manipulation, we will demonstrate step by step how to embed a textual signature into the low-frequency (AC) coefficients of each 8\u00d78 block, how to retrieve its fingerprint, and why using the <strong>coefficient\u2019s sign<\/strong> represents a robust strategy against common JPEG compressions, even at 80% quality or lower.<\/p>\n<p>The goal is not purely educational: the resulting microservice can be cloned from the repository and integrated, via CLI or API, into any image publishing workflow.<\/p>\n<h2 class=\"wp-block-heading\">Technical foundations<\/h2>\n<p>Before writing a single line of code, it is worth clarifying how the JPEG compression algorithm processes the images it needs to compress.<\/p>\n<p>The JPEG format divides the image into a grid of 8\u00d78 pixel blocks; each block is transformed using the Discrete Cosine Transform (DCT), which decomposes the visual information into 64 coefficients ordered from the lowest frequency (the top-left corner, representing the average intensity) to the highest frequency (the finest details).<\/p>\n<p>The mid-to-low frequency coefficients are the ideal spot for our watermark: altering the zero-frequency (DC) coefficient would produce visible halos, while modifying only the highest frequencies would lead to their removal during the very first JPEG compression.<\/p>\n<p>By instead acting on intermediate coefficients, we can encode individual bits by <strong>modifying the sign of the coefficient<\/strong> (positive = 0, negative = 1), thus obtaining a marker that is invisible to the eye but robust enough to survive resizing and JPEG compressions down to 80% quality.<\/p>\n<p>This mathematical principle will guide the entire implementation.<\/p>\n<p>We will read each 8\u00d78 block, compute the DCT using a native PHP function, modify the <strong>sign<\/strong> of one or more selected coefficients, and save the new JPEG using GD or Imagick.<\/p>\n<p>In other words, the watermark will be hidden precisely in the coefficients that the JPEG compression algorithm tends to preserve: it will be invisible to the eye but difficult to remove, even in the presence of light recompressions.<\/p>\n<h2 class=\"wp-block-heading\">The mathematics that makes the watermark invisible<\/h2>\n<p>Each <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-269f426dfc1dab3e5d9987e3361f4307_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#56;&times;&#56;\" title=\"Rendered by QuickLaTeX.com\" height=\"12\" width=\"18\" style=\"vertical-align: 0px;\"\/> block of intensities <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-533196a0d71c414a47d0753600045b35_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#102;&#95;&#123;&#120;&#44;&#121;&#125;\" title=\"Rendered by QuickLaTeX.com\" height=\"18\" width=\"28\" style=\"vertical-align: -6px;\"\/> (where<img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-2cde234e6bcf66bbc8f3f37407c2dea8_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#32;&#120;&#44;&#121;&#32;&#92;&#105;&#110;&#32;&#92;&#123;&#48;&#44;&#92;&#100;&#111;&#116;&#115;&#44;&#55;&#92;&#125;\" title=\"Rendered by QuickLaTeX.com\" height=\"19\" width=\"123\" style=\"vertical-align: -5px;\"\/>) is converted into 64 coefficients <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-c82f152c8e6619cbeddd318d16e9aa3c_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#67;&#95;&#123;&#117;&#44;&#118;&#125;\" title=\"Rendered by QuickLaTeX.com\" height=\"18\" width=\"32\" style=\"vertical-align: -6px;\"\/> (with <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-3568fd28364bcfd7b6e3a22d1242fb48_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#117;&#44;&#118;&#32;&#92;&#105;&#110;&#32;&#92;&#123;&#48;&#44;&#92;&#100;&#111;&#116;&#115;&#44;&#55;&#92;&#125;\" title=\"Rendered by QuickLaTeX.com\" height=\"19\" width=\"123\" style=\"vertical-align: -5px;\"\/>) using:<\/p>\n<p class=\"p1\">\\[<\/p>\n<p class=\"p1\">C_{u,v}= \\frac{1}{4}\\,\\alpha(u)\\,\\alpha(v)\\!<\/p>\n<p class=\"p1\">\\sum_{x=0}^{7}\\,\\sum_{y=0}^{7}<\/p>\n<p class=\"p1\">f_{x,y}\\;<\/p>\n<p class=\"p1\">\\cos\\!\\Bigl[\\frac{(2x+1)u\\pi}{16}\\Bigr]\\,<\/p>\n<p class=\"p1\">\\cos\\!\\Bigl[\\frac{(2y+1)v\\pi}{16}\\Bigr]<\/p>\n<p class=\"p1\">\\tag{1}<\/p>\n<p class=\"p1\">\\]<\/p>\n<\/p>\n<p>where<\/p>\n<p class=\"p1\">\\[<\/p>\n<p class=\"p1\">\\alpha(k)=<\/p>\n<p class=\"p1\">\\begin{cases}<\/p>\n<p class=\"p1\">\\dfrac1{\\sqrt{2}}, &amp; k=0,\\\\[6pt]<\/p>\n<p class=\"p1\">1, &amp; k\\ge 1.<\/p>\n<p class=\"p1\">\\end{cases}<\/p>\n<p class=\"p1\">\\]<\/p>\n<p> <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-d28eb1caf4d0c1c6fad49a76dcf1fcd7_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#67;&#95;&#123;&#48;&#44;&#48;&#125;\" title=\"Rendered by QuickLaTeX.com\" height=\"18\" width=\"31\" style=\"vertical-align: -6px;\"\/> (the DC coefficient) represents the average luminance of the block. The <b>AC<\/b> coefficients C_{u,v} with <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-f8b0a2994090535db3387a23b96d68f2_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#117;&#44;&#32;&#118;&#32;&#92;&#110;&#101;&#113;&#32;&#48;\" title=\"Rendered by QuickLaTeX.com\" height=\"17\" width=\"60\" style=\"vertical-align: -4px;\"\/> describe increasingly fine details as either <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-f6b6854c2a333869e2c2bb8c982339bd_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#117;&#32;\" title=\"Rendered by QuickLaTeX.com\" height=\"8\" width=\"10\" style=\"vertical-align: 0px;\"\/>or <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-f516060802ba8658c6967ff76b28e475_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#118;&#32;\" title=\"Rendered by QuickLaTeX.com\" height=\"8\" width=\"9\" style=\"vertical-align: 0px;\"\/>increase. <\/p>\n<h3 class=\"wp-block-heading\">Simplified numerical example<\/h3>\n<p>Let\u2019s suppose a block where all values are 128, a medium gray. Then: <\/p>\n<p><img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-10d14ca9d7630918f33b4edf581813bf_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#67;&#95;&#123;&#48;&#44;&#48;&#125;&#32;&#61;&#32;&#56;&#32;&#92;&#99;&#100;&#111;&#116;&#32;&#56;&#32;&#92;&#99;&#100;&#111;&#116;&#32;&#49;&#50;&#56;&#32;&#92;&#99;&#100;&#111;&#116;&#32;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#52;&#125;&#32;&#92;&#99;&#100;&#111;&#116;&#32;&#92;&#97;&#108;&#112;&#104;&#97;&#40;&#48;&#41;&#94;&#50;&#32;&#61;&#32;&#54;&#52;&#32;&#92;&#99;&#100;&#111;&#116;&#32;&#49;&#50;&#56;&#32;&#92;&#99;&#100;&#111;&#116;&#32;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#52;&#125;&#32;&#92;&#99;&#100;&#111;&#116;&#32;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#50;&#125;&#32;&#61;&#32;&#49;&#48;&#50;&#52;\" title=\"Rendered by QuickLaTeX.com\" height=\"22\" width=\"390\" style=\"vertical-align: -6px;\"\/> while <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-21f20b4860c60891e0cdad863c164b8d_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#67;&#95;&#123;&#117;&#44;&#118;&#125;&#32;&#61;&#32;&#48;&#32;&#92;&#113;&#117;&#97;&#100;&#32;&#92;&#116;&#101;&#120;&#116;&#123;&#102;&#111;&#114;&#32;&#125;\" title=\"Rendered by QuickLaTeX.com\" height=\"19\" width=\"104\" style=\"vertical-align: -6px;\"\/> <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-c60f08aca839d142803dad02c4ea0b69_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#40;&#117;&#44;&#118;&#41;&#32;&#92;&#110;&#101;&#113;&#32;&#40;&#48;&#44;&#48;&#41;\" title=\"Rendered by QuickLaTeX.com\" height=\"19\" width=\"102\" style=\"vertical-align: -5px;\"\/><br \/>because there are no frequency variations.<\/p>\n<p>The compressed image preserves the lower-frequency coefficients, while the higher ones are aggressively quantized\u2014often down to 0.<\/p>\n<h3 class=\"wp-block-heading\">Quantization and selection of safe frequencies<\/h3>\n<p>Before being saved in JPEG format, the DCT coefficients are divided by a quantization matrix <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-cd69090f5c2d8ab2c05b77ea4f2526b5_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#81;&#95;&#123;&#117;&#44;&#118;&#125;\" title=\"Rendered by QuickLaTeX.com\" height=\"18\" width=\"33\" style=\"vertical-align: -6px;\"\/>, specific to each frequency:<\/p>\n<p class=\"p1\">\\[<\/p>\n<p class=\"p1\">\\tilde{C}{u,v}= \\operatorname{round}\\!\\Bigl(\\frac{C{u,v}}{Q_{u,v}}\\right)\\Big).<\/p>\n<p class=\"p1\">\\tag{2}<\/p>\n<p class=\"p1\">\\]<\/p>\n<p>The higher the value of <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-cd69090f5c2d8ab2c05b77ea4f2526b5_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#81;&#95;&#123;&#117;&#44;&#118;&#125;\" title=\"Rendered by QuickLaTeX.com\" height=\"18\" width=\"33\" style=\"vertical-align: -6px;\"\/>, the greater the loss of precision, with the possibility that the coefficients will be reduced to zero.<br \/>For this reason, in our algorithm we operate on a low-frequency subset of the AC coefficients, in positions where quantization is moderate and the values are more likely to survive compression.<br \/>We also avoid coefficients that are too low (including DC), as modifying them could introduce visible artifacts.<\/p>\n<h3 class=\"wp-block-heading\">Bit encoding in the coefficient<\/h3>\n<p>To ensure the bit survives JPEG compression, instead of using parity, we enforce the sign of the coefficient based on the bit to be written:<\/p>\n<p>If the bit is 0, we make the coefficient positive<\/p>\n<p class=\"p1\">\\[<\/p>\n<p>\\operatorname{embed}(c, b) =<\/p>\n<p>\\begin{cases}<\/p>\n<p>+\\text{minAmp} + \\text{boost}, &amp; b = 0 \\\\\\\\<\/p>\n<p>-\\text{minAmp} &#8211; \\text{boost}, &amp; b = 1<\/p>\n<p>\\end{cases}<\/p>\n<p>\\tag{3\u2019}<\/p>\n<p class=\"p1\">\\]<\/p>\n<p class=\"p1\">Where:<\/p>\n<p><img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-fc1945d79b767f05e0fb239e856a6ba4_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#92;&#116;&#101;&#120;&#116;&#123;&#109;&#105;&#110;&#65;&#109;&#112;&#125;\" title=\"Rendered by QuickLaTeX.com\" height=\"17\" width=\"68\" style=\"vertical-align: -4px;\"\/> ensures a value sufficiently far from zero (typically \u2265\u202f80),<br \/><img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-adb5446b7c5c59b04b6130e6bf9ee412_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#92;&#116;&#101;&#120;&#116;&#123;&#98;&#111;&#111;&#115;&#116;&#125;\" title=\"Rendered by QuickLaTeX.com\" height=\"12\" width=\"42\" style=\"vertical-align: 0px;\"\/> (e.g., 64) increases the distance from zero to prevent nullification during quantization.<\/p>\n<p class=\"p2\">In this way, even after lossy transformations, the sign remains unchanged and the bit can be recovered during reading.<\/p>\n<p>If we later wish to read the bit, we simply need to evaluate the <strong>sign<\/strong> of the quantized DCT coefficient:<\/p>\n<p class=\"p1\">\\[<\/p>\n<p>b =<\/p>\n<p>\\begin{cases}<\/p>\n<p>0, &amp; \\tilde{C}{u,v} \\ge 0 \\\\\\\\<\/p>\n<p>1, &amp; \\tilde{C}{u,v} &lt; 0<\/p>\n<p>\\end{cases}<\/p>\n<p>\\tag{4\u2019}<\/p>\n<p class=\"p1\">\\]<\/p>\n<p>In other words, a positive coefficient indicates bit 0, a negative coefficient indicates bit 1.<\/p>\n<p>This method is more robust because the sign of a coefficient survives many lossy transformations, unlike the least significant bit.<\/p>\n<h3 class=\"wp-block-heading\">Reconstruction (Inverse DCT)<\/h3>\n<p>After modifying the coefficients, we invert the transformation to obtain the watermarked image block: <\/p>\n<p class=\"p1\">\\[<\/p>\n<p class=\"p1\">f_{x,y}= \\frac{1}{4}\\!<\/p>\n<p class=\"p1\">\\sum_{u=0}^{7}\\sum_{v=0}^{7}<\/p>\n<p class=\"p1\">\\alpha(u)\\,\\alpha(v)\\,<\/p>\n<p class=\"p1\">\\tilde{C}_{u,v}\\,<\/p>\n<p class=\"p1\">\\cos\\!\\Bigl[\\frac{(2x+1)u\\pi}{16}\\Bigr]\\,<\/p>\n<p class=\"p1\">\\cos\\!\\Bigl[\\frac{(2y+1)v\\pi}{16}\\Bigr].<\/p>\n<p class=\"p1\">\\tag{5}<\/p>\n<p class=\"p1\">\\]<\/p>\n<p>The maximum error introduced by a \u00b11 variation on a mid-frequency coefficient is less than 1 quantum in luminance, which is below the human visual perception threshold for real photographs.<\/p>\n<h3 class=\"wp-block-heading\">Cyclic redundancy to induce robustness<\/h3>\n<p>To withstand compression or cropping, we encode the message M by duplicating each bit k times and applying a majority vote during reading. With k = 3: <\/p>\n<p class=\"p1\">\\[<\/p>\n<p class=\"p1\">M = b_1b_2\\dots b_n<\/p>\n<p class=\"p1\">\\;\\longrightarrow\\;<\/p>\n<p class=\"p1\">b_1b_1b_1\\,b_2b_2b_2\\dots b_nb_nb_n<\/p>\n<p class=\"p1\">\\tag{6}<\/p>\n<p class=\"p1\">\\]<\/p>\n<p>Correct recovery is guaranteed as long as <strong>at least two out of three copies survive<\/strong>.<\/p>\n<h2 class=\"wp-block-heading\">From formulas to code: the DCT class<\/h2>\n<p>Now that we have formalized the entire mathematical framework, we can translate equation (1) and its inverse directly into PHP.<\/p>\n<p>To keep the project in pure PHP, without native extensions or external dependencies, we implement the DCT manually on 8\u00d78 blocks.<\/p>\n<p>This approach is sufficiently fast for images up to a few megapixels and, most importantly, it is transparent and easy to understand and modify.<\/p>\n<p>The project is organized with Composer and PSR-4 autoloading, but the Dct class is <strong>completely self-contained<\/strong> and <strong>does not require any external libraries<\/strong>.<\/p>\n<p>If in the future you wish to extend the system with matrix analyses (e.g., box counting or distortion metrics), you can integrate MathPHP, but it is not required for the DCT.<\/p>\n<h3 class=\"wp-block-heading\">composer.json<\/h3>\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" style=\"font-size: .875rem; font-family: Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace; line-height: 1.25rem; --cbp-tab-width: 2; tab-size: var(--cbp-tab-width, 2);\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\">\n<pre class=\"shiki nord\" style=\"background-color: #2e3440ff;\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #eceff4;\">{<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #8fbcbb;\">name<\/span><span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #eceff4;\">:<\/span> <span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #a3be8c;\">renornad\/php-dct-invisible-watermark<\/span><span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #eceff4;\">,<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #8fbcbb;\">description<\/span><span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #eceff4;\">:<\/span> <span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #a3be8c;\">Pure-PHP DCT watermarking library for JPEG images.<\/span><span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #eceff4;\">,<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #8fbcbb;\">type<\/span><span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #eceff4;\">:<\/span> <span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #a3be8c;\">project<\/span><span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #eceff4;\">,<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #8fbcbb;\">license<\/span><span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #eceff4;\">:<\/span> <span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #a3be8c;\">MIT<\/span><span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #eceff4;\">,<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #8fbcbb;\">require<\/span><span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #eceff4;\">:<\/span> <span style=\"color: #eceff4;\">{<\/span><\/span>\n<span class=\"line\">      <span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #8fbcbb;\">php<\/span><span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #eceff4;\">:<\/span> <span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #a3be8c;\">&gt;=8.3<\/span><span style=\"color: #eceff4;\">\"<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #eceff4;\">},<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #8fbcbb;\">autoload<\/span><span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #eceff4;\">:<\/span> <span style=\"color: #eceff4;\">{<\/span><\/span>\n<span class=\"line\">      <span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #8fbcbb;\">psr-4<\/span><span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #eceff4;\">:<\/span> <span style=\"color: #eceff4;\">{<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #8fbcbb;\">Renor<\/span><span style=\"color: #ebcb8b;\">\\\\<\/span><span style=\"color: #8fbcbb;\">Watermark<\/span><span style=\"color: #ebcb8b;\">\\\\<\/span><span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #eceff4;\">:<\/span> <span style=\"color: #eceff4;\">\"<\/span><span style=\"color: #a3be8c;\">src\/<\/span><span style=\"color: #eceff4;\">\"<\/span><\/span>\n<span class=\"line\">      <span style=\"color: #eceff4;\">}<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #eceff4;\">}<\/span><\/span>\n<span class=\"line\">  <span style=\"color: #eceff4;\">}<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>After defining our composer.json file, we proceed with the installation. Open the terminal and type the command: <\/p>\n\n<pre class=\"wp-block-code\"><code>composer install<\/code><\/pre>\n<p>At this point, Composer will create the composer.lock file and the vendor directory, but it won\u2019t install any packages from Packagist because we are not including any dependencies.<\/p>\n<h2 class=\"wp-block-heading\">src\/Dct.php<\/h2>\n<p>We can now finally write the Dct class. Remember that it is preferable to include comments in the code, following the standard in English: <\/p>\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" style=\"font-size: .875rem; font-family: Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace; line-height: 1.25rem; --cbp-tab-width: 2; tab-size: var(--cbp-tab-width, 2);\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\">\n<pre class=\"shiki dark-plus\" style=\"background-color: #1e1e1e;\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #d4d4d4;\">&lt;?php<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #c586c0;\">declare<\/span><span style=\"color: #d4d4d4;\">(strict_types=<\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #569cd6;\">namespace<\/span> <span style=\"color: #4ec9b0;\">Renor\\Watermark<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #6a9955;\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * 2-D Discrete Cosine Transform (DCT) and its inverse (IDCT) for 8x8 blocks.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569cd6;\">final<\/span> <span style=\"color: #569cd6;\">class<\/span> <span style=\"color: #4ec9b0;\">Dct<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">{<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">private<\/span> <span style=\"color: #569cd6;\">const<\/span><span style=\"color: #d4d4d4;\"> N = <\/span><span style=\"color: #b5cea8;\">8<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">private<\/span> <span style=\"color: #569cd6;\">const<\/span><span style=\"color: #d4d4d4;\"> SQRT_2_INV = <\/span><span style=\"color: #b5cea8;\">0.7071067811865476<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #6a9955;\">\/\/ 1 \/ sqrt(2)<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #6a9955;\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * Performs the forward DCT on an 8x8 block of pixel intensities (0-255).<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     *\/<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">public<\/span> <span style=\"color: #569cd6;\">static<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">forward<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #569cd6;\">array<\/span> <span style=\"color: #9cdcfe;\">$block<\/span><span style=\"color: #d4d4d4;\">): <\/span><span style=\"color: #569cd6;\">array<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    {<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">assertBlock<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$block<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$C<\/span><span style=\"color: #d4d4d4;\"> = [];<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$u<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$u<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::N; ++<\/span><span style=\"color: #9cdcfe;\">$u<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #9cdcfe;\">$alphaU<\/span><span style=\"color: #d4d4d4;\"> = (<\/span><span style=\"color: #9cdcfe;\">$u<\/span><span style=\"color: #d4d4d4;\"> === <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">) ? <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::SQRT_2_INV : <\/span><span style=\"color: #b5cea8;\">1.0<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::N; ++<\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$alphaV<\/span><span style=\"color: #d4d4d4;\"> = (<\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\"> === <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">) ? <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::SQRT_2_INV : <\/span><span style=\"color: #b5cea8;\">1.0<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$sum<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0.0<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::N; ++<\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">                    <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::N; ++<\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">                        <span style=\"color: #9cdcfe;\">$cosX<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">cos<\/span><span style=\"color: #d4d4d4;\">((<\/span><span style=\"color: #b5cea8;\">2<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\"> + <\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">) * <\/span><span style=\"color: #9cdcfe;\">$u<\/span><span style=\"color: #d4d4d4;\"> * M_PI \/ (<\/span><span style=\"color: #b5cea8;\">2<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::N));<\/span><\/span>\n<span class=\"line\">                        <span style=\"color: #9cdcfe;\">$cosY<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">cos<\/span><span style=\"color: #d4d4d4;\">((<\/span><span style=\"color: #b5cea8;\">2<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\"> + <\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">) * <\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\"> * M_PI \/ (<\/span><span style=\"color: #b5cea8;\">2<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::N));<\/span><\/span>\n<span class=\"line\">                        <span style=\"color: #9cdcfe;\">$sum<\/span><span style=\"color: #d4d4d4;\"> += <\/span><span style=\"color: #9cdcfe;\">$block<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\">][<\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\">] * <\/span><span style=\"color: #9cdcfe;\">$cosX<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$cosY<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">                    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">                }<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #6a9955;\">\/\/ The DCT formula includes a factor of 1\/4<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$C<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #9cdcfe;\">$u<\/span><span style=\"color: #d4d4d4;\">][<\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\">] = <\/span><span style=\"color: #b5cea8;\">0.25<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$alphaU<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$alphaV<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$sum<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">return<\/span> <span style=\"color: #9cdcfe;\">$C<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    }<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #6a9955;\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * Performs the inverse DCT on an 8x8 block of coefficients, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * returning pixel values in the range [0..255].<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     *\/<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">public<\/span> <span style=\"color: #569cd6;\">static<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">inverse<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #569cd6;\">array<\/span> <span style=\"color: #9cdcfe;\">$coeff<\/span><span style=\"color: #d4d4d4;\">): <\/span><span style=\"color: #569cd6;\">array<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    {<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">assertBlock<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$coeff<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$f<\/span><span style=\"color: #d4d4d4;\"> = [];<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::N; ++<\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::N; ++<\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$sum<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0.0<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$u<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$u<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::N; ++<\/span><span style=\"color: #9cdcfe;\">$u<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">                    <span style=\"color: #9cdcfe;\">$alphaU<\/span><span style=\"color: #d4d4d4;\"> = (<\/span><span style=\"color: #9cdcfe;\">$u<\/span><span style=\"color: #d4d4d4;\"> === <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">) ? <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::SQRT_2_INV : <\/span><span style=\"color: #b5cea8;\">1.0<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">                    <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::N; ++<\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">                        <span style=\"color: #9cdcfe;\">$alphaV<\/span><span style=\"color: #d4d4d4;\"> = (<\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\"> === <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">) ? <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::SQRT_2_INV : <\/span><span style=\"color: #b5cea8;\">1.0<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">                        <span style=\"color: #9cdcfe;\">$cosX<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">cos<\/span><span style=\"color: #d4d4d4;\">((<\/span><span style=\"color: #b5cea8;\">2<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\"> + <\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">) * <\/span><span style=\"color: #9cdcfe;\">$u<\/span><span style=\"color: #d4d4d4;\"> * M_PI \/ (<\/span><span style=\"color: #b5cea8;\">2<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::N));<\/span><\/span>\n<span class=\"line\">                        <span style=\"color: #9cdcfe;\">$cosY<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">cos<\/span><span style=\"color: #d4d4d4;\">((<\/span><span style=\"color: #b5cea8;\">2<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\"> + <\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">) * <\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\"> * M_PI \/ (<\/span><span style=\"color: #b5cea8;\">2<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::N));<\/span><\/span>\n<span class=\"line\">                        <span style=\"color: #9cdcfe;\">$sum<\/span><span style=\"color: #d4d4d4;\"> += <\/span><span style=\"color: #9cdcfe;\">$alphaU<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$alphaV<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$coeff<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #9cdcfe;\">$u<\/span><span style=\"color: #d4d4d4;\">][<\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\">] * <\/span><span style=\"color: #9cdcfe;\">$cosX<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$cosY<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">                    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">                }<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$pixel<\/span><span style=\"color: #d4d4d4;\"> = (<\/span><span style=\"color: #569cd6;\">int<\/span><span style=\"color: #d4d4d4;\">) <\/span><span style=\"color: #dcdcaa;\">round<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">0.25<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$sum<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$f<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\">][<\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\">] = <\/span><span style=\"color: #dcdcaa;\">max<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #dcdcaa;\">min<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">255<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$pixel<\/span><span style=\"color: #d4d4d4;\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">return<\/span> <span style=\"color: #9cdcfe;\">$f<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    }<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #6a9955;\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * Checks that the array is exactly 8x8.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     *\/<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">private<\/span> <span style=\"color: #569cd6;\">static<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">assertBlock<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #569cd6;\">array<\/span> <span style=\"color: #9cdcfe;\">$block<\/span><span style=\"color: #d4d4d4;\">): <\/span><span style=\"color: #569cd6;\">void<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    {<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">if<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #dcdcaa;\">count<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$block<\/span><span style=\"color: #d4d4d4;\">) !== <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::N) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">throw<\/span> <span style=\"color: #569cd6;\">new<\/span> <span style=\"color: #4ec9b0;\">\\InvalidArgumentException<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #ce9178;\">'Block must have 8 rows.'<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">foreach<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$block<\/span><span style=\"color: #d4d4d4;\"> as <\/span><span style=\"color: #9cdcfe;\">$row<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">if<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #dcdcaa;\">count<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$row<\/span><span style=\"color: #d4d4d4;\">) !== <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::N) {<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #c586c0;\">throw<\/span> <span style=\"color: #569cd6;\">new<\/span> <span style=\"color: #4ec9b0;\">\\InvalidArgumentException<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #ce9178;\">'Each row must have 8 columns.'<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    }<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #6a9955;\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * Disallow instantiation.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     *\/<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">private<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">__construct<\/span><span style=\"color: #d4d4d4;\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">}<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>This class is the core of the project. It encapsulates the algorithm of the two-dimensional Discrete Cosine Transform applied to 8\u00d78 pixel blocks, the same scheme used by the JPEG standard.<br \/>At the start of the forward method, the class checks that the input array contains exactly eight rows and eight columns; otherwise, it throws an exception to prevent a sizing error from propagating silently.  <\/p>\n<p>Once the shape has been verified, for each pair of frequency indices <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-75fa73f534ffea86ffac4074123b96b5_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#117;&#44;&#32;&#118;\" title=\"Rendered by QuickLaTeX.com\" height=\"12\" width=\"27\" style=\"vertical-align: -4px;\"\/>, it computes the double summation defined by the canonical DCT formula: it takes each luminance value <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-533196a0d71c414a47d0753600045b35_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#102;&#95;&#123;&#120;&#44;&#121;&#125;\" title=\"Rendered by QuickLaTeX.com\" height=\"18\" width=\"28\" style=\"vertical-align: -6px;\"\/>, multiplies it by two cosine terms \u2014 one as a function of <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-43fe27dc3e528266a619764d90fce60b_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#117;\" title=\"Rendered by QuickLaTeX.com\" height=\"8\" width=\"10\" style=\"vertical-align: 0px;\"\/> and coordinate <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-ede05c264bba0eda080918aaa09c4658_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#120;\" title=\"Rendered by QuickLaTeX.com\" height=\"8\" width=\"10\" style=\"vertical-align: 0px;\"\/>, the other as a function of <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-ef71511c70f0e4b25cc6bd69f3bc20c2_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#118;\" title=\"Rendered by QuickLaTeX.com\" height=\"8\" width=\"9\" style=\"vertical-align: 0px;\"\/> and coordinate <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-0af556714940c351c933bba8cf840796_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#121;\" title=\"Rendered by QuickLaTeX.com\" height=\"12\" width=\"9\" style=\"vertical-align: -4px;\"\/> \u2014 and accumulates the result. Once the entire block has been scanned, it applies the normalization factor     <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-fb3d4f7d1fb07bdbf19390d35df9d5c1_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#92;&#116;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#52;&#125;&#32;&#92;&#97;&#108;&#112;&#104;&#97;&#40;&#117;&#41;&#92;&#97;&#108;&#112;&#104;&#97;&#40;&#118;&#41;\" title=\"Rendered by QuickLaTeX.com\" height=\"22\" width=\"78\" style=\"vertical-align: -6px;\"\/>, where <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-1bcc20827e12fcb2c5fa968a7d1b895a_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#92;&#97;&#108;&#112;&#104;&#97;&#40;&#48;&#41;&#32;&#61;&#32;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#92;&#115;&#113;&#114;&#116;&#123;&#50;&#125;&#125;\" title=\"Rendered by QuickLaTeX.com\" height=\"27\" width=\"79\" style=\"vertical-align: -11px;\"\/> and <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-e95917e94dcf66be56c331e91a855b06_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#92;&#97;&#108;&#112;&#104;&#97;&#40;&#107;&#41;&#32;&#61;&#32;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#50;&#125;\" title=\"Rendered by QuickLaTeX.com\" height=\"22\" width=\"68\" style=\"vertical-align: -6px;\"\/> for <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-58f509ef01deb77042355f3d2111cc1a_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#107;&#32;&#92;&#103;&#101;&#113;&#32;&#49;\" title=\"Rendered by QuickLaTeX.com\" height=\"15\" width=\"41\" style=\"vertical-align: -3px;\"\/>, so that the coefficient <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-d28eb1caf4d0c1c6fad49a76dcf1fcd7_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#67;&#95;&#123;&#48;&#44;&#48;&#125;\" title=\"Rendered by QuickLaTeX.com\" height=\"18\" width=\"31\" style=\"vertical-align: -6px;\"\/> preserves the average luminance, and all the others represent, at the correct scale, the increasingly finer detail components. The method therefore returns an 8\u00d78 matrix of floating-point coefficients: it is on this frequency representation that we will later embed the watermark bits.    <\/p>\n<p>The inverse path is handled by the inverse method. Here too, before any processing, the class enforces a check on the shape of the block. For each pair of pixel coordinates <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-40ca3e51a9803f260de25590c47d925e_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#120;&#44;&#32;&#121;\" title=\"Rendered by QuickLaTeX.com\" height=\"12\" width=\"27\" style=\"vertical-align: -4px;\"\/>, it reconstructs the luminance by summing the 64 frequency components, each weighted by the product of cosine terms and the normalization factors <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-7e8439594a36787d99d464e65263b0d6_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#92;&#97;&#108;&#112;&#104;&#97;&#40;&#117;&#41;&#92;&#97;&#108;&#112;&#104;&#97;&#40;&#118;&#41;\" title=\"Rendered by QuickLaTeX.com\" height=\"19\" width=\"69\" style=\"vertical-align: -5px;\"\/>. The final value is then multiplied by <img wpfc-lazyload-disable=\"true\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/ql-cache\/quicklatex.com-bc0cbfb7e7a2c46054a9130a25f73d75_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#92;&#116;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#52;&#125;\" title=\"Rendered by QuickLaTeX.com\" height=\"22\" width=\"7\" style=\"vertical-align: -6px;\"\/>, rounded to the nearest integer, and clamped to the 0\u2013255 range, to prevent any numerical errors from pushing the result outside the valid color space.   <\/p>\n<p>The implementation closely follows the mathematical definition, without relying on FFT or SIMD accelerations, favoring educational clarity over performance. The constructor is private, the class cannot be instantiated, and all methods are static and stateless: in this way, the DCT behaves like a pure function\u2014easily testable and reusable. When, in the following sections, we use it to embed a bit by modifying the sign of a low-frequency coefficient, we can be confident that the forward and inverse transformations are numerically consistent and that the alteration remains confined to the values we intend to manipulate.  <\/p>\n<h2 class=\"wp-block-heading\">src\/Watermarker.php<\/h2>\n<p>The Watermarker class is the director that orchestrates the most delicate phase of the entire project. It receives as input or output a sequence of 8\u00d78 DCT coefficient blocks already computed by the Dct class and, without dealing with the physical reading of the JPEG file, simply manipulates those numbers to hide or retrieve an ASCII text. <\/p>\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" style=\"font-size: .875rem; font-family: Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace; line-height: 1.25rem; --cbp-tab-width: 2; tab-size: var(--cbp-tab-width, 2);\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\">\n<pre class=\"shiki dark-plus\" style=\"background-color: #1e1e1e;\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #d4d4d4;\">&lt;?php<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #c586c0;\">declare<\/span><span style=\"color: #d4d4d4;\">(strict_types=<\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #569cd6;\">namespace<\/span> <span style=\"color: #4ec9b0;\">Renor\\Watermark<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #6a9955;\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * Watermarker class<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * Embeds\/extracts a short ASCII message (max 10 characters + terminator)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * into low-frequency DCT coefficients. Instead of relying on the single<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * parity bit \u2013 too fragile after rounding and quantization \u2013 here<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * we encode the information into the **sign** of the coefficient:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *   bit 0  \u2192 positive coefficient<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *   bit 1  \u2192 negative coefficient<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * The sign is never affected during:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *   1. IDCT \u2192 integer rounding,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *   2. division by JPEG quantization tables,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *   3. further rounding or transformations.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569cd6;\">final<\/span> <span style=\"color: #569cd6;\">class<\/span> <span style=\"color: #4ec9b0;\">Watermarker<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">{<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #6a9955;\">\/** Low-frequency coordinates (survive even at q\u224890\u2013100). *\/<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">private<\/span> <span style=\"color: #569cd6;\">const<\/span><span style=\"color: #d4d4d4;\"> EMBED_COORDS = [<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        [<\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">], [<\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">], [<\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">], [<\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #b5cea8;\">2<\/span><span style=\"color: #d4d4d4;\">],<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        [<\/span><span style=\"color: #b5cea8;\">2<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">], [<\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #b5cea8;\">2<\/span><span style=\"color: #d4d4d4;\">], [<\/span><span style=\"color: #b5cea8;\">2<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">], [<\/span><span style=\"color: #b5cea8;\">2<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #b5cea8;\">2<\/span><span style=\"color: #d4d4d4;\">]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    ];<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #6a9955;\">\/** Redundancy: each bit is repeated 25 times. *\/<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">private<\/span> <span style=\"color: #569cd6;\">const<\/span><span style=\"color: #d4d4d4;\"> REDUNDANCY = <\/span><span style=\"color: #b5cea8;\">25<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #569cd6;\">private<\/span> <span style=\"color: #569cd6;\">const<\/span><span style=\"color: #d4d4d4;\"> TERMINATOR = <\/span><span style=\"color: #ce9178;\">\"<\/span><span style=\"color: #d7ba7d;\">\\0<\/span><span style=\"color: #ce9178;\">\"<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #6a9955;\">\/* ------------------------------------------------------------------<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">       Public API<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">    -------------------------------------------------------------------*\/<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #569cd6;\">public<\/span> <span style=\"color: #569cd6;\">static<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">embed<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #569cd6;\">array<\/span> <span style=\"color: #569cd6;\">&amp;<\/span><span style=\"color: #9cdcfe;\">$blocks<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #569cd6;\">string<\/span> <span style=\"color: #9cdcfe;\">$msg<\/span><span style=\"color: #d4d4d4;\">): <\/span><span style=\"color: #569cd6;\">void<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    {<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">if<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #dcdcaa;\">strlen<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$msg<\/span><span style=\"color: #d4d4d4;\">) &gt; <\/span><span style=\"color: #b5cea8;\">10<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">throw<\/span> <span style=\"color: #569cd6;\">new<\/span> <span style=\"color: #4ec9b0;\">\\RuntimeException<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #ce9178;\">'Message too long (max 10).'<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$bits<\/span><span style=\"color: #d4d4d4;\">   = <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">stringToBitStream<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$msg<\/span> <span style=\"color: #d4d4d4;\">.<\/span> <span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::TERMINATOR);<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$cursor<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #c586c0;\">foreach<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$blocks<\/span><span style=\"color: #d4d4d4;\"> as <\/span><span style=\"color: #569cd6;\">&amp;<\/span><span style=\"color: #9cdcfe;\">$block<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">foreach<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::EMBED_COORDS as [<\/span><span style=\"color: #9cdcfe;\">$u<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\">]) {<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #c586c0;\">if<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$cursor<\/span><span style=\"color: #d4d4d4;\"> &gt;= <\/span><span style=\"color: #dcdcaa;\">count<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$bits<\/span><span style=\"color: #d4d4d4;\">)) {<\/span><\/span>\n<span class=\"line\">                    <span style=\"color: #c586c0;\">return<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">                }<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$bit<\/span><span style=\"color: #d4d4d4;\">           = <\/span><span style=\"color: #9cdcfe;\">$bits<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #9cdcfe;\">$cursor<\/span><span style=\"color: #d4d4d4;\">++];<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$block<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #9cdcfe;\">$u<\/span><span style=\"color: #d4d4d4;\">][<\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\">] = <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">forceSign<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$block<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #9cdcfe;\">$u<\/span><span style=\"color: #d4d4d4;\">][<\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\">], <\/span><span style=\"color: #9cdcfe;\">$bit<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">if<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$cursor<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #dcdcaa;\">count<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$bits<\/span><span style=\"color: #d4d4d4;\">)) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">throw<\/span> <span style=\"color: #569cd6;\">new<\/span> <span style=\"color: #4ec9b0;\">\\RuntimeException<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #ce9178;\">'Image too small for the message.'<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    }<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #569cd6;\">public<\/span> <span style=\"color: #569cd6;\">static<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">extract<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #569cd6;\">array<\/span> <span style=\"color: #9cdcfe;\">$blocks<\/span><span style=\"color: #d4d4d4;\">): <\/span><span style=\"color: #569cd6;\">string<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    {<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$bits<\/span><span style=\"color: #d4d4d4;\"> = [];<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">foreach<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$blocks<\/span><span style=\"color: #d4d4d4;\"> as <\/span><span style=\"color: #9cdcfe;\">$block<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">foreach<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::EMBED_COORDS as [<\/span><span style=\"color: #9cdcfe;\">$u<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\">]) {<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$bits<\/span><span style=\"color: #d4d4d4;\">[] = ( (<\/span><span style=\"color: #569cd6;\">int<\/span><span style=\"color: #d4d4d4;\">) <\/span><span style=\"color: #dcdcaa;\">round<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$block<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #9cdcfe;\">$u<\/span><span style=\"color: #d4d4d4;\">][<\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\">]) &lt; <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\"> ) ? <\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\"> : <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$filtered<\/span><span style=\"color: #d4d4d4;\">   = <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">majority<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$bits<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::REDUNDANCY);<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$byteChunks<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">array_chunk<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$filtered<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #b5cea8;\">8<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$out<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #ce9178;\">''<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">foreach<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$byteChunks<\/span><span style=\"color: #d4d4d4;\"> as <\/span><span style=\"color: #9cdcfe;\">$chunk<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">if<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #dcdcaa;\">count<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$chunk<\/span><span style=\"color: #d4d4d4;\">) &lt; <\/span><span style=\"color: #b5cea8;\">8<\/span><span style=\"color: #d4d4d4;\">) <\/span><span style=\"color: #c586c0;\">break<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #9cdcfe;\">$ch<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">chr<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">bitsToInt<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$chunk<\/span><span style=\"color: #d4d4d4;\">));<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">if<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$ch<\/span><span style=\"color: #d4d4d4;\"> === <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::TERMINATOR) <\/span><span style=\"color: #c586c0;\">break<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #9cdcfe;\">$out<\/span> <span style=\"color: #d4d4d4;\">.=<\/span> <span style=\"color: #9cdcfe;\">$ch<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">return<\/span> <span style=\"color: #9cdcfe;\">$out<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    }<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #6a9955;\">\/* ------------------------------------------------------------------<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">       Private helpers<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">    -------------------------------------------------------------------*\/<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #569cd6;\">private<\/span> <span style=\"color: #569cd6;\">static<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">stringToBitStream<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #569cd6;\">string<\/span> <span style=\"color: #9cdcfe;\">$s<\/span><span style=\"color: #d4d4d4;\">): <\/span><span style=\"color: #569cd6;\">array<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    {<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$bits<\/span><span style=\"color: #d4d4d4;\"> = [];<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">foreach<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #dcdcaa;\">str_split<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$s<\/span><span style=\"color: #d4d4d4;\">) as <\/span><span style=\"color: #9cdcfe;\">$c<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #9cdcfe;\">$byte<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">ord<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$c<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$i<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">7<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$i<\/span><span style=\"color: #d4d4d4;\"> &gt;= <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; --<\/span><span style=\"color: #9cdcfe;\">$i<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$bit<\/span><span style=\"color: #d4d4d4;\"> = (<\/span><span style=\"color: #9cdcfe;\">$byte<\/span><span style=\"color: #d4d4d4;\"> &gt;&gt; <\/span><span style=\"color: #9cdcfe;\">$i<\/span><span style=\"color: #d4d4d4;\">) &amp; <\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$bits<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">array_merge<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$bits<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #dcdcaa;\">array_fill<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::REDUNDANCY, <\/span><span style=\"color: #9cdcfe;\">$bit<\/span><span style=\"color: #d4d4d4;\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">return<\/span> <span style=\"color: #9cdcfe;\">$bits<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    }<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #569cd6;\">private<\/span> <span style=\"color: #569cd6;\">static<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">majority<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #569cd6;\">array<\/span> <span style=\"color: #9cdcfe;\">$bits<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #569cd6;\">int<\/span> <span style=\"color: #9cdcfe;\">$group<\/span><span style=\"color: #d4d4d4;\">): <\/span><span style=\"color: #569cd6;\">array<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    {<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$out<\/span><span style=\"color: #d4d4d4;\"> = [];<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">foreach<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #dcdcaa;\">array_chunk<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$bits<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$group<\/span><span style=\"color: #d4d4d4;\">) as <\/span><span style=\"color: #9cdcfe;\">$chunk<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #9cdcfe;\">$out<\/span><span style=\"color: #d4d4d4;\">[] = (<\/span><span style=\"color: #dcdcaa;\">array_sum<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$chunk<\/span><span style=\"color: #d4d4d4;\">) &gt; <\/span><span style=\"color: #9cdcfe;\">$group<\/span><span style=\"color: #d4d4d4;\"> \/ <\/span><span style=\"color: #b5cea8;\">2<\/span><span style=\"color: #d4d4d4;\">) ? <\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\"> : <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">return<\/span> <span style=\"color: #9cdcfe;\">$out<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    }<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #569cd6;\">private<\/span> <span style=\"color: #569cd6;\">static<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">bitsToInt<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #569cd6;\">array<\/span> <span style=\"color: #9cdcfe;\">$bits<\/span><span style=\"color: #d4d4d4;\">): <\/span><span style=\"color: #569cd6;\">int<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    {<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">return<\/span> <span style=\"color: #dcdcaa;\">array_reduce<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$bits<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #569cd6;\">fn<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$b<\/span><span style=\"color: #d4d4d4;\">) =&gt; (<\/span><span style=\"color: #9cdcfe;\">$v<\/span><span style=\"color: #d4d4d4;\"> &lt;&lt; <\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">) | <\/span><span style=\"color: #9cdcfe;\">$b<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    }<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #6a9955;\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * Forces the sign of the coefficient:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     *   bit 0 \u2192 positive   (&gt;= +minAmp)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     *   bit 1 \u2192 negative   (&lt;= -minAmp)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * so the quantizer cannot flip it.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     *\/<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">private<\/span> <span style=\"color: #569cd6;\">static<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">forceSign<\/span><span style=\"color: #d4d4d4;\">(<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #569cd6;\">float<\/span> <span style=\"color: #9cdcfe;\">$coeff<\/span><span style=\"color: #d4d4d4;\">,<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #569cd6;\">int<\/span>   <span style=\"color: #9cdcfe;\">$bit<\/span><span style=\"color: #d4d4d4;\">,<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #569cd6;\">int<\/span>   <span style=\"color: #9cdcfe;\">$minAmp<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">80<\/span><span style=\"color: #d4d4d4;\">,   <\/span><span style=\"color: #6a9955;\">\/\/ safe amplitude &gt; luminance quantization divisors<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #569cd6;\">int<\/span>   <span style=\"color: #9cdcfe;\">$boost<\/span><span style=\"color: #d4d4d4;\">  = <\/span><span style=\"color: #b5cea8;\">64<\/span>    <span style=\"color: #6a9955;\">\/\/ further offset to move away from zero<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    ): <\/span><span style=\"color: #569cd6;\">float<\/span><span style=\"color: #d4d4d4;\"> {<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$rounded<\/span><span style=\"color: #d4d4d4;\"> = (<\/span><span style=\"color: #569cd6;\">int<\/span><span style=\"color: #d4d4d4;\">) <\/span><span style=\"color: #dcdcaa;\">round<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$coeff<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #6a9955;\">\/\/ Enforce minimum amplitude<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">if<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #dcdcaa;\">abs<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$rounded<\/span><span style=\"color: #d4d4d4;\">) &lt; <\/span><span style=\"color: #9cdcfe;\">$minAmp<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #9cdcfe;\">$rounded<\/span><span style=\"color: #d4d4d4;\"> = (<\/span><span style=\"color: #9cdcfe;\">$rounded<\/span><span style=\"color: #d4d4d4;\"> &gt;= <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">) ? <\/span><span style=\"color: #9cdcfe;\">$minAmp<\/span><span style=\"color: #d4d4d4;\"> : -<\/span><span style=\"color: #9cdcfe;\">$minAmp<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #6a9955;\">\/\/ Set the sign according to the bit<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">if<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$bit<\/span><span style=\"color: #d4d4d4;\"> === <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\"> &amp;&amp; <\/span><span style=\"color: #9cdcfe;\">$rounded<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">) <\/span><span style=\"color: #9cdcfe;\">$rounded<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">abs<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$rounded<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">if<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$bit<\/span><span style=\"color: #d4d4d4;\"> === <\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\"> &amp;&amp; <\/span><span style=\"color: #9cdcfe;\">$rounded<\/span><span style=\"color: #d4d4d4;\"> &gt; <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">) <\/span><span style=\"color: #9cdcfe;\">$rounded<\/span><span style=\"color: #d4d4d4;\"> = -<\/span><span style=\"color: #9cdcfe;\">$rounded<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #6a9955;\">\/\/ Push further from zero: +\/-boost (preserving the sign)<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$rounded<\/span><span style=\"color: #d4d4d4;\"> += (<\/span><span style=\"color: #9cdcfe;\">$rounded<\/span><span style=\"color: #d4d4d4;\"> &gt; <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">) ? <\/span><span style=\"color: #9cdcfe;\">$boost<\/span><span style=\"color: #d4d4d4;\"> : -<\/span><span style=\"color: #9cdcfe;\">$boost<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #c586c0;\">return<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #569cd6;\">float<\/span><span style=\"color: #d4d4d4;\">) <\/span><span style=\"color: #9cdcfe;\">$rounded<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    }<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #569cd6;\">private<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">__construct<\/span><span style=\"color: #d4d4d4;\">() {}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">}<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>When the embed method is called, the caller provides the array of DCT blocks and the message to be embedded. The method converts each character into 8 bits, and each bit is replicated 25 times (as specified by the REDUNDANCY constant), so that it can later be read using a majority vote and withstand alterations due to JPEG compression. The resulting redundant bitstream flows block by block and relies on 8 <strong>low-frequency<\/strong> coordinates defined in the constant array EMBED_COORDS. These positions were chosen because they do not affect visual perception but tend to survive even moderate JPEG compressions (quality 60\u201380).   <\/p>\n<p>For each selected coefficient, the private function forceSign() enforces a specific sign: positive to represent 0, negative to represent 1. This approach\u2014more robust than using parity\u2014ensures that the information remains readable even after JPEG quantization.<br \/>If the image does not contain enough blocks to represent the entire message, an exception is thrown with an explicit message.  <\/p>\n<p>The inverse process is handled by the extract method. Here too, the class reads the sign of the same 8 coefficients in each block, reconstructing a long vector of zeros and ones. The bits are then grouped according to the redundancy factor and passed through a majority vote function (majority()), which recovers the original bit. Every group of 8 bits yields one character, until a NUL terminator is encountered, signaling the end of the message. The resulting sequence of characters forms the original message.    <\/p>\n<p>The helper functions stringToBitStream, bitsToInt, and majority encapsulate binary-level details, keeping the public methods short and readable. Like the Dct class, Watermarker is also stateless and cannot be instantiated: all methods are static. This functional approach facilitates automated testing and use in concurrent environments.<br \/>In summary, the Watermarker class concretely implements the mathematical principles described earlier: cyclic redundancy, bit encoding via sign, explicit message termination\u2014all in a compact and robust flow designed to survive the typical transformations of images published online.   <\/p>\n<h2 class=\"wp-block-heading\">ImageIO: from the image to DCT blocks and back<\/h2>\n<p>The ImageIO class is the bridge between the mathematical theory and the actual JPEG file.<\/p>\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" style=\"font-size: .875rem; font-family: Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace; line-height: 1.25rem; --cbp-tab-width: 2; tab-size: var(--cbp-tab-width, 2);\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\">\n<pre class=\"shiki dark-plus\" style=\"background-color: #1e1e1e;\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #d4d4d4;\">&lt;?php<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #c586c0;\">declare<\/span><span style=\"color: #d4d4d4;\">(strict_types=<\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #569cd6;\">namespace<\/span> <span style=\"color: #4ec9b0;\">Renor\\Watermark<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #569cd6;\">use<\/span> <span style=\"color: #4ec9b0;\">GdImage<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #6a9955;\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * Class ImageIO<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * - Loads a JPEG image.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * - Converts RGB to the Y (luminance) channel.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * - Splits it into 8x8 blocks and applies DCT\/IDCT.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * - Overwrites the Y channel with the embedded watermark, merging with the original CbCr.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * - Saves the final image as JPEG with a specified quality.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569cd6;\">final<\/span> <span style=\"color: #569cd6;\">class<\/span> <span style=\"color: #4ec9b0;\">ImageIO<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">{<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">private<\/span> <span style=\"color: #569cd6;\">const<\/span><span style=\"color: #d4d4d4;\"> BLOCK_SIZE = <\/span><span style=\"color: #b5cea8;\">8<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">private<\/span> <span style=\"color: #569cd6;\">const<\/span><span style=\"color: #d4d4d4;\"> MIN_WIDTH = <\/span><span style=\"color: #b5cea8;\">200<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">private<\/span> <span style=\"color: #569cd6;\">const<\/span><span style=\"color: #d4d4d4;\"> MIN_HEIGHT = <\/span><span style=\"color: #b5cea8;\">200<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #6a9955;\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * Embed a watermark in a JPEG image and save the result.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     *<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * <\/span><span style=\"color: #569cd6;\">@param<\/span> <span style=\"color: #569cd6;\">string<\/span><span style=\"color: #6a9955;\"> $src      Path to the original JPEG<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * <\/span><span style=\"color: #569cd6;\">@param<\/span> <span style=\"color: #569cd6;\">string<\/span><span style=\"color: #6a9955;\"> $dest     Output path for the watermarked image<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * <\/span><span style=\"color: #569cd6;\">@param<\/span> <span style=\"color: #569cd6;\">string<\/span><span style=\"color: #6a9955;\"> $message  ASCII watermark (up to 10 chars)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * <\/span><span style=\"color: #569cd6;\">@param<\/span> <span style=\"color: #569cd6;\">int<\/span><span style=\"color: #6a9955;\">    $quality  JPEG quality in [0..100], default 90<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     *\/<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">public<\/span> <span style=\"color: #569cd6;\">static<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">embed<\/span><span style=\"color: #d4d4d4;\">(<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #569cd6;\">string<\/span> <span style=\"color: #9cdcfe;\">$src<\/span><span style=\"color: #d4d4d4;\">,<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #569cd6;\">string<\/span> <span style=\"color: #9cdcfe;\">$dest<\/span><span style=\"color: #d4d4d4;\">,<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #569cd6;\">string<\/span> <span style=\"color: #9cdcfe;\">$message<\/span><span style=\"color: #d4d4d4;\">,<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #569cd6;\">int<\/span> <span style=\"color: #9cdcfe;\">$quality<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">90<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    ): <\/span><span style=\"color: #569cd6;\">void<\/span><span style=\"color: #d4d4d4;\"> {<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">loadJpeg<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$src<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">imagesx<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">imagesy<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #6a9955;\">\/\/ Ensure a minimum image size<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">if<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::MIN_WIDTH || <\/span><span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::MIN_HEIGHT) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #dcdcaa;\">imagedestroy<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">throw<\/span> <span style=\"color: #569cd6;\">new<\/span> <span style=\"color: #4ec9b0;\">\\RuntimeException<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #ce9178;\">\"Image must be at least 200x200 for robust embedding.\"<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #6a9955;\">\/\/ Convert RGB \u2192 Y<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$Y<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">rgbToY<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #6a9955;\">\/\/ Split into 8x8 blocks, apply forward DCT<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$blocks<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">forwardBlocks<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$Y<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #6a9955;\">\/\/ Embed the message into the DCT coefficients<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #4ec9b0;\">Watermarker<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">embed<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$blocks<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$message<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #6a9955;\">\/\/ Reconstruct the Y channel from the inverse DCT<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$Ywm<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">inverseBlocks<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$blocks<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #6a9955;\">\/\/ Merge the modified Y channel and save as JPEG<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">mergeAndSave<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$Ywm<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$dest<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$quality<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #dcdcaa;\">imagedestroy<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    }<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #6a9955;\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * Extract the watermark from a JPEG image.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     *<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * <\/span><span style=\"color: #569cd6;\">@param<\/span> <span style=\"color: #569cd6;\">string<\/span><span style=\"color: #6a9955;\"> $src Path to the watermarked JPEG<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * <\/span><span style=\"color: #569cd6;\">@return<\/span> <span style=\"color: #569cd6;\">string<\/span><span style=\"color: #6a9955;\">     The recovered ASCII message<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     *\/<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">public<\/span> <span style=\"color: #569cd6;\">static<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">extract<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #569cd6;\">string<\/span> <span style=\"color: #9cdcfe;\">$src<\/span><span style=\"color: #d4d4d4;\">): <\/span><span style=\"color: #569cd6;\">string<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    {<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">loadJpeg<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$src<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">imagesx<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">imagesy<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #c586c0;\">if<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::MIN_WIDTH || <\/span><span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::MIN_HEIGHT) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #dcdcaa;\">imagedestroy<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">throw<\/span> <span style=\"color: #569cd6;\">new<\/span> <span style=\"color: #4ec9b0;\">\\RuntimeException<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #ce9178;\">\"Image is too small (&lt;200x200). It may not contain a robust watermark.\"<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #6a9955;\">\/\/ Convert to Y<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$Y<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">rgbToY<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #6a9955;\">\/\/ Apply DCT on 8x8 blocks<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$blocks<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">forwardBlocks<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$Y<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #6a9955;\">\/\/ Extract the message from the DCT blocks<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$msg<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #4ec9b0;\">Watermarker<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">extract<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$blocks<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #dcdcaa;\">imagedestroy<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">return<\/span> <span style=\"color: #9cdcfe;\">$msg<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    }<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #6a9955;\">\/* -------------------------------------------------------------------------<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">       INTERNAL METHODS<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">    -------------------------------------------------------------------------- *\/<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #6a9955;\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * Loads a JPEG image from disk or throws an exception if invalid.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     *\/<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">public<\/span> <span style=\"color: #569cd6;\">static<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">loadJpeg<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #569cd6;\">string<\/span> <span style=\"color: #9cdcfe;\">$path<\/span><span style=\"color: #d4d4d4;\">): <\/span><span style=\"color: #4ec9b0;\">GdImage<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    {<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">if<\/span><span style=\"color: #d4d4d4;\"> (!<\/span><span style=\"color: #dcdcaa;\">is_file<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$path<\/span><span style=\"color: #d4d4d4;\">)) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">throw<\/span> <span style=\"color: #569cd6;\">new<\/span> <span style=\"color: #4ec9b0;\">\\RuntimeException<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #ce9178;\">\"File not found: <\/span><span style=\"color: #9cdcfe;\">$path<\/span><span style=\"color: #ce9178;\">\"<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\"> = @<\/span><span style=\"color: #dcdcaa;\">imagecreatefromjpeg<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$path<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">if<\/span><span style=\"color: #d4d4d4;\"> (!<\/span><span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">throw<\/span> <span style=\"color: #569cd6;\">new<\/span> <span style=\"color: #4ec9b0;\">\\RuntimeException<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #ce9178;\">\"Invalid JPEG: <\/span><span style=\"color: #9cdcfe;\">$path<\/span><span style=\"color: #ce9178;\">\"<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #c586c0;\">return<\/span> <span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    }<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #6a9955;\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * Converts an RGB image to a 2D Y (luminance) matrix.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     *\/<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">public<\/span> <span style=\"color: #569cd6;\">static<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">rgbToY<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #4ec9b0;\">GdImage<\/span> <span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\">): <\/span><span style=\"color: #569cd6;\">array<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    {<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">imagesx<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">imagesy<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$Y<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">array_fill<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #dcdcaa;\">array_fill<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">));<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\">++) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\">++) {<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$rgb<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">imagecolorat<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$im<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$r<\/span><span style=\"color: #d4d4d4;\"> = (<\/span><span style=\"color: #9cdcfe;\">$rgb<\/span><span style=\"color: #d4d4d4;\"> &gt;&gt; <\/span><span style=\"color: #b5cea8;\">16<\/span><span style=\"color: #d4d4d4;\">) &amp; <\/span><span style=\"color: #b5cea8;\">0xFF<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$g<\/span><span style=\"color: #d4d4d4;\"> = (<\/span><span style=\"color: #9cdcfe;\">$rgb<\/span><span style=\"color: #d4d4d4;\"> &gt;&gt; <\/span><span style=\"color: #b5cea8;\">8<\/span><span style=\"color: #d4d4d4;\">) &amp; <\/span><span style=\"color: #b5cea8;\">0xFF<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$b<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #9cdcfe;\">$rgb<\/span><span style=\"color: #d4d4d4;\"> &amp; <\/span><span style=\"color: #b5cea8;\">0xFF<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #6a9955;\">\/\/ ITU-R BT.601 luma formula<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$luma<\/span><span style=\"color: #d4d4d4;\"> = (<\/span><span style=\"color: #569cd6;\">int<\/span><span style=\"color: #d4d4d4;\">) <\/span><span style=\"color: #dcdcaa;\">round<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">0.299<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$r<\/span><span style=\"color: #d4d4d4;\"> + <\/span><span style=\"color: #b5cea8;\">0.587<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$g<\/span><span style=\"color: #d4d4d4;\"> + <\/span><span style=\"color: #b5cea8;\">0.114<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$b<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$Y<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\">][<\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\">] = <\/span><span style=\"color: #dcdcaa;\">max<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #dcdcaa;\">min<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">255<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$luma<\/span><span style=\"color: #d4d4d4;\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #c586c0;\">return<\/span> <span style=\"color: #9cdcfe;\">$Y<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    }<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #6a9955;\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * Splits the Y matrix into 8x8 blocks and applies forward DCT.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     *\/<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">public<\/span> <span style=\"color: #569cd6;\">static<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">forwardBlocks<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #569cd6;\">array<\/span> <span style=\"color: #9cdcfe;\">$Y<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #569cd6;\">int<\/span> <span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #569cd6;\">int<\/span> <span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\">): <\/span><span style=\"color: #569cd6;\">array<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    {<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$blocks<\/span><span style=\"color: #d4d4d4;\"> = [];<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$by<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$by<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$by<\/span><span style=\"color: #d4d4d4;\"> += <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::BLOCK_SIZE) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$bx<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$bx<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$bx<\/span><span style=\"color: #d4d4d4;\"> += <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::BLOCK_SIZE) {<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$block<\/span><span style=\"color: #d4d4d4;\"> = [];<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$i<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$i<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::BLOCK_SIZE; <\/span><span style=\"color: #9cdcfe;\">$i<\/span><span style=\"color: #d4d4d4;\">++) {<\/span><\/span>\n<span class=\"line\">                    <span style=\"color: #9cdcfe;\">$row<\/span><span style=\"color: #d4d4d4;\"> = [];<\/span><\/span>\n<span class=\"line\">                    <span style=\"color: #9cdcfe;\">$srcY<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">min<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$by<\/span><span style=\"color: #d4d4d4;\"> + <\/span><span style=\"color: #9cdcfe;\">$i<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\"> - <\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">                    <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$j<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$j<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::BLOCK_SIZE; <\/span><span style=\"color: #9cdcfe;\">$j<\/span><span style=\"color: #d4d4d4;\">++) {<\/span><\/span>\n<span class=\"line\">                        <span style=\"color: #9cdcfe;\">$srcX<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">min<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$bx<\/span><span style=\"color: #d4d4d4;\"> + <\/span><span style=\"color: #9cdcfe;\">$j<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\"> - <\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">                        <span style=\"color: #9cdcfe;\">$row<\/span><span style=\"color: #d4d4d4;\">[] = <\/span><span style=\"color: #9cdcfe;\">$Y<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #9cdcfe;\">$srcY<\/span><span style=\"color: #d4d4d4;\">][<\/span><span style=\"color: #9cdcfe;\">$srcX<\/span><span style=\"color: #d4d4d4;\">];<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">                    }<\/span><\/span>\n<span class=\"line\">                    <span style=\"color: #9cdcfe;\">$block<\/span><span style=\"color: #d4d4d4;\">[] = <\/span><span style=\"color: #9cdcfe;\">$row<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">                }<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$blocks<\/span><span style=\"color: #d4d4d4;\">[] = <\/span><span style=\"color: #4ec9b0;\">Dct<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">forward<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$block<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">return<\/span> <span style=\"color: #9cdcfe;\">$blocks<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    }<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #6a9955;\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * Applies inverse DCT to each 8x8 block and rebuilds the Y matrix.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     *\/<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">private<\/span> <span style=\"color: #569cd6;\">static<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">inverseBlocks<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #569cd6;\">array<\/span> <span style=\"color: #9cdcfe;\">$blocks<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #569cd6;\">int<\/span> <span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #569cd6;\">int<\/span> <span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\">): <\/span><span style=\"color: #569cd6;\">array<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    {<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$Y<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">array_fill<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #dcdcaa;\">array_fill<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">));<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$idx<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$by<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$by<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$by<\/span><span style=\"color: #d4d4d4;\"> += <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::BLOCK_SIZE) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$bx<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$bx<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$bx<\/span><span style=\"color: #d4d4d4;\"> += <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::BLOCK_SIZE) {<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$coeffBlock<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #9cdcfe;\">$blocks<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #9cdcfe;\">$idx<\/span><span style=\"color: #d4d4d4;\">++];<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$pixBlock<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #4ec9b0;\">Dct<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">inverse<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$coeffBlock<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\">                <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$i<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$i<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::BLOCK_SIZE; <\/span><span style=\"color: #9cdcfe;\">$i<\/span><span style=\"color: #d4d4d4;\">++) {<\/span><\/span>\n<span class=\"line\">                    <span style=\"color: #9cdcfe;\">$dstY<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #9cdcfe;\">$by<\/span><span style=\"color: #d4d4d4;\"> + <\/span><span style=\"color: #9cdcfe;\">$i<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">                    <span style=\"color: #c586c0;\">if<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$dstY<\/span><span style=\"color: #d4d4d4;\"> &gt;= <\/span><span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\">) <\/span><span style=\"color: #c586c0;\">break<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">                    <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$j<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$j<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #569cd6;\">self<\/span><span style=\"color: #d4d4d4;\">::BLOCK_SIZE; <\/span><span style=\"color: #9cdcfe;\">$j<\/span><span style=\"color: #d4d4d4;\">++) {<\/span><\/span>\n<span class=\"line\">                        <span style=\"color: #9cdcfe;\">$dstX<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #9cdcfe;\">$bx<\/span><span style=\"color: #d4d4d4;\"> + <\/span><span style=\"color: #9cdcfe;\">$j<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">                        <span style=\"color: #c586c0;\">if<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$dstX<\/span><span style=\"color: #d4d4d4;\"> &gt;= <\/span><span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\">) <\/span><span style=\"color: #c586c0;\">break<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">                        <span style=\"color: #9cdcfe;\">$Y<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #9cdcfe;\">$dstY<\/span><span style=\"color: #d4d4d4;\">][<\/span><span style=\"color: #9cdcfe;\">$dstX<\/span><span style=\"color: #d4d4d4;\">] = <\/span><span style=\"color: #9cdcfe;\">$pixBlock<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #9cdcfe;\">$i<\/span><span style=\"color: #d4d4d4;\">][<\/span><span style=\"color: #9cdcfe;\">$j<\/span><span style=\"color: #d4d4d4;\">];<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">                    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">                }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #c586c0;\">return<\/span> <span style=\"color: #9cdcfe;\">$Y<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    }<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #6a9955;\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * Merges the watermarked Y channel with the original CbCr, then saves the final JPEG.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     *\/<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">private<\/span> <span style=\"color: #569cd6;\">static<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">mergeAndSave<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #4ec9b0;\">GdImage<\/span> <span style=\"color: #9cdcfe;\">$orig<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #569cd6;\">array<\/span> <span style=\"color: #9cdcfe;\">$Ywm<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #569cd6;\">string<\/span> <span style=\"color: #9cdcfe;\">$dest<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #569cd6;\">int<\/span> <span style=\"color: #9cdcfe;\">$quality<\/span><span style=\"color: #d4d4d4;\">): <\/span><span style=\"color: #569cd6;\">void<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    {<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">imagesx<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$orig<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">imagesy<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$orig<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #6a9955;\">\/\/ 1) Overwrite the RGB pixels of the GDImage using the new Y<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #9cdcfe;\">$h<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\">++) {<\/span><\/span>\n<span class=\"line\">            <span style=\"color: #c586c0;\">for<\/span><span style=\"color: #d4d4d4;\"> (<\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\"> &lt; <\/span><span style=\"color: #9cdcfe;\">$w<\/span><span style=\"color: #d4d4d4;\">; <\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\">++) {<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$rgb<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">imagecolorat<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$orig<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$r<\/span><span style=\"color: #d4d4d4;\"> = (<\/span><span style=\"color: #9cdcfe;\">$rgb<\/span><span style=\"color: #d4d4d4;\"> &gt;&gt; <\/span><span style=\"color: #b5cea8;\">16<\/span><span style=\"color: #d4d4d4;\">) &amp; <\/span><span style=\"color: #b5cea8;\">0xFF<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$g<\/span><span style=\"color: #d4d4d4;\"> = (<\/span><span style=\"color: #9cdcfe;\">$rgb<\/span><span style=\"color: #d4d4d4;\"> &gt;&gt; <\/span><span style=\"color: #b5cea8;\">8<\/span><span style=\"color: #d4d4d4;\">) &amp; <\/span><span style=\"color: #b5cea8;\">0xFF<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$b<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #9cdcfe;\">$rgb<\/span><span style=\"color: #d4d4d4;\"> &amp; <\/span><span style=\"color: #b5cea8;\">0xFF<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$cb<\/span><span style=\"color: #d4d4d4;\"> = -<\/span><span style=\"color: #b5cea8;\">0.169<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$r<\/span><span style=\"color: #d4d4d4;\"> - <\/span><span style=\"color: #b5cea8;\">0.331<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$g<\/span><span style=\"color: #d4d4d4;\"> + <\/span><span style=\"color: #b5cea8;\">0.5<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$b<\/span><span style=\"color: #d4d4d4;\"> + <\/span><span style=\"color: #b5cea8;\">128<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$cr<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #b5cea8;\">0.5<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$r<\/span><span style=\"color: #d4d4d4;\"> - <\/span><span style=\"color: #b5cea8;\">0.419<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$g<\/span><span style=\"color: #d4d4d4;\"> - <\/span><span style=\"color: #b5cea8;\">0.081<\/span><span style=\"color: #d4d4d4;\"> * <\/span><span style=\"color: #9cdcfe;\">$b<\/span><span style=\"color: #d4d4d4;\"> + <\/span><span style=\"color: #b5cea8;\">128<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$Yval<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #9cdcfe;\">$Ywm<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\">][<\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\">];<\/span><\/span>\n\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$R<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #9cdcfe;\">$Yval<\/span><span style=\"color: #d4d4d4;\"> + <\/span><span style=\"color: #b5cea8;\">1.402<\/span><span style=\"color: #d4d4d4;\"> * (<\/span><span style=\"color: #9cdcfe;\">$cr<\/span><span style=\"color: #d4d4d4;\"> - <\/span><span style=\"color: #b5cea8;\">128<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$G<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #9cdcfe;\">$Yval<\/span><span style=\"color: #d4d4d4;\"> - <\/span><span style=\"color: #b5cea8;\">0.344136<\/span><span style=\"color: #d4d4d4;\"> * (<\/span><span style=\"color: #9cdcfe;\">$cb<\/span><span style=\"color: #d4d4d4;\"> - <\/span><span style=\"color: #b5cea8;\">128<\/span><span style=\"color: #d4d4d4;\">) - <\/span><span style=\"color: #b5cea8;\">0.714136<\/span><span style=\"color: #d4d4d4;\"> * (<\/span><span style=\"color: #9cdcfe;\">$cr<\/span><span style=\"color: #d4d4d4;\"> - <\/span><span style=\"color: #b5cea8;\">128<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$B<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #9cdcfe;\">$Yval<\/span><span style=\"color: #d4d4d4;\"> + <\/span><span style=\"color: #b5cea8;\">1.772<\/span><span style=\"color: #d4d4d4;\"> * (<\/span><span style=\"color: #9cdcfe;\">$cb<\/span><span style=\"color: #d4d4d4;\"> - <\/span><span style=\"color: #b5cea8;\">128<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$R<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">max<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #dcdcaa;\">min<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">255<\/span><span style=\"color: #d4d4d4;\">, (<\/span><span style=\"color: #569cd6;\">int<\/span><span style=\"color: #d4d4d4;\">) <\/span><span style=\"color: #dcdcaa;\">round<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$R<\/span><span style=\"color: #d4d4d4;\">)));<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$G<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">max<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #dcdcaa;\">min<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">255<\/span><span style=\"color: #d4d4d4;\">, (<\/span><span style=\"color: #569cd6;\">int<\/span><span style=\"color: #d4d4d4;\">) <\/span><span style=\"color: #dcdcaa;\">round<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$G<\/span><span style=\"color: #d4d4d4;\">)));<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$B<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">max<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">0<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #dcdcaa;\">min<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">255<\/span><span style=\"color: #d4d4d4;\">, (<\/span><span style=\"color: #569cd6;\">int<\/span><span style=\"color: #d4d4d4;\">) <\/span><span style=\"color: #dcdcaa;\">round<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$B<\/span><span style=\"color: #d4d4d4;\">)));<\/span><\/span>\n\n<span class=\"line\">                <span style=\"color: #9cdcfe;\">$color<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">imagecolorallocate<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$orig<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$R<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$G<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$B<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">                <span style=\"color: #dcdcaa;\">imagesetpixel<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$orig<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$x<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$y<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$color<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">        }<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #6a9955;\">\/\/ 2) Convert GDImage to a PNG blob in memory (lossless)<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #dcdcaa;\">ob_start<\/span><span style=\"color: #d4d4d4;\">();<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #dcdcaa;\">imagepng<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$orig<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$pngData<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">ob_get_clean<\/span><span style=\"color: #d4d4d4;\">();<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #6a9955;\">\/\/ 3) Create an Imagick object from the PNG blob<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$imagick<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #569cd6;\">new<\/span> <span style=\"color: #4ec9b0;\">\\Imagick<\/span><span style=\"color: #d4d4d4;\">();<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$imagick<\/span><span style=\"color: #d4d4d4;\">-&gt;<\/span><span style=\"color: #dcdcaa;\">readImageBlob<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$pngData<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #6a9955;\">\/\/ 4) Set desired JPEG parameters<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$imagick<\/span><span style=\"color: #d4d4d4;\">-&gt;<\/span><span style=\"color: #dcdcaa;\">setOption<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #ce9178;\">'jpeg:sampling-factor'<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #ce9178;\">'1x1'<\/span><span style=\"color: #d4d4d4;\">); <\/span><span style=\"color: #6a9955;\">\/\/ disable chroma subsampling<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$imagick<\/span><span style=\"color: #d4d4d4;\">-&gt;<\/span><span style=\"color: #dcdcaa;\">setImageCompressionQuality<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$quality<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$imagick<\/span><span style=\"color: #d4d4d4;\">-&gt;<\/span><span style=\"color: #dcdcaa;\">setImageCompression<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #4ec9b0;\">\\Imagick<\/span><span style=\"color: #d4d4d4;\">::COMPRESSION_JPEG);<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$imagick<\/span><span style=\"color: #d4d4d4;\">-&gt;<\/span><span style=\"color: #dcdcaa;\">setImageFormat<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #ce9178;\">'jpeg'<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #6a9955;\">\/\/ 5) Save the file<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$imagick<\/span><span style=\"color: #d4d4d4;\">-&gt;<\/span><span style=\"color: #dcdcaa;\">writeImage<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$dest<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n\n<span class=\"line\">        <span style=\"color: #6a9955;\">\/\/ 6) Cleanup<\/span><\/span>\n<span class=\"line\">        <span style=\"color: #9cdcfe;\">$imagick<\/span><span style=\"color: #d4d4d4;\">-&gt;<\/span><span style=\"color: #dcdcaa;\">destroy<\/span><span style=\"color: #d4d4d4;\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    }<\/span><\/span>\n\n<span class=\"line\">    <span style=\"color: #6a9955;\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     * Prevents instantiation.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\">     *\/<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #569cd6;\">private<\/span> <span style=\"color: #569cd6;\">function<\/span> <span style=\"color: #dcdcaa;\">__construct<\/span><span style=\"color: #d4d4d4;\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">}<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>When the static embed method is invoked, the code opens the image using the GD extension and extracts the Y (luminance) component\u2014 the only one involved in watermarking\u2014while leaving the chrominance channels Cb and Cr untouched, to ensure the watermark remains invisible to the human eye.<br \/>The Y matrix is then divided, row by row, into a grid of 8\u00d78 blocks. Each block is transformed into the frequency domain using Dct::forward, enabling the Watermarker class to embed the message bits by <strong>forcing the sign<\/strong> of 8 specifically chosen <strong>low-frequency<\/strong> coefficients.  <\/p>\n<p>Once the embedding is complete, ImageIO converts each block back into pixels using Dct::inverse, reconstructing a new, watermarked Y matrix. At this point, the class recalculates the RGB values by combining the modified luminance with the original chrominance components: for each pixel, it applies the inverse color space formulas according to the ITU-R BT.601 standard, ensuring that the results stay within the 0\u2013255 range. <\/p>\n<p>The complete bitmap is finally saved as a JPEG at the desired quality, using Imagick to disable chroma subsampling and maximize fidelity. The result is a file that is visually identical to the original but contains, within its DCT coefficients, an invisible yet resilient textual signature. <\/p>\n<p>The inverse process, handled by the extract method, performs the opposite operation: it reloads the image, isolates the luminance channel, divides it into blocks, computes the DCT of each block, and passes the sequence of coefficients to Watermarker::extract. This method reads the <strong>sign<\/strong> of the coefficients, applies majority voting across the repetitions of each bit, and reconstructs the original string up to the NUL termination character. <\/p>\n<p>All I\/O logic\u2014file opening, color conversion, and JPEG saving\u2014is confined within the ImageIO class, while Dct and Watermarker remain pure mathematical functions. This clear separation of responsibilities promotes code modularity, testability, and easy integration into any image processing pipeline. <\/p>\n<h2 class=\"wp-block-heading\">CLI test<\/h2>\n<h3 class=\"wp-block-heading\">\/embed.php<\/h3>\n<p>Embedding a watermark in an image<\/p>\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" style=\"font-size: .875rem; font-family: Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace; line-height: 1.25rem; --cbp-tab-width: 2; tab-size: var(--cbp-tab-width, 2);\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\">\n<pre class=\"shiki dark-plus\" style=\"background-color: #1e1e1e;\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #6a9955;\">#!\/usr\/bin\/env php<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">&lt;?php<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #6a9955;\">\/\/ Set memory limit to 1GB<\/span><\/span>\n<span class=\"line\"><span style=\"color: #dcdcaa;\">ini_set<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #ce9178;\">'memory_limit'<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #ce9178;\">'1024M'<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #c586c0;\">require<\/span> <span style=\"color: #569cd6;\">__DIR__<\/span> <span style=\"color: #d4d4d4;\">.<\/span> <span style=\"color: #ce9178;\">'\/vendor\/autoload.php'<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #569cd6;\">use<\/span><span style=\"color: #d4d4d4;\"> Renor\\Watermark\\<\/span><span style=\"color: #4ec9b0;\">ImageIO<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #6a9955;\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * This command-line script embeds a watermark (up to 10 characters)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * into a JPEG and saves the result. By default, it uses quality=90.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * Example usage:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *   php embed.php --src=original.jpg --out=watermarked.jpg --msg=\"HELLO\" --q=95<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * Or simply:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *   php embed.php --src=original.jpg --out=watermarked.jpg<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *   (defaults to msg=\"DEFAULT\" and quality=90)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *\/<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #9cdcfe;\">$options<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">getopt<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #ce9178;\">''<\/span><span style=\"color: #d4d4d4;\">, [<\/span><span style=\"color: #ce9178;\">'src:'<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #ce9178;\">'out:'<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #ce9178;\">'msg::'<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #ce9178;\">'q::'<\/span><span style=\"color: #d4d4d4;\">]);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9cdcfe;\">$src<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #9cdcfe;\">$options<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #ce9178;\">'src'<\/span><span style=\"color: #d4d4d4;\">] ?? <\/span><span style=\"color: #569cd6;\">null<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9cdcfe;\">$out<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #9cdcfe;\">$options<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #ce9178;\">'out'<\/span><span style=\"color: #d4d4d4;\">] ?? <\/span><span style=\"color: #569cd6;\">null<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9cdcfe;\">$msg<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #9cdcfe;\">$options<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #ce9178;\">'msg'<\/span><span style=\"color: #d4d4d4;\">] ?? <\/span><span style=\"color: #ce9178;\">'DEFAULT'<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9cdcfe;\">$q<\/span><span style=\"color: #d4d4d4;\">   = <\/span><span style=\"color: #dcdcaa;\">isset<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$options<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #ce9178;\">'q'<\/span><span style=\"color: #d4d4d4;\">]) ? (<\/span><span style=\"color: #569cd6;\">int<\/span><span style=\"color: #d4d4d4;\">) <\/span><span style=\"color: #9cdcfe;\">$options<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #ce9178;\">'q'<\/span><span style=\"color: #d4d4d4;\">] : <\/span><span style=\"color: #b5cea8;\">90<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #c586c0;\">if<\/span><span style=\"color: #d4d4d4;\"> (!<\/span><span style=\"color: #9cdcfe;\">$src<\/span><span style=\"color: #d4d4d4;\"> || !<\/span><span style=\"color: #9cdcfe;\">$out<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #dcdcaa;\">fwrite<\/span><span style=\"color: #d4d4d4;\">(STDERR, <\/span><span style=\"color: #ce9178;\">\"Usage: embed --src=INPUT.jpg --out=OUTPUT.jpg [--msg=STRING] [--q=90]<\/span><span style=\"color: #d7ba7d;\">\\n<\/span><span style=\"color: #ce9178;\">\"<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #c586c0;\">exit<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">}<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #c586c0;\">try<\/span><span style=\"color: #d4d4d4;\"> {<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #4ec9b0;\">ImageIO<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">embed<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$src<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$out<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$msg<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #9cdcfe;\">$q<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #dcdcaa;\">echo<\/span> <span style=\"color: #ce9178;\">\"Watermark <\/span><span style=\"color: #d7ba7d;\">\\\"<\/span><span style=\"color: #9cdcfe;\">$msg<\/span><span style=\"color: #d7ba7d;\">\\\"<\/span><span style=\"color: #ce9178;\"> embedded successfully into <\/span><span style=\"color: #9cdcfe;\">$out<\/span><span style=\"color: #ce9178;\"> at quality <\/span><span style=\"color: #9cdcfe;\">$q<\/span><span style=\"color: #d7ba7d;\">\\n<\/span><span style=\"color: #ce9178;\">\"<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">} <\/span><span style=\"color: #c586c0;\">catch<\/span><span style=\"color: #d4d4d4;\"> (\\<\/span><span style=\"color: #4ec9b0;\">Exception<\/span> <span style=\"color: #9cdcfe;\">$e<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #dcdcaa;\">fwrite<\/span><span style=\"color: #d4d4d4;\">(STDERR, <\/span><span style=\"color: #ce9178;\">\"Error: \"<\/span> <span style=\"color: #d4d4d4;\">.<\/span> <span style=\"color: #9cdcfe;\">$e<\/span><span style=\"color: #d4d4d4;\">-&gt;<\/span><span style=\"color: #dcdcaa;\">getMessage<\/span><span style=\"color: #d4d4d4;\">() <\/span><span style=\"color: #d4d4d4;\">.<\/span> <span style=\"color: #ce9178;\">\"<\/span><span style=\"color: #d7ba7d;\">\\n<\/span><span style=\"color: #ce9178;\">\"<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #c586c0;\">exit<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">}<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>In this CLI script (embed.php), we define the message to embed in the image via the &#8211;msg option and call the static method ImageIO::embed() from the ImageIO class. The script accepts the following parameters: <\/p>\n<p>&#8211;q (optional): the JPEG quality for saving (default: 90).<\/p>\n<p>&#8211;src: the path to the source JPEG image (e.g., original.jpg);<\/p>\n<p>&#8211;out: the path to the destination JPEG file that will contain the watermark;<\/p>\n<p>&#8211;msg (optional): the ASCII text to embed (max 10 characters);<\/p>\n\n<pre class=\"wp-block-code\"><code>php embed.php --src=original.jpg --out=watermarked.jpg --msg=\"RENOR\" --q=95<\/code><\/pre>\n<p>it will return:<\/p>\n\n<pre class=\"wp-block-code\"><code>Watermark \"RENOR\" embedded successfully into watermarked.jpg at quality 95<\/code><\/pre>\n<h2 class=\"wp-block-heading\">\/extract.php<\/h2>\n<p>From here, we extract the watermark text contained in the watermarked.jpg image just created by embed.php.<\/p>\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" style=\"font-size: .875rem; font-family: Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace; line-height: 1.25rem; --cbp-tab-width: 2; tab-size: var(--cbp-tab-width, 2);\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\">\n<pre class=\"shiki dark-plus\" style=\"background-color: #1e1e1e;\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #6a9955;\">#!\/usr\/bin\/env php<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">&lt;?php<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #6a9955;\">\/\/ Set memory limit to 1GB<\/span><\/span>\n<span class=\"line\"><span style=\"color: #dcdcaa;\">ini_set<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #ce9178;\">'memory_limit'<\/span><span style=\"color: #d4d4d4;\">, <\/span><span style=\"color: #ce9178;\">'1024M'<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #c586c0;\">require<\/span> <span style=\"color: #569cd6;\">__DIR__<\/span> <span style=\"color: #d4d4d4;\">.<\/span> <span style=\"color: #ce9178;\">'\/vendor\/autoload.php'<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #569cd6;\">use<\/span><span style=\"color: #d4d4d4;\"> Renor\\Watermark\\<\/span><span style=\"color: #4ec9b0;\">ImageIO<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #6a9955;\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * This command-line script extracts a watermark from a JPEG.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> * Usage:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *   php extract.php --src=watermarked.jpg<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6a9955;\"> *\/<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #9cdcfe;\">$options<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #dcdcaa;\">getopt<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #ce9178;\">''<\/span><span style=\"color: #d4d4d4;\">, [<\/span><span style=\"color: #ce9178;\">'src:'<\/span><span style=\"color: #d4d4d4;\">]);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9cdcfe;\">$src<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #9cdcfe;\">$options<\/span><span style=\"color: #d4d4d4;\">[<\/span><span style=\"color: #ce9178;\">'src'<\/span><span style=\"color: #d4d4d4;\">] ?? <\/span><span style=\"color: #569cd6;\">null<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #c586c0;\">if<\/span><span style=\"color: #d4d4d4;\"> (!<\/span><span style=\"color: #9cdcfe;\">$src<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #dcdcaa;\">fwrite<\/span><span style=\"color: #d4d4d4;\">(STDERR, <\/span><span style=\"color: #ce9178;\">\"Usage: extract --src=IMAGE.jpg<\/span><span style=\"color: #d7ba7d;\">\\n<\/span><span style=\"color: #ce9178;\">\"<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #c586c0;\">exit<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">}<\/span><\/span>\n\n<span class=\"line\"><span style=\"color: #c586c0;\">try<\/span><span style=\"color: #d4d4d4;\"> {<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #9cdcfe;\">$msg<\/span><span style=\"color: #d4d4d4;\"> = <\/span><span style=\"color: #4ec9b0;\">ImageIO<\/span><span style=\"color: #d4d4d4;\">::<\/span><span style=\"color: #dcdcaa;\">extract<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #9cdcfe;\">$src<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #dcdcaa;\">echo<\/span> <span style=\"color: #ce9178;\">\"Recovered message: <\/span><span style=\"color: #d7ba7d;\">\\\"<\/span><span style=\"color: #9cdcfe;\">$msg<\/span><span style=\"color: #d7ba7d;\">\\\"\\n<\/span><span style=\"color: #ce9178;\">\"<\/span><span style=\"color: #d4d4d4;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">} <\/span><span style=\"color: #c586c0;\">catch<\/span><span style=\"color: #d4d4d4;\"> (\\<\/span><span style=\"color: #4ec9b0;\">Exception<\/span> <span style=\"color: #9cdcfe;\">$e<\/span><span style=\"color: #d4d4d4;\">) {<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #dcdcaa;\">fwrite<\/span><span style=\"color: #d4d4d4;\">(STDERR, <\/span><span style=\"color: #ce9178;\">\"Error: \"<\/span> <span style=\"color: #d4d4d4;\">.<\/span> <span style=\"color: #9cdcfe;\">$e<\/span><span style=\"color: #d4d4d4;\">-&gt;<\/span><span style=\"color: #dcdcaa;\">getMessage<\/span><span style=\"color: #d4d4d4;\">() <\/span><span style=\"color: #d4d4d4;\">.<\/span> <span style=\"color: #ce9178;\">\"<\/span><span style=\"color: #d7ba7d;\">\\n<\/span><span style=\"color: #ce9178;\">\"<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\">    <span style=\"color: #c586c0;\">exit<\/span><span style=\"color: #d4d4d4;\">(<\/span><span style=\"color: #b5cea8;\">1<\/span><span style=\"color: #d4d4d4;\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #d4d4d4;\">}<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>The extract.php script completes the invisible watermark usage cycle by allowing the extraction of the previously embedded message. It is a simple command-line script which, given a watermarked JPEG file, reads the hidden content by decoding the sign of specific modified DCT coefficients.<br \/>The message\u2014robustly recovered even after medium-to-high quality JPEG compressions\u2014is reconstructed using majority voting on the repeated bits.<br \/>Just run the command with the &#8211;src option to specify the image to analyze, and the script will return the originally embedded string in the terminal.   <\/p>\n<p>We can run the command:<\/p>\n\n<pre class=\"wp-block-code\"><code>php extract.php --src=watermarked.jpg  <\/code><\/pre>\n<p>we&#8217;ll get:<\/p>\n\n<pre class=\"wp-block-code\"><code>Recovered message: \"RENOR\"<\/code><\/pre>\n<p>It is also worth analyzing photographs:<\/p>\n\n<figure class=\"wp-block-image size-large\"><img wpfc-lazyload-disable=\"true\" decoding=\"async\" src=\"https:\/\/renor.it\/wp-content\/uploads\/2025\/05\/test-1024x342.webp\" alt=\"\" class=\"wp-image-360\"\/><\/figure>\n<p>On the left, the original image; on the right, the watermarked one.<\/p>\n<p>We can observe that, as thoroughly described, there are indeed no elements visible to the naked eye that can be traced back to the application of a watermark, which nevertheless remains fully decodable using the extract script. <\/p>\n<p>Clearly, the project is purely demonstrative, and using it at an enterprise level or in production environments would require further refinement.<\/p>\n\n<p><strong>[starbox] <\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Protect your images by modifying the coefficients, without damaging them Publishing photographs online has become essential for photographers, e-commerce sites, and bloggers, but according to the latest studies on image theft, over 70% of visual content is reshared without credit or authorization. A visible watermark certainly protects the author, but to make it truly effective [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":920,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_writerflow_disable_suggestions":false,"footnotes":""},"categories":[1977],"tags":[1421,1422,1423,1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1391,1436,1437,1438],"class_list":["post-670","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-sviluppo-software-programmazione","tag-copyright-en","tag-dct-en","tag-digital-pgotography","tag-digital-sign","tag-discrete-cosine-transform","tag-gd-en","tag-image-security","tag-images-protection","tag-imagick-en","tag-invisible-metadata","tag-invisible-watermark","tag-jpeg-en","tag-jpeg-compression","tag-open-source-en-2","tag-photography-blog","tag-php-en","tag-php-script","tag-robust-watermarking","tag-steganography"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.4 (Yoast SEO v27.6) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Invisible Watermark in JPEG with PHP 8 | RENOR &amp; Partners S.r.l.<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/renor.it\/en\/blog\/sviluppo-software-programmazione\/invisible-watermark-in-jpeg-with-php-8\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Invisible Watermark in JPEG with PHP 8\" \/>\n<meta property=\"og:description\" content=\"Protect your images by modifying the coefficients, without damaging them Publishing photographs online has become essential for photographers, e-commerce sites, and bloggers, but according to the latest studies on image theft, over 70% of visual content is reshared without credit or authorization. A visible watermark certainly protects the author, but to make it truly effective [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/renor.it\/en\/blog\/sviluppo-software-programmazione\/invisible-watermark-in-jpeg-with-php-8\/\" \/>\n<meta property=\"og:site_name\" content=\"RENOR &amp; Partners S.r.l.\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/renorsrl\" \/>\n<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/simone.renzi.3954\/\" \/>\n<meta property=\"article:published_time\" content=\"2025-05-11T02:27:30+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-12-20T14:53:53+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/renor.it\/wp-content\/uploads\/2025\/05\/invisible-watermark.webp\" \/>\n\t<meta property=\"og:image:width\" content=\"1536\" \/>\n\t<meta property=\"og:image:height\" content=\"1024\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/webp\" \/>\n<meta name=\"author\" content=\"Simone Renzi\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Simone Renzi\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"23 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/blog\\\/sviluppo-software-programmazione\\\/invisible-watermark-in-jpeg-with-php-8\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/blog\\\/sviluppo-software-programmazione\\\/invisible-watermark-in-jpeg-with-php-8\\\/\"},\"author\":{\"name\":\"Simone Renzi\",\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/#\\\/schema\\\/person\\\/21343be04e5983a87f3a9a6182cf8795\"},\"headline\":\"Invisible Watermark in JPEG with PHP 8\",\"datePublished\":\"2025-05-11T02:27:30+00:00\",\"dateModified\":\"2025-12-20T14:53:53+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/blog\\\/sviluppo-software-programmazione\\\/invisible-watermark-in-jpeg-with-php-8\\\/\"},\"wordCount\":2701,\"publisher\":{\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/blog\\\/sviluppo-software-programmazione\\\/invisible-watermark-in-jpeg-with-php-8\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/renor.it\\\/wp-content\\\/uploads\\\/2025\\\/05\\\/invisible-watermark.webp\",\"keywords\":[\"copyright\",\"dct\",\"digital pgotography\",\"digital sign\",\"discrete cosine transform\",\"gd\",\"image security\",\"images protection\",\"imagick\",\"invisible metadata\",\"invisible watermark\",\"jpeg\",\"jpeg compression\",\"open source\",\"photography blog\",\"php\",\"php script\",\"robust watermarking\",\"steganography\"],\"articleSection\":[\"Sviluppo Software &amp; Programmazione\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/blog\\\/sviluppo-software-programmazione\\\/invisible-watermark-in-jpeg-with-php-8\\\/\",\"url\":\"https:\\\/\\\/renor.it\\\/en\\\/blog\\\/sviluppo-software-programmazione\\\/invisible-watermark-in-jpeg-with-php-8\\\/\",\"name\":\"Invisible Watermark in JPEG with PHP 8 | RENOR &amp; Partners S.r.l.\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/blog\\\/sviluppo-software-programmazione\\\/invisible-watermark-in-jpeg-with-php-8\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/blog\\\/sviluppo-software-programmazione\\\/invisible-watermark-in-jpeg-with-php-8\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/renor.it\\\/wp-content\\\/uploads\\\/2025\\\/05\\\/invisible-watermark.webp\",\"datePublished\":\"2025-05-11T02:27:30+00:00\",\"dateModified\":\"2025-12-20T14:53:53+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/blog\\\/sviluppo-software-programmazione\\\/invisible-watermark-in-jpeg-with-php-8\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/renor.it\\\/en\\\/blog\\\/sviluppo-software-programmazione\\\/invisible-watermark-in-jpeg-with-php-8\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/blog\\\/sviluppo-software-programmazione\\\/invisible-watermark-in-jpeg-with-php-8\\\/#primaryimage\",\"url\":\"https:\\\/\\\/renor.it\\\/wp-content\\\/uploads\\\/2025\\\/05\\\/invisible-watermark.webp\",\"contentUrl\":\"https:\\\/\\\/renor.it\\\/wp-content\\\/uploads\\\/2025\\\/05\\\/invisible-watermark.webp\",\"width\":1536,\"height\":1024,\"caption\":\"Esempio grafico del progetto open-source per inserire watermark invisibili all\u2019interno dei coefficienti DCT di immagini JPEG, utilizzando PHP e una libreria personalizzata senza dipendenze esterne.\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/blog\\\/sviluppo-software-programmazione\\\/invisible-watermark-in-jpeg-with-php-8\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/renor.it\\\/en\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Blog\",\"item\":\"https:\\\/\\\/renor.it\\\/en\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Software Development &amp; Programming\",\"item\":\"https:\\\/\\\/renor.it\\\/en\\\/blog\\\/software-development-programming\\\/\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Invisible Watermark in JPEG with PHP 8\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/#website\",\"url\":\"https:\\\/\\\/renor.it\\\/en\\\/\",\"name\":\"RENOR & Partners S.r.l.\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/#organization\"},\"alternateName\":\"RENOR & Partners S.r.l.\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/renor.it\\\/en\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/#organization\",\"name\":\"RENOR & Partners S.r.l.\",\"url\":\"https:\\\/\\\/renor.it\\\/en\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/renor.it\\\/wp-content\\\/uploads\\\/2025\\\/12\\\/logo-new-1.webp\",\"contentUrl\":\"https:\\\/\\\/renor.it\\\/wp-content\\\/uploads\\\/2025\\\/12\\\/logo-new-1.webp\",\"width\":432,\"height\":146,\"caption\":\"RENOR & Partners S.r.l.\"},\"image\":{\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/renorsrl\",\"https:\\\/\\\/www.instagram.com\\\/renorpartners\\\/\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/renor-partners\\\/posts\\\/?feedView=all\"],\"description\":\"RENOR & Partners Srl \u00e8 una societ\u00e0 di consulenza tecnologica e ingegneristica specializzata in sviluppo software, cloud computing, integrazione di sistemi, intelligenza artificiale applicata e progettazione elettronica. L\u2019azienda supporta imprese e pubbliche amministrazioni nella realizzazione di soluzioni digitali affidabili, scalabili e orientate all\u2019efficienza, con un approccio pragmatico basato su competenze tecniche, progettazione su misura e innovazione concreta.\",\"email\":\"info@renor.it\",\"telephone\":\"3791489430\",\"legalName\":\"RENOR AND PARTNERS S.r.l.\",\"foundingDate\":\"2022-06-21\",\"vatID\":\"16768411007\",\"taxID\":\"16768411007\",\"numberOfEmployees\":{\"@type\":\"QuantitativeValue\",\"minValue\":\"1\",\"maxValue\":\"10\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/renor.it\\\/en\\\/#\\\/schema\\\/person\\\/21343be04e5983a87f3a9a6182cf8795\",\"name\":\"Simone Renzi\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/54f81b51be6bda6d63a06a1cd6563d9b0d5778d7af4f0bda4e246fc3e5737e2e?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/54f81b51be6bda6d63a06a1cd6563d9b0d5778d7af4f0bda4e246fc3e5737e2e?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/54f81b51be6bda6d63a06a1cd6563d9b0d5778d7af4f0bda4e246fc3e5737e2e?s=96&d=mm&r=g\",\"caption\":\"Simone Renzi\"},\"description\":\"Senior full-stack web engineer with over 20 years of experience in cloud architectures, AI, and SaaS solutions; member of Mensa Italia. Creator of platforms such as HR24.ai and Paghe.ai, he oversaw the web development of FNS, a neural network simulator cited in Scientific Reports (Nature Portfolio), and has collaborated on research projects with INFN \u2013 Laboratori Nazionali di Frascati, Universit\u00e0 di Roma \u201cTor Vergata\u201d, Universidad Complutense, Universidad Polit\u00e9cnica and Centro de Tecnolog\u00eda Biom\u00e9dica in Madrid. A classical pianist, he combines musical creativity and technological rigor in every project.\",\"sameAs\":[\"https:\\\/\\\/renor.it\",\"https:\\\/\\\/www.facebook.com\\\/simone.renzi.3954\\\/\",\"https:\\\/\\\/www.linkedin.com\\\/in\\\/simone-renzi\"],\"url\":\"https:\\\/\\\/renor.it\\\/en\\\/author\\\/thesimon\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Invisible Watermark in JPEG with PHP 8 | RENOR &amp; Partners S.r.l.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/renor.it\/en\/blog\/sviluppo-software-programmazione\/invisible-watermark-in-jpeg-with-php-8\/","og_locale":"en_US","og_type":"article","og_title":"Invisible Watermark in JPEG with PHP 8","og_description":"Protect your images by modifying the coefficients, without damaging them Publishing photographs online has become essential for photographers, e-commerce sites, and bloggers, but according to the latest studies on image theft, over 70% of visual content is reshared without credit or authorization. A visible watermark certainly protects the author, but to make it truly effective [&hellip;]","og_url":"https:\/\/renor.it\/en\/blog\/sviluppo-software-programmazione\/invisible-watermark-in-jpeg-with-php-8\/","og_site_name":"RENOR &amp; Partners S.r.l.","article_publisher":"https:\/\/www.facebook.com\/renorsrl","article_author":"https:\/\/www.facebook.com\/simone.renzi.3954\/","article_published_time":"2025-05-11T02:27:30+00:00","article_modified_time":"2025-12-20T14:53:53+00:00","og_image":[{"width":1536,"height":1024,"url":"https:\/\/renor.it\/wp-content\/uploads\/2025\/05\/invisible-watermark.webp","type":"image\/webp"}],"author":"Simone Renzi","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Simone Renzi","Est. reading time":"23 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/renor.it\/en\/blog\/sviluppo-software-programmazione\/invisible-watermark-in-jpeg-with-php-8\/#article","isPartOf":{"@id":"https:\/\/renor.it\/en\/blog\/sviluppo-software-programmazione\/invisible-watermark-in-jpeg-with-php-8\/"},"author":{"name":"Simone Renzi","@id":"https:\/\/renor.it\/en\/#\/schema\/person\/21343be04e5983a87f3a9a6182cf8795"},"headline":"Invisible Watermark in JPEG with PHP 8","datePublished":"2025-05-11T02:27:30+00:00","dateModified":"2025-12-20T14:53:53+00:00","mainEntityOfPage":{"@id":"https:\/\/renor.it\/en\/blog\/sviluppo-software-programmazione\/invisible-watermark-in-jpeg-with-php-8\/"},"wordCount":2701,"publisher":{"@id":"https:\/\/renor.it\/en\/#organization"},"image":{"@id":"https:\/\/renor.it\/en\/blog\/sviluppo-software-programmazione\/invisible-watermark-in-jpeg-with-php-8\/#primaryimage"},"thumbnailUrl":"https:\/\/renor.it\/wp-content\/uploads\/2025\/05\/invisible-watermark.webp","keywords":["copyright","dct","digital pgotography","digital sign","discrete cosine transform","gd","image security","images protection","imagick","invisible metadata","invisible watermark","jpeg","jpeg compression","open source","photography blog","php","php script","robust watermarking","steganography"],"articleSection":["Sviluppo Software &amp; Programmazione"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/renor.it\/en\/blog\/sviluppo-software-programmazione\/invisible-watermark-in-jpeg-with-php-8\/","url":"https:\/\/renor.it\/en\/blog\/sviluppo-software-programmazione\/invisible-watermark-in-jpeg-with-php-8\/","name":"Invisible Watermark in JPEG with PHP 8 | RENOR &amp; Partners S.r.l.","isPartOf":{"@id":"https:\/\/renor.it\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/renor.it\/en\/blog\/sviluppo-software-programmazione\/invisible-watermark-in-jpeg-with-php-8\/#primaryimage"},"image":{"@id":"https:\/\/renor.it\/en\/blog\/sviluppo-software-programmazione\/invisible-watermark-in-jpeg-with-php-8\/#primaryimage"},"thumbnailUrl":"https:\/\/renor.it\/wp-content\/uploads\/2025\/05\/invisible-watermark.webp","datePublished":"2025-05-11T02:27:30+00:00","dateModified":"2025-12-20T14:53:53+00:00","breadcrumb":{"@id":"https:\/\/renor.it\/en\/blog\/sviluppo-software-programmazione\/invisible-watermark-in-jpeg-with-php-8\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/renor.it\/en\/blog\/sviluppo-software-programmazione\/invisible-watermark-in-jpeg-with-php-8\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/renor.it\/en\/blog\/sviluppo-software-programmazione\/invisible-watermark-in-jpeg-with-php-8\/#primaryimage","url":"https:\/\/renor.it\/wp-content\/uploads\/2025\/05\/invisible-watermark.webp","contentUrl":"https:\/\/renor.it\/wp-content\/uploads\/2025\/05\/invisible-watermark.webp","width":1536,"height":1024,"caption":"Esempio grafico del progetto open-source per inserire watermark invisibili all\u2019interno dei coefficienti DCT di immagini JPEG, utilizzando PHP e una libreria personalizzata senza dipendenze esterne."},{"@type":"BreadcrumbList","@id":"https:\/\/renor.it\/en\/blog\/sviluppo-software-programmazione\/invisible-watermark-in-jpeg-with-php-8\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/renor.it\/en\/"},{"@type":"ListItem","position":2,"name":"Blog","item":"https:\/\/renor.it\/en\/blog\/"},{"@type":"ListItem","position":3,"name":"Software Development &amp; Programming","item":"https:\/\/renor.it\/en\/blog\/software-development-programming\/"},{"@type":"ListItem","position":4,"name":"Invisible Watermark in JPEG with PHP 8"}]},{"@type":"WebSite","@id":"https:\/\/renor.it\/en\/#website","url":"https:\/\/renor.it\/en\/","name":"RENOR & Partners S.r.l.","description":"","publisher":{"@id":"https:\/\/renor.it\/en\/#organization"},"alternateName":"RENOR & Partners S.r.l.","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/renor.it\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/renor.it\/en\/#organization","name":"RENOR & Partners S.r.l.","url":"https:\/\/renor.it\/en\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/renor.it\/en\/#\/schema\/logo\/image\/","url":"https:\/\/renor.it\/wp-content\/uploads\/2025\/12\/logo-new-1.webp","contentUrl":"https:\/\/renor.it\/wp-content\/uploads\/2025\/12\/logo-new-1.webp","width":432,"height":146,"caption":"RENOR & Partners S.r.l."},"image":{"@id":"https:\/\/renor.it\/en\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/renorsrl","https:\/\/www.instagram.com\/renorpartners\/","https:\/\/www.linkedin.com\/company\/renor-partners\/posts\/?feedView=all"],"description":"RENOR & Partners Srl \u00e8 una societ\u00e0 di consulenza tecnologica e ingegneristica specializzata in sviluppo software, cloud computing, integrazione di sistemi, intelligenza artificiale applicata e progettazione elettronica. L\u2019azienda supporta imprese e pubbliche amministrazioni nella realizzazione di soluzioni digitali affidabili, scalabili e orientate all\u2019efficienza, con un approccio pragmatico basato su competenze tecniche, progettazione su misura e innovazione concreta.","email":"info@renor.it","telephone":"3791489430","legalName":"RENOR AND PARTNERS S.r.l.","foundingDate":"2022-06-21","vatID":"16768411007","taxID":"16768411007","numberOfEmployees":{"@type":"QuantitativeValue","minValue":"1","maxValue":"10"}},{"@type":"Person","@id":"https:\/\/renor.it\/en\/#\/schema\/person\/21343be04e5983a87f3a9a6182cf8795","name":"Simone Renzi","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/54f81b51be6bda6d63a06a1cd6563d9b0d5778d7af4f0bda4e246fc3e5737e2e?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/54f81b51be6bda6d63a06a1cd6563d9b0d5778d7af4f0bda4e246fc3e5737e2e?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/54f81b51be6bda6d63a06a1cd6563d9b0d5778d7af4f0bda4e246fc3e5737e2e?s=96&d=mm&r=g","caption":"Simone Renzi"},"description":"Senior full-stack web engineer with over 20 years of experience in cloud architectures, AI, and SaaS solutions; member of Mensa Italia. Creator of platforms such as HR24.ai and Paghe.ai, he oversaw the web development of FNS, a neural network simulator cited in Scientific Reports (Nature Portfolio), and has collaborated on research projects with INFN \u2013 Laboratori Nazionali di Frascati, Universit\u00e0 di Roma \u201cTor Vergata\u201d, Universidad Complutense, Universidad Polit\u00e9cnica and Centro de Tecnolog\u00eda Biom\u00e9dica in Madrid. A classical pianist, he combines musical creativity and technological rigor in every project.","sameAs":["https:\/\/renor.it","https:\/\/www.facebook.com\/simone.renzi.3954\/","https:\/\/www.linkedin.com\/in\/simone-renzi"],"url":"https:\/\/renor.it\/en\/author\/thesimon\/"}]}},"_links":{"self":[{"href":"https:\/\/renor.it\/en\/wp-json\/wp\/v2\/posts\/670","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/renor.it\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/renor.it\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/renor.it\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/renor.it\/en\/wp-json\/wp\/v2\/comments?post=670"}],"version-history":[{"count":0,"href":"https:\/\/renor.it\/en\/wp-json\/wp\/v2\/posts\/670\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/renor.it\/en\/wp-json\/wp\/v2\/media\/920"}],"wp:attachment":[{"href":"https:\/\/renor.it\/en\/wp-json\/wp\/v2\/media?parent=670"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/renor.it\/en\/wp-json\/wp\/v2\/categories?post=670"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/renor.it\/en\/wp-json\/wp\/v2\/tags?post=670"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}