| @@ -38,8 +38,31 @@ | ||
| 38 | 38 | * |
| 39 | 39 | * @return string The `<img>` tag, or '' when the value is empty or generation fails. |
| 40 | 40 | */ |
| 41 | 41 | public static function barcode_img( string $type, string $value, int $height = 40 ): string { |
| 42 | + $png = self::barcode_png( $type, $value, $height ); | |
| 43 | + if ( '' === $png ) { | |
| 44 | + return ''; | |
| 45 | + } | |
| 46 | + | |
| 47 | + // bwip-js renders the human-readable value under the bars in the | |
| 48 | + // client-side previews; mirror it so the PDF matches on-screen. | |
| 49 | + return self::img_from_png( $png ) . self::barcode_text( trim( $value ) ); | |
| 50 | + } | |
| 51 | + | |
| 52 | + /** | |
| 53 | + * Rasterize a barcode to opaque PNG bytes. | |
| 54 | + * | |
| 55 | + * The receipt raster emitter composites these straight onto its canvas, so it | |
| 56 | + * needs the bytes rather than the `<img>` wrapper the HTML/PDF path uses. | |
| 57 | + * | |
| 58 | + * @param string $type The barcode symbology (e.g. code128, ean13). | |
| 59 | + * @param string $value The barcode value. | |
| 60 | + * @param int $height The barcode height in pixels. | |
| 61 | + * | |
| 62 | + * @return string The PNG bytes, or '' when the value is empty or generation fails. | |
| 63 | + */ | |
| 64 | + public static function barcode_png( string $type, string $value, int $height = 40 ): string { | |
| 42 | 65 | $text = trim( $value ); |
| 43 | 66 | if ( '' === $text ) { |
| 44 | 67 | return ''; |
| 45 | 68 | } |
| @@ -56,15 +79,13 @@ | ||
| 56 | 79 | } |
| 57 | 80 | |
| 58 | 81 | // Clamp the height so a malformed template dimension cannot |
| 59 | 82 | // allocate a huge raster. |
| 60 | - return $generator->getBarcode( $text, self::barcode_constant( $type ), 2, max( 8, min( 600, $height ) ) ); | |
| 83 | + return $generator->getBarcode( $text, Barcode_Symbology::picqer_type( $type ), 2, max( 8, min( 600, $height ) ) ); | |
| 61 | 84 | } |
| 62 | 85 | ); |
| 63 | 86 | |
| 64 | - // bwip-js renders the human-readable value under the bars in the | |
| 65 | - // client-side previews; mirror it so the PDF matches on-screen. | |
| 66 | - return self::img_from_png( $png ) . self::barcode_text( $text ); | |
| 87 | + return self::flatten_png( $png ); | |
| 67 | 88 | } catch ( Throwable $error ) { |
| 68 | 89 | return ''; |
| 69 | 90 | } |
| 70 | 91 | } |
| @@ -90,8 +111,22 @@ | ||
| 90 | 111 | * |
| 91 | 112 | * @return string The `<img>` tag, or '' when the value is empty or generation fails. |
| 92 | 113 | */ |
| 93 | 114 | public static function qrcode_img( string $value, int $size = 4 ): string { |
| 115 | + $png = self::qrcode_png( $value, $size ); | |
| 116 | + | |
| 117 | + return '' === $png ? '' : self::img_from_png( $png ); | |
| 118 | + } | |
| 119 | + | |
| 120 | + /** | |
| 121 | + * Rasterize a QR code to opaque PNG bytes. | |
| 122 | + * | |
| 123 | + * @param string $value The QR code value. | |
| 124 | + * @param int $size The QR module scale (pixels per module). | |
| 125 | + * | |
| 126 | + * @return string The PNG bytes, or '' when the value is empty or generation fails. | |
| 127 | + */ | |
| 128 | + public static function qrcode_png( string $value, int $size = 4 ): string { | |
| 94 | 129 | $text = trim( $value ); |
| 95 | 130 | if ( '' === $text ) { |
| 96 | 131 | return ''; |
| 97 | 132 | } |
| @@ -112,9 +147,9 @@ | ||
| 112 | 147 | return ( new QRCode( $options ) )->render( $text ); |
| 113 | 148 | } |
| 114 | 149 | ); |
| 115 | 150 | |
| 116 | - return self::img_from_png( $png ); | |
| 151 | + return self::flatten_png( $png ); | |
| 117 | 152 | } catch ( Throwable $error ) { |
| 118 | 153 | return ''; |
| 119 | 154 | } |
| 120 | 155 | } |
| @@ -188,9 +223,9 @@ | ||
| 188 | 223 | $raw_type = '' !== $raw_type ? $raw_type : 'qr'; |
| 189 | 224 | } |
| 190 | 225 | $type = strtolower( trim( $raw_type ) ); |
| 191 | 226 | |
| 192 | - if ( 'qr' === $type || 'qrcode' === $type ) { | |
| 227 | + if ( Barcode_Symbology::is_qr( $type ) ) { | |
| 193 | 228 | $size = (int) self::attr( $attrs, 'size' ); |
| 194 | 229 | |
| 195 | 230 | return self::qrcode_img( $value, $size > 0 ? $size : 4 ); |
| 196 | 231 | } |
| @@ -207,8 +242,10 @@ | ||
| 207 | 242 | * |
| 208 | 243 | * @return string The `<img>` tag. |
| 209 | 244 | */ |
| 210 | 245 | private static function img_from_png( string $png ): string { |
| 246 | + // Callers hand over already-flattened bytes; flatten_png() is idempotent, so | |
| 247 | + // the second pass is a no-op that keeps this safe for any future caller. | |
| 211 | 248 | return '<img src="data:image/png;base64,' . base64_encode( self::flatten_png( $png ) ) . '" ' |
| 212 | 249 | . 'style="max-width: 100%; height: auto" alt="" />'; |
| 213 | 250 | } |
| 214 | 251 | |
| @@ -267,33 +304,8 @@ | ||
| 267 | 304 | return ( $m[2] ?? '' ) . ( $m[3] ?? '' ) . ( $m[4] ?? '' ); |
| 268 | 305 | } |
| 269 | 306 | |
| 270 | 307 | return ''; |
| 271 | - } | |
| 272 | - | |
| 273 | - /** | |
| 274 | - * Map a barcode type string to a picqer generator constant. | |
| 275 | - * | |
| 276 | - * @param string $type The barcode type string. | |
| 277 | - * | |
| 278 | - * @return string The picqer TYPE_* constant value. | |
| 279 | - */ | |
| 280 | - private static function barcode_constant( string $type ): string { | |
| 281 | - $map = array( | |
| 282 | - 'code128' => BarcodeGeneratorPNG::TYPE_CODE_128, | |
| 283 | - 'code39' => BarcodeGeneratorPNG::TYPE_CODE_39, | |
| 284 | - 'code93' => BarcodeGeneratorPNG::TYPE_CODE_93, | |
| 285 | - 'ean13' => BarcodeGeneratorPNG::TYPE_EAN_13, | |
| 286 | - 'ean8' => BarcodeGeneratorPNG::TYPE_EAN_8, | |
| 287 | - 'upca' => BarcodeGeneratorPNG::TYPE_UPC_A, | |
| 288 | - 'upce' => BarcodeGeneratorPNG::TYPE_UPC_E, | |
| 289 | - 'codabar' => BarcodeGeneratorPNG::TYPE_CODABAR, | |
| 290 | - 'itf' => BarcodeGeneratorPNG::TYPE_INTERLEAVED_2_5, | |
| 291 | - ); | |
| 292 | - | |
| 293 | - $normalized = strtolower( trim( $type ) ); | |
| 294 | - | |
| 295 | - return isset( $map[ $normalized ] ) ? $map[ $normalized ] : BarcodeGeneratorPNG::TYPE_CODE_128; | |
| 296 | 308 | } |
| 297 | 309 | |
| 298 | 310 | /** |
| 299 | 311 | * Run a callable with E_DEPRECATED notices from the vendored libraries silenced. |