├── preview.jpg ├── BMP2JPG ├── 02 - plsql function.sql ├── example.sql └── 01 - bmp2jpg java.sql ├── LICENSE ├── apexplugin.json ├── README.md ├── plugin ├── item_type_plugin_eu_zttech_qr_code.sql └── olderversions │ └── item_type_plugin_eu_zttech_qr_code_func_api.sql └── package ├── ZT_QR.pks └── ZT_QR.pkb /preview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zorantica/plsql-qr-code/HEAD/preview.jpg -------------------------------------------------------------------------------- /BMP2JPG/02 - plsql function.sql: -------------------------------------------------------------------------------- 1 | CREATE OR REPLACE FUNCTION f_bmp2jpg(p_bmp_image blob) RETURN blob AS 2 | language java name 'Bmp2JPG.convert2JPG(oracle.sql.BLOB) return oracle.sql.BLOB' 3 | ; 4 | -------------------------------------------------------------------------------- /BMP2JPG/example.sql: -------------------------------------------------------------------------------- 1 | DECLARE 2 | lbQR blob; 3 | 4 | BEGIN 5 | lbQR := f_bmp2jpg( 6 | ZT_QR.F_QR_AS_BMP( 7 | p_data => 'HTTP://WWW.ZT-TECH.EU', 8 | p_error_correction => 'M') 9 | ); 10 | 11 | ZT_QR.p_save_file(lbQR, 'qr.jpg', 'E_SHARED'); 12 | END; 13 | 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 - Zoran Tica 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /apexplugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "QRCode", 3 | "version" : "1.0.0", 4 | "description" : "QRCode is an item type plugin that provides functionality to show QR Code for desired input value. QR Code can be rendered as HTML table or BMP image.", 5 | "keywords" : ["qr code"], 6 | "homepage" : "https://github.com/zorantica/plsql-qr-code", 7 | "bugs" : { 8 | "url" : "https://github.com/zorantica/plsql-qr-code/issues", 9 | "email" : "zoran.tica@gmail.com" 10 | }, 11 | "license" : "MIT", 12 | "author" : { 13 | "name" : "Zoran Tica", 14 | "email" : "zoran.tica@gmail.com", 15 | "url" : "http://www.zt-tech.eu", 16 | "twitter" : "zoran_tica" 17 | }, 18 | "repository" : { 19 | "type" : "git", 20 | "url" : "https://github.com/zorantica/plsql-qr-code.git" 21 | }, 22 | "oracle" : { 23 | "versions" : ["11.2.0.1", "12.1.0.1", "12.2.0.1", "18.0.0.0.0 >=" ], 24 | "apex" : { 25 | "versions" : ["5.0.0 >="], 26 | "plugin" : { 27 | "internalName" : "EU.ZTTECH.QRCODE", 28 | "type" : "item", 29 | "demo" : "https://apex.oracle.com/pls/apex/f?p=zttechdemo", 30 | "previewImage" : "https://raw.githubusercontent.com/zorantica/plsql-qr-code/master/preview.jpg" 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /BMP2JPG/01 - bmp2jpg java.sql: -------------------------------------------------------------------------------- 1 | create or replace and compile java source named Bmp2Jpeg 2 | as 3 | 4 | import oracle.sql.BLOB; 5 | import oracle.sql.*; 6 | import oracle.jdbc.driver.*; 7 | import java.sql.*; 8 | import javax.imageio.ImageIO; 9 | import java.awt.image.BufferedImage; 10 | import java.io.ByteArrayOutputStream; 11 | import java.io.File; 12 | import java.io.FileOutputStream; 13 | import java.io.OutputStream; 14 | import java.io.*; 15 | import java.util.*; 16 | import javax.imageio.ImageIO; 17 | import java.awt.image.BufferedImage; 18 | import java.sql.Blob; 19 | 20 | public class Bmp2JPG { 21 | 22 | static OracleDriver ora = new OracleDriver(); 23 | static Connection conn; 24 | static ByteArrayOutputStream out; 25 | static { 26 | try { 27 | conn = ora.defaultConnection(); 28 | } catch (Exception ex) {} 29 | } 30 | public static ByteArrayOutputStream TO_JPG(java.sql.Blob blob) throws Exception { 31 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 32 | BufferedImage image = ImageIO.read(blob.getBinaryStream()); 33 | ImageIO.write(image, "jpeg", outputStream); 34 | 35 | 36 | return outputStream; 37 | } 38 | 39 | public static oracle.sql.BLOB convert2JPG(oracle.sql.BLOB value) throws Exception { 40 | 41 | if (conn == null) conn = ora.defaultConnection(); 42 | BLOB retBlob = BLOB.createTemporary(conn, true, oracle.sql.BLOB.DURATION_SESSION); 43 | 44 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 45 | out = Bmp2JPG.TO_JPG(value); 46 | 47 | try { 48 | java.io.OutputStream outStr = retBlob.setBinaryStream(0); 49 | outStr.write(out.toByteArray()); 50 | outStr.flush(); 51 | } finally { 52 | out.close(); 53 | } 54 | return retBlob; 55 | } 56 | } 57 | 58 | 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Oracle PL/SQL Package and APEX plugin for QR Code Generation 2 | QR Codes Generator package provides functionality to quickly and efficiently generate QR Codes (module 2) directly from Oracle database. 3 | 4 | It requires no additional resources and it is developed in pure PL/SQL. 5 | 6 | Item-type APEX plugin uses PL/SQL package for calculations and graphical implementation of QR code and simplifies QR code usage in APEX applications. 7 | 8 | ## Changelog 9 | - 1.0 - Initial Release 10 | - 1.1 - Added APEX plugin 11 | - 1.2 - UTF-8 support 12 | - 1.3 - "_" and "%" BUG resolved (Franz.Apeltauer@prinzhorn-holding.com, thank You for kind help!) 13 | - 1.4 - added function f_qr_as_long_raw 14 | - 1.5 - terminator zeroes BUG solved (Markus Lobedann, thank You for kind help!) 15 | - 1.6 - older databases compatilbility (10g) 16 | - 1.7 - Numeric mode BUG with "0" at the beginning of triplet group 17 | - 2.0 - SVG image files support 18 | - 2.1 - Show logo in QR code 19 | - 2.2 - Select a QR code and background color for BMP representation (thank You k0mita for the contribution!) 20 | 21 | ## Install PL/SQL package 22 | - download 2 script files from "package" directory 23 | - execute them in database schema in following order: 24 | 1. PKS script file (package definition) 25 | 2. PKB file (package body) 26 | 27 | New Package ZT_QR is created in database schema. 28 | 29 | ## How to use PL/SQL package 30 | Procedure and Function descriptions with input and output parameters and examples are located in package definition script. 31 | 32 | ## Use JPG images instead of BMP 33 | BI Publisher (and potentialy some other software) is not displaying QR code BMP images correctly. 34 | 35 | Solution is to convert BMP images to JPG using JAVA in database - thanks to mr Hamzeh Fathi (hfathi54@gmail.com). 36 | 37 | How to install and use this functionality: 38 | - download 2 script files from "BMP2JPG" directory 39 | - install JAVA source from file "01 - bmp2jpg java.sql" 40 | - install PL/SQL function wrapper for JAVA source from file "02 - plsql function.sql"; function can be installed as standalone or in some package (for example in QR code package) 41 | 42 | That's it. Usage example for standalone function can be found in file "example.sql". 43 | 44 | Remark: this way images also get smaller in size. 45 | 46 | ## Install APEX plugin 47 | - First install PL/SQL package from "package" directory 48 | - Then import plugin file "item_type_plugin_eu_zttech_qr_code.sql" from "apex plugin" directory into your application 49 | 50 | For older versions of APEX, which use deprecated "Function" API interface use plugin file "item_type_plugin_eu_zttech_qr_code_func_api.sql" from "apex plugin/older versions" directory. 51 | 52 | ## Plugin Settings 53 | For calculation and graphic representation of QR Code there are following parameters: 54 | - Error correction level (4 different levels used for QR Code calculation) 55 | - Margines (Yes/No - show 4 modules margine around QR Code or not) 56 | - Display type (SVG image (default), HTML table or BMP image) 57 | - Module size (used when "HTML table" or "SVG image" display type is selected - defines moduze size in pixels) 58 | - Image size (used when "BMP image" display type is selected - defines image size in pixels) 59 | - Module color (used when "SVG image" display type is selected - defines module color; colors can be defined as named colors (for example black, red, white...), using rgb function (for example rgb(255, 0, 0) ) or HEX values (for example #FF0000) ) 60 | - Background color (used when "SVG image" display type is selected - defines QR code background color; colors can be defined as named colors (for example black, red, white...), using rgb function (for example rgb(255, 0, 0) ) or HEX values (for example #FF0000) ) 61 | - Rounded module edges (used when "SVG image" display type is selected - defines if modules should have rounded edges; if size of this parameter is half the module size (or larger) then modules are represented as circles) 62 | 63 | ## Demo Application 64 | https://apex.oracle.com/pls/apex/f?p=zttechdemo 65 | 66 | ![](https://github.com/zorantica/qr-code/blob/master/preview.jpg) 67 | -------------------------------------------------------------------------------- /plugin/item_type_plugin_eu_zttech_qr_code.sql: -------------------------------------------------------------------------------- 1 | prompt --application/set_environment 2 | set define off verify off feedback off 3 | whenever sqlerror exit sql.sqlcode rollback 4 | -------------------------------------------------------------------------------- 5 | -- 6 | -- ORACLE Application Express (APEX) export file 7 | -- 8 | -- You should run the script connected to SQL*Plus as the Oracle user 9 | -- APEX_190100 or as the owner (parsing schema) of the application. 10 | -- 11 | -- NOTE: Calls to apex_application_install override the defaults below. 12 | -- 13 | -------------------------------------------------------------------------------- 14 | begin 15 | wwv_flow_api.import_begin ( 16 | p_version_yyyy_mm_dd=>'2018.04.04' 17 | ,p_release=>'18.1.0.00.45' 18 | ,p_default_workspace_id=>1622468447055903 19 | ,p_default_application_id=>102 20 | ,p_default_owner=>'TICA' 21 | ); 22 | end; 23 | / 24 | prompt --application/shared_components/plugins/item_type/eu_zttech_qrcode 25 | begin 26 | wwv_flow_api.create_plugin( 27 | p_id=>wwv_flow_api.id(19166686046667066) 28 | ,p_plugin_type=>'ITEM TYPE' 29 | ,p_name=>'EU.ZTTECH.QRCODE' 30 | ,p_display_name=>'QR Code' 31 | ,p_supported_ui_types=>'DESKTOP:JQM_SMARTPHONE' 32 | ,p_supported_component_types=>'APEX_APPLICATION_PAGE_ITEMS' 33 | ,p_plsql_code=>wwv_flow_string.join(wwv_flow_t_varchar2( 34 | 'PROCEDURE render_qrcode(', 35 | ' p_item IN apex_plugin.t_item,', 36 | ' p_plugin IN apex_plugin.t_plugin,', 37 | ' p_param IN apex_plugin.t_item_render_param,', 38 | ' p_result OUT apex_plugin.t_item_render_result) IS', 39 | ' ', 40 | 'BEGIN', 41 | ' if p_param.value is null then', 42 | ' htp.p(''no data'');', 43 | ' else', 44 | '', 45 | ' -- Printer Friendly Display', 46 | ' IF p_param.is_printer_friendly THEN', 47 | ' apex_plugin_util.print_display_only(p_item_name => p_item.name,', 48 | ' p_display_value => p_param.value,', 49 | ' p_show_line_breaks => FALSE,', 50 | ' p_escape => TRUE,', 51 | ' p_attributes => p_item.element_attributes);', 52 | ' -- Read Only Display', 53 | ' ELSIF p_param.is_readonly THEN', 54 | ' apex_plugin_util.print_hidden_if_readonly(p_item_name => p_item.name,', 55 | ' p_value => p_param.value,', 56 | ' p_is_readonly => p_param.is_readonly,', 57 | ' p_is_printer_friendly => p_param.is_printer_friendly);', 58 | '', 59 | ' -- Normal Display', 60 | ' ELSE', 61 | ' if p_item.attribute_02 = ''HTML'' then', 62 | ' ZT_QR.p_qr_as_html_table(', 63 | ' p_data => p_param.value,', 64 | ' p_error_correction => p_item.attribute_01,', 65 | ' p_module_size_in_px => p_item.attribute_03,', 66 | ' p_margines => (CASE WHEN p_item.attribute_05 = ''Y'' THEN true ELSE false END)', 67 | ' );', 68 | ' elsif p_item.attribute_02 = ''BMP'' then', 69 | ' ZT_QR.p_qr_as_img_tag_base64(', 70 | ' p_data => p_param.value,', 71 | ' p_error_correction => p_item.attribute_01,', 72 | ' p_image_size_px => p_item.attribute_04,', 73 | ' p_margines => p_item.attribute_05', 74 | ' );', 75 | ' elsif p_item.attribute_02 = ''SVG'' then', 76 | ' ZT_QR.p_qr_as_svg(', 77 | ' p_data => p_param.value,', 78 | ' p_error_correction => p_item.attribute_01,', 79 | ' p_module_size_px => p_item.attribute_03,', 80 | ' p_margines_yn => p_item.attribute_05,', 81 | ' p_module_color => p_item.attribute_06,', 82 | ' p_background_color => p_item.attribute_07,', 83 | ' p_module_rounded_px => p_item.attribute_08', 84 | ' );', 85 | ' ', 86 | ' --htp.p(''

Download'');', 87 | ' else', 88 | ' htp.prn(''Error - unsupported display type.'');', 89 | ' end if;', 90 | ' ', 91 | ' end if;', 92 | ' ', 93 | ' end if;', 94 | '', 95 | ' p_result.is_navigable := false;', 96 | ' ', 97 | 'END render_qrcode;')) 98 | ,p_api_version=>2 99 | ,p_render_function=>'render_qrcode' 100 | ,p_standard_attributes=>'VISIBLE:FORM_ELEMENT:SESSION_STATE:SOURCE' 101 | ,p_substitute_attributes=>true 102 | ,p_subscribe_plugin_settings=>true 103 | ,p_help_text=>wwv_flow_string.join(wwv_flow_t_varchar2( 104 | 'QR plugin version 2.0.0', 105 | 'Usage and details on GitHub', 106 | 'https://github.com/zorantica/plsql-qr-code')) 107 | ,p_version_identifier=>'2.0.0.0' 108 | ,p_about_url=>'https://github.com/zorantica/plsql-qr-code' 109 | ); 110 | wwv_flow_api.create_plugin_attribute( 111 | p_id=>wwv_flow_api.id(19195010070495085) 112 | ,p_plugin_id=>wwv_flow_api.id(19166686046667066) 113 | ,p_attribute_scope=>'COMPONENT' 114 | ,p_attribute_sequence=>1 115 | ,p_display_sequence=>10 116 | ,p_prompt=>'Error correction level' 117 | ,p_attribute_type=>'SELECT LIST' 118 | ,p_is_required=>true 119 | ,p_default_value=>'L' 120 | ,p_supported_ui_types=>'DESKTOP' 121 | ,p_supported_component_types=>'APEX_APPLICATION_PAGE_ITEMS:APEX_APPL_PAGE_IG_COLUMNS' 122 | ,p_is_translatable=>false 123 | ,p_lov_type=>'STATIC' 124 | ); 125 | wwv_flow_api.create_plugin_attr_value( 126 | p_id=>wwv_flow_api.id(19195587333496851) 127 | ,p_plugin_attribute_id=>wwv_flow_api.id(19195010070495085) 128 | ,p_display_sequence=>10 129 | ,p_display_value=>'L - Low (7% of data)' 130 | ,p_return_value=>'L' 131 | ); 132 | wwv_flow_api.create_plugin_attr_value( 133 | p_id=>wwv_flow_api.id(19195953361499270) 134 | ,p_plugin_attribute_id=>wwv_flow_api.id(19195010070495085) 135 | ,p_display_sequence=>20 136 | ,p_display_value=>'M - Medium (15% of data)' 137 | ,p_return_value=>'M' 138 | ); 139 | wwv_flow_api.create_plugin_attr_value( 140 | p_id=>wwv_flow_api.id(19196401846501124) 141 | ,p_plugin_attribute_id=>wwv_flow_api.id(19195010070495085) 142 | ,p_display_sequence=>30 143 | ,p_display_value=>'Q - Quartile (25% of data)' 144 | ,p_return_value=>'Q' 145 | ); 146 | wwv_flow_api.create_plugin_attr_value( 147 | p_id=>wwv_flow_api.id(19196767711502010) 148 | ,p_plugin_attribute_id=>wwv_flow_api.id(19195010070495085) 149 | ,p_display_sequence=>40 150 | ,p_display_value=>'H - High (30% of data)' 151 | ,p_return_value=>'H' 152 | ); 153 | wwv_flow_api.create_plugin_attribute( 154 | p_id=>wwv_flow_api.id(19203464560101742) 155 | ,p_plugin_id=>wwv_flow_api.id(19166686046667066) 156 | ,p_attribute_scope=>'COMPONENT' 157 | ,p_attribute_sequence=>2 158 | ,p_display_sequence=>20 159 | ,p_prompt=>'Display Type' 160 | ,p_attribute_type=>'SELECT LIST' 161 | ,p_is_required=>true 162 | ,p_default_value=>'SVG' 163 | ,p_supported_ui_types=>'DESKTOP' 164 | ,p_supported_component_types=>'APEX_APPLICATION_PAGE_ITEMS:APEX_APPL_PAGE_IG_COLUMNS' 165 | ,p_is_translatable=>false 166 | ,p_lov_type=>'STATIC' 167 | ); 168 | wwv_flow_api.create_plugin_attr_value( 169 | p_id=>wwv_flow_api.id(15301637796637240) 170 | ,p_plugin_attribute_id=>wwv_flow_api.id(19203464560101742) 171 | ,p_display_sequence=>5 172 | ,p_display_value=>'SVG image' 173 | ,p_return_value=>'SVG' 174 | ); 175 | wwv_flow_api.create_plugin_attr_value( 176 | p_id=>wwv_flow_api.id(19204051603103163) 177 | ,p_plugin_attribute_id=>wwv_flow_api.id(19203464560101742) 178 | ,p_display_sequence=>10 179 | ,p_display_value=>'HTML Table' 180 | ,p_return_value=>'HTML' 181 | ); 182 | wwv_flow_api.create_plugin_attr_value( 183 | p_id=>wwv_flow_api.id(19204426782104803) 184 | ,p_plugin_attribute_id=>wwv_flow_api.id(19203464560101742) 185 | ,p_display_sequence=>20 186 | ,p_display_value=>'BMP Image' 187 | ,p_return_value=>'BMP' 188 | ); 189 | wwv_flow_api.create_plugin_attribute( 190 | p_id=>wwv_flow_api.id(19206265959135863) 191 | ,p_plugin_id=>wwv_flow_api.id(19166686046667066) 192 | ,p_attribute_scope=>'COMPONENT' 193 | ,p_attribute_sequence=>3 194 | ,p_display_sequence=>30 195 | ,p_prompt=>'Module size' 196 | ,p_attribute_type=>'NUMBER' 197 | ,p_is_required=>true 198 | ,p_default_value=>'8' 199 | ,p_display_length=>5 200 | ,p_max_length=>2 201 | ,p_unit=>'pixels' 202 | ,p_supported_ui_types=>'DESKTOP' 203 | ,p_supported_component_types=>'APEX_APPLICATION_PAGE_ITEMS' 204 | ,p_is_translatable=>false 205 | ,p_depending_on_attribute_id=>wwv_flow_api.id(19203464560101742) 206 | ,p_depending_on_has_to_exist=>true 207 | ,p_depending_on_condition_type=>'IN_LIST' 208 | ,p_depending_on_expression=>'HTML,SVG' 209 | ); 210 | wwv_flow_api.create_plugin_attribute( 211 | p_id=>wwv_flow_api.id(19207654617152716) 212 | ,p_plugin_id=>wwv_flow_api.id(19166686046667066) 213 | ,p_attribute_scope=>'COMPONENT' 214 | ,p_attribute_sequence=>4 215 | ,p_display_sequence=>40 216 | ,p_prompt=>'Image size' 217 | ,p_attribute_type=>'NUMBER' 218 | ,p_is_required=>true 219 | ,p_display_length=>5 220 | ,p_max_length=>4 221 | ,p_unit=>'pixels' 222 | ,p_is_translatable=>false 223 | ,p_depending_on_attribute_id=>wwv_flow_api.id(19203464560101742) 224 | ,p_depending_on_has_to_exist=>true 225 | ,p_depending_on_condition_type=>'EQUALS' 226 | ,p_depending_on_expression=>'BMP' 227 | ); 228 | wwv_flow_api.create_plugin_attribute( 229 | p_id=>wwv_flow_api.id(19208230004156464) 230 | ,p_plugin_id=>wwv_flow_api.id(19166686046667066) 231 | ,p_attribute_scope=>'COMPONENT' 232 | ,p_attribute_sequence=>5 233 | ,p_display_sequence=>15 234 | ,p_prompt=>'Margines' 235 | ,p_attribute_type=>'CHECKBOX' 236 | ,p_is_required=>true 237 | ,p_default_value=>'N' 238 | ,p_supported_ui_types=>'DESKTOP:JQM_SMARTPHONE' 239 | ,p_supported_component_types=>'APEX_APPLICATION_PAGE_ITEMS' 240 | ,p_is_translatable=>false 241 | ); 242 | wwv_flow_api.create_plugin_attribute( 243 | p_id=>wwv_flow_api.id(15310884392722565) 244 | ,p_plugin_id=>wwv_flow_api.id(19166686046667066) 245 | ,p_attribute_scope=>'COMPONENT' 246 | ,p_attribute_sequence=>6 247 | ,p_display_sequence=>60 248 | ,p_prompt=>'Module color' 249 | ,p_attribute_type=>'TEXT' 250 | ,p_is_required=>false 251 | ,p_supported_ui_types=>'DESKTOP:JQM_SMARTPHONE' 252 | ,p_supported_component_types=>'APEX_APPLICATION_PAGE_ITEMS' 253 | ,p_is_translatable=>false 254 | ,p_depending_on_attribute_id=>wwv_flow_api.id(19203464560101742) 255 | ,p_depending_on_has_to_exist=>true 256 | ,p_depending_on_condition_type=>'EQUALS' 257 | ,p_depending_on_expression=>'SVG' 258 | ,p_examples=>'black | red | rgb(255, 0, 0) | #FF0000' 259 | ,p_help_text=>'Module color (as named color, rgb function or HEX# notification).' 260 | ); 261 | wwv_flow_api.create_plugin_attribute( 262 | p_id=>wwv_flow_api.id(15311493488724950) 263 | ,p_plugin_id=>wwv_flow_api.id(19166686046667066) 264 | ,p_attribute_scope=>'COMPONENT' 265 | ,p_attribute_sequence=>7 266 | ,p_display_sequence=>70 267 | ,p_prompt=>'Background color' 268 | ,p_attribute_type=>'TEXT' 269 | ,p_is_required=>false 270 | ,p_is_translatable=>false 271 | ,p_depending_on_attribute_id=>wwv_flow_api.id(19203464560101742) 272 | ,p_depending_on_has_to_exist=>true 273 | ,p_depending_on_condition_type=>'EQUALS' 274 | ,p_depending_on_expression=>'SVG' 275 | ); 276 | wwv_flow_api.create_plugin_attribute( 277 | p_id=>wwv_flow_api.id(15320807577751337) 278 | ,p_plugin_id=>wwv_flow_api.id(19166686046667066) 279 | ,p_attribute_scope=>'COMPONENT' 280 | ,p_attribute_sequence=>8 281 | ,p_display_sequence=>80 282 | ,p_prompt=>'Rounded module edges' 283 | ,p_attribute_type=>'NUMBER' 284 | ,p_is_required=>false 285 | ,p_unit=>'pixel' 286 | ,p_supported_ui_types=>'DESKTOP:JQM_SMARTPHONE' 287 | ,p_supported_component_types=>'APEX_APPLICATION_PAGE_ITEMS' 288 | ,p_is_translatable=>false 289 | ); 290 | end; 291 | / 292 | begin 293 | wwv_flow_api.import_end(p_auto_install_sup_obj => nvl(wwv_flow_application_install.get_auto_install_sup_obj, false), p_is_component_import => true); 294 | commit; 295 | end; 296 | / 297 | set verify on feedback on define on 298 | prompt ...done 299 | -------------------------------------------------------------------------------- /plugin/olderversions/item_type_plugin_eu_zttech_qr_code_func_api.sql: -------------------------------------------------------------------------------- 1 | prompt --application/set_environment 2 | set define off verify off feedback off 3 | whenever sqlerror exit sql.sqlcode rollback 4 | -------------------------------------------------------------------------------- 5 | -- 6 | -- ORACLE Application Express (APEX) export file 7 | -- 8 | -- You should run the script connected to SQL*Plus as the Oracle user 9 | -- APEX_190100 or as the owner (parsing schema) of the application. 10 | -- 11 | -- NOTE: Calls to apex_application_install override the defaults below. 12 | -- 13 | -------------------------------------------------------------------------------- 14 | begin 15 | wwv_flow_api.import_begin ( 16 | p_version_yyyy_mm_dd=>'2016.08.24' 17 | ,p_release=>'5.1.1.00.08' 18 | ,p_default_workspace_id=>1962282725390507 19 | ,p_default_application_id=>1000 20 | ,p_default_owner=>'TICA' 21 | ); 22 | end; 23 | / 24 | prompt --application/shared_components/plugins/item_type/eu_zttech_qrcode 25 | begin 26 | wwv_flow_api.create_plugin( 27 | p_id=>wwv_flow_api.id(19166686046667066) 28 | ,p_plugin_type=>'ITEM TYPE' 29 | ,p_name=>'EU.ZTTECH.QRCODE' 30 | ,p_display_name=>'QR Code' 31 | ,p_supported_ui_types=>'DESKTOP:JQM_SMARTPHONE' 32 | ,p_supported_component_types=>'APEX_APPLICATION_PAGE_ITEMS' 33 | ,p_plsql_code=>wwv_flow_string.join(wwv_flow_t_varchar2( 34 | 'FUNCTION render_qrcode(p_item IN apex_plugin.t_page_item,', 35 | ' p_plugin IN apex_plugin.t_plugin,', 36 | ' p_value IN VARCHAR2,', 37 | ' p_is_readonly IN BOOLEAN,', 38 | ' p_is_printer_friendly IN BOOLEAN)', 39 | ' RETURN apex_plugin.t_page_item_render_result IS', 40 | '', 41 | ' l_result apex_plugin.t_page_item_render_result;', 42 | '', 43 | 'BEGIN', 44 | ' if p_value is null then', 45 | ' htp.p(''no data'');', 46 | ' else', 47 | '', 48 | ' -- Printer Friendly Display', 49 | ' IF p_is_printer_friendly THEN', 50 | ' apex_plugin_util.print_display_only(p_item_name => p_item.name,', 51 | ' p_display_value => p_value,', 52 | ' p_show_line_breaks => FALSE,', 53 | ' p_escape => TRUE,', 54 | ' p_attributes => p_item.element_attributes);', 55 | ' -- Read Only Display', 56 | ' ELSIF p_is_readonly THEN', 57 | ' apex_plugin_util.print_hidden_if_readonly(p_item_name => p_item.name,', 58 | ' p_value => p_value,', 59 | ' p_is_readonly => p_is_readonly,', 60 | ' p_is_printer_friendly => p_is_printer_friendly);', 61 | '', 62 | ' -- Normal Display', 63 | ' ELSE', 64 | ' if p_item.attribute_02 = ''HTML'' then', 65 | ' ZT_QR.p_qr_as_html_table(', 66 | ' p_data => p_value,', 67 | ' p_error_correction => p_item.attribute_01,', 68 | ' p_module_size_in_px => p_item.attribute_03,', 69 | ' p_margines => (CASE WHEN p_item.attribute_05 = ''Y'' THEN true ELSE false END)', 70 | ' );', 71 | ' elsif p_item.attribute_02 = ''BMP'' then', 72 | ' ZT_QR.p_qr_as_img_tag_base64(', 73 | ' p_data => p_value,', 74 | ' p_error_correction => p_item.attribute_01,', 75 | ' p_image_size_px => p_item.attribute_04,', 76 | ' p_margines => p_item.attribute_05', 77 | ' );', 78 | ' elsif p_item.attribute_02 = ''SVG'' then', 79 | ' ZT_QR.p_qr_as_svg(', 80 | ' p_data => p_value,', 81 | ' p_error_correction => p_item.attribute_01,', 82 | ' p_module_size_px => p_item.attribute_03,', 83 | ' p_margines_yn => p_item.attribute_05,', 84 | ' p_module_color => p_item.attribute_06,', 85 | ' p_background_color => p_item.attribute_07,', 86 | ' p_module_rounded_px => p_item.attribute_08', 87 | ' );', 88 | ' ', 89 | ' --htp.p(''

Download'');', 90 | ' else', 91 | ' htp.prn(''Error - unsupported display type.'');', 92 | ' end if;', 93 | ' end if;', 94 | ' ', 95 | ' end if;', 96 | '', 97 | ' l_result.is_navigable := false;', 98 | ' RETURN l_result;', 99 | '', 100 | 'END render_qrcode;')) 101 | ,p_api_version=>2 102 | ,p_render_function=>'render_qrcode' 103 | ,p_standard_attributes=>'VISIBLE:FORM_ELEMENT:SESSION_STATE:SOURCE' 104 | ,p_substitute_attributes=>true 105 | ,p_subscribe_plugin_settings=>true 106 | ,p_help_text=>wwv_flow_string.join(wwv_flow_t_varchar2( 107 | 'QR plugin version 2.0.0', 108 | 'Usage and details on GitHub', 109 | 'https://github.com/zorantica/plsql-qr-code')) 110 | ,p_version_identifier=>'2.0.0.0' 111 | ,p_about_url=>'https://github.com/zorantica/plsql-qr-code' 112 | ); 113 | wwv_flow_api.create_plugin_attribute( 114 | p_id=>wwv_flow_api.id(19195010070495085) 115 | ,p_plugin_id=>wwv_flow_api.id(19166686046667066) 116 | ,p_attribute_scope=>'COMPONENT' 117 | ,p_attribute_sequence=>1 118 | ,p_display_sequence=>10 119 | ,p_prompt=>'Error correction level' 120 | ,p_attribute_type=>'SELECT LIST' 121 | ,p_is_required=>true 122 | ,p_default_value=>'L' 123 | ,p_supported_ui_types=>'DESKTOP' 124 | ,p_supported_component_types=>'APEX_APPLICATION_PAGE_ITEMS:APEX_APPL_PAGE_IG_COLUMNS' 125 | ,p_is_translatable=>false 126 | ,p_lov_type=>'STATIC' 127 | ); 128 | wwv_flow_api.create_plugin_attr_value( 129 | p_id=>wwv_flow_api.id(19195587333496851) 130 | ,p_plugin_attribute_id=>wwv_flow_api.id(19195010070495085) 131 | ,p_display_sequence=>10 132 | ,p_display_value=>'L - Low (7% of data)' 133 | ,p_return_value=>'L' 134 | ); 135 | wwv_flow_api.create_plugin_attr_value( 136 | p_id=>wwv_flow_api.id(19195953361499270) 137 | ,p_plugin_attribute_id=>wwv_flow_api.id(19195010070495085) 138 | ,p_display_sequence=>20 139 | ,p_display_value=>'M - Medium (15% of data)' 140 | ,p_return_value=>'M' 141 | ); 142 | wwv_flow_api.create_plugin_attr_value( 143 | p_id=>wwv_flow_api.id(19196401846501124) 144 | ,p_plugin_attribute_id=>wwv_flow_api.id(19195010070495085) 145 | ,p_display_sequence=>30 146 | ,p_display_value=>'Q - Quartile (25% of data)' 147 | ,p_return_value=>'Q' 148 | ); 149 | wwv_flow_api.create_plugin_attr_value( 150 | p_id=>wwv_flow_api.id(19196767711502010) 151 | ,p_plugin_attribute_id=>wwv_flow_api.id(19195010070495085) 152 | ,p_display_sequence=>40 153 | ,p_display_value=>'H - High (30% of data)' 154 | ,p_return_value=>'H' 155 | ); 156 | wwv_flow_api.create_plugin_attribute( 157 | p_id=>wwv_flow_api.id(19203464560101742) 158 | ,p_plugin_id=>wwv_flow_api.id(19166686046667066) 159 | ,p_attribute_scope=>'COMPONENT' 160 | ,p_attribute_sequence=>2 161 | ,p_display_sequence=>20 162 | ,p_prompt=>'Display Type' 163 | ,p_attribute_type=>'SELECT LIST' 164 | ,p_is_required=>true 165 | ,p_default_value=>'SVG' 166 | ,p_supported_ui_types=>'DESKTOP' 167 | ,p_supported_component_types=>'APEX_APPLICATION_PAGE_ITEMS:APEX_APPL_PAGE_IG_COLUMNS' 168 | ,p_is_translatable=>false 169 | ,p_lov_type=>'STATIC' 170 | ); 171 | wwv_flow_api.create_plugin_attr_value( 172 | p_id=>wwv_flow_api.id(15301637796637240) 173 | ,p_plugin_attribute_id=>wwv_flow_api.id(19203464560101742) 174 | ,p_display_sequence=>5 175 | ,p_display_value=>'SVG image' 176 | ,p_return_value=>'SVG' 177 | ); 178 | wwv_flow_api.create_plugin_attr_value( 179 | p_id=>wwv_flow_api.id(19204051603103163) 180 | ,p_plugin_attribute_id=>wwv_flow_api.id(19203464560101742) 181 | ,p_display_sequence=>10 182 | ,p_display_value=>'HTML Table' 183 | ,p_return_value=>'HTML' 184 | ); 185 | wwv_flow_api.create_plugin_attr_value( 186 | p_id=>wwv_flow_api.id(19204426782104803) 187 | ,p_plugin_attribute_id=>wwv_flow_api.id(19203464560101742) 188 | ,p_display_sequence=>20 189 | ,p_display_value=>'BMP Image' 190 | ,p_return_value=>'BMP' 191 | ); 192 | wwv_flow_api.create_plugin_attribute( 193 | p_id=>wwv_flow_api.id(19206265959135863) 194 | ,p_plugin_id=>wwv_flow_api.id(19166686046667066) 195 | ,p_attribute_scope=>'COMPONENT' 196 | ,p_attribute_sequence=>3 197 | ,p_display_sequence=>30 198 | ,p_prompt=>'Module size' 199 | ,p_attribute_type=>'NUMBER' 200 | ,p_is_required=>true 201 | ,p_default_value=>'8' 202 | ,p_display_length=>5 203 | ,p_max_length=>2 204 | ,p_unit=>'pixels' 205 | ,p_supported_ui_types=>'DESKTOP' 206 | ,p_supported_component_types=>'APEX_APPLICATION_PAGE_ITEMS' 207 | ,p_is_translatable=>false 208 | ,p_depending_on_attribute_id=>wwv_flow_api.id(19203464560101742) 209 | ,p_depending_on_has_to_exist=>true 210 | ,p_depending_on_condition_type=>'IN_LIST' 211 | ,p_depending_on_expression=>'HTML,SVG' 212 | ); 213 | wwv_flow_api.create_plugin_attribute( 214 | p_id=>wwv_flow_api.id(19207654617152716) 215 | ,p_plugin_id=>wwv_flow_api.id(19166686046667066) 216 | ,p_attribute_scope=>'COMPONENT' 217 | ,p_attribute_sequence=>4 218 | ,p_display_sequence=>40 219 | ,p_prompt=>'Image size' 220 | ,p_attribute_type=>'NUMBER' 221 | ,p_is_required=>true 222 | ,p_display_length=>5 223 | ,p_max_length=>4 224 | ,p_unit=>'pixels' 225 | ,p_is_translatable=>false 226 | ,p_depending_on_attribute_id=>wwv_flow_api.id(19203464560101742) 227 | ,p_depending_on_has_to_exist=>true 228 | ,p_depending_on_condition_type=>'EQUALS' 229 | ,p_depending_on_expression=>'BMP' 230 | ); 231 | wwv_flow_api.create_plugin_attribute( 232 | p_id=>wwv_flow_api.id(19208230004156464) 233 | ,p_plugin_id=>wwv_flow_api.id(19166686046667066) 234 | ,p_attribute_scope=>'COMPONENT' 235 | ,p_attribute_sequence=>5 236 | ,p_display_sequence=>15 237 | ,p_prompt=>'Margines' 238 | ,p_attribute_type=>'CHECKBOX' 239 | ,p_is_required=>true 240 | ,p_default_value=>'N' 241 | ,p_supported_ui_types=>'DESKTOP:JQM_SMARTPHONE' 242 | ,p_supported_component_types=>'APEX_APPLICATION_PAGE_ITEMS' 243 | ,p_is_translatable=>false 244 | ); 245 | wwv_flow_api.create_plugin_attribute( 246 | p_id=>wwv_flow_api.id(15310884392722565) 247 | ,p_plugin_id=>wwv_flow_api.id(19166686046667066) 248 | ,p_attribute_scope=>'COMPONENT' 249 | ,p_attribute_sequence=>6 250 | ,p_display_sequence=>60 251 | ,p_prompt=>'Module color' 252 | ,p_attribute_type=>'TEXT' 253 | ,p_is_required=>false 254 | ,p_supported_ui_types=>'DESKTOP:JQM_SMARTPHONE' 255 | ,p_supported_component_types=>'APEX_APPLICATION_PAGE_ITEMS' 256 | ,p_is_translatable=>false 257 | ,p_depending_on_attribute_id=>wwv_flow_api.id(19203464560101742) 258 | ,p_depending_on_has_to_exist=>true 259 | ,p_depending_on_condition_type=>'EQUALS' 260 | ,p_depending_on_expression=>'SVG' 261 | ,p_examples=>'black | red | rgb(255, 0, 0) | #FF0000' 262 | ,p_help_text=>'Module color (as named color, rgb function or HEX# notification).' 263 | ); 264 | wwv_flow_api.create_plugin_attribute( 265 | p_id=>wwv_flow_api.id(15311493488724950) 266 | ,p_plugin_id=>wwv_flow_api.id(19166686046667066) 267 | ,p_attribute_scope=>'COMPONENT' 268 | ,p_attribute_sequence=>7 269 | ,p_display_sequence=>70 270 | ,p_prompt=>'Background color' 271 | ,p_attribute_type=>'TEXT' 272 | ,p_is_required=>false 273 | ,p_is_translatable=>false 274 | ,p_depending_on_attribute_id=>wwv_flow_api.id(19203464560101742) 275 | ,p_depending_on_has_to_exist=>true 276 | ,p_depending_on_condition_type=>'EQUALS' 277 | ,p_depending_on_expression=>'SVG' 278 | ); 279 | wwv_flow_api.create_plugin_attribute( 280 | p_id=>wwv_flow_api.id(15320807577751337) 281 | ,p_plugin_id=>wwv_flow_api.id(19166686046667066) 282 | ,p_attribute_scope=>'COMPONENT' 283 | ,p_attribute_sequence=>8 284 | ,p_display_sequence=>80 285 | ,p_prompt=>'Rounded module edges' 286 | ,p_attribute_type=>'NUMBER' 287 | ,p_is_required=>false 288 | ,p_unit=>'pixel' 289 | ,p_supported_ui_types=>'DESKTOP:JQM_SMARTPHONE' 290 | ,p_supported_component_types=>'APEX_APPLICATION_PAGE_ITEMS' 291 | ,p_is_translatable=>false 292 | ); 293 | end; 294 | / 295 | begin 296 | wwv_flow_api.import_end(p_auto_install_sup_obj => nvl(wwv_flow_application_install.get_auto_install_sup_obj, false), p_is_component_import => true); 297 | commit; 298 | end; 299 | / 300 | set verify on feedback on define on 301 | prompt ...done 302 | -------------------------------------------------------------------------------- /package/ZT_QR.pks: -------------------------------------------------------------------------------- 1 | create or replace PACKAGE ZT_QR AUTHID DEFINER AS 2 | /****************************************************************************** 3 | Author: Zoran Tica 4 | ZT-TECH, racunalni�ke storitve s.p. 5 | http://www.zt-tech.eu 6 | 7 | PURPOSE: A package for QR code data and image generation 8 | 9 | REVISIONS: 10 | Ver Date Author Description 11 | --------- ---------- --------------- ------------------------------------ 12 | 1.0 18/08/2018 Zoran Tica First version of package. 13 | 1.1 26/05/2019 Zoran Tica Added UTF-8 support, fixed minor BUGs for debug display 14 | 1.2 15/12/2019 Zoran Tica Fixed "_" and "%" BUG 15 | 1.3 13/03/2020 Zoran Tica Added function f_qr_as_long_raw 16 | 1.4 07/01/2021 Zoran Tica Terminator BUG 17 | 1.5 05/02/2021 Zoran Tica older databases compatibility (10g) 18 | f_integer_2_binary - LISTAGG replaced with pure PL SQL 19 | f_get_version - XMLTABLE replaced with local function f_explode 20 | 2.0 09/02/2021 Zoran Tica SVG files support 21 | 2.1 21/08/2023 Zoran Tica Display logo in QR code (for SVG QR Code representation) 22 | 2.2 24/06/2024 k0mita Select a QR code and background color for BMP representation 23 | 24 | 25 | ---------------------------------------------------------------------------- 26 | Copyright (C) 2018 - Zoran Tica 27 | 28 | Permission is hereby granted, free of charge, to any person obtaining a copy 29 | of this software and associated documentation files (the "Software"), to deal 30 | in the Software without restriction, including without limitation the rights 31 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 32 | copies of the Software, and to permit persons to whom the Software is 33 | furnished to do so, subject to the following conditions: 34 | 35 | The above copyright notice and this permission notice shall be included in 36 | all copies or substantial portions of the Software. 37 | 38 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 39 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 40 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 41 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 42 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 43 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 44 | THE SOFTWARE. 45 | ---------------------------------------------------------------------------- 46 | */ 47 | 48 | 49 | /* 50 | Error correction modes: 51 | L - Low Recovers 7% of data 52 | M - Medium Recovers 15% of data 53 | Q - Quartile Recovers 25% of data 54 | H - High Recovers 30% of data 55 | */ 56 | 57 | 58 | /* 59 | Procedure generates QR code data as varchar2 variable filled with 0 and 1 60 | 0 is white module, 1 is black 61 | Lines are separated with chr(10) 62 | 63 | IN parameters: 64 | p_data - data that is going to be encoded into QR code 65 | p_error_correction - error correction level (values L, M, Q or H) 66 | 67 | OUT parameters: 68 | p_qr - generated QR code data in format "row (1110100010100...) || newline (chr 10) || row || newline..." 69 | p_matrix_size - matrix size in modules (21, 25, 29...) 70 | */ 71 | PROCEDURE p_generate_qr_data( 72 | p_data varchar2, 73 | p_error_correction varchar2, 74 | p_qr OUT NOCOPY varchar2, 75 | p_matrix_size OUT pls_integer 76 | ); 77 | 78 | 79 | /* 80 | Procedure generates QR code data as varchar2 variable filled with 0 and 1 81 | 0 is white module, 1 is black 82 | Lines are separated with chr(10) 83 | Debug is printed as DBMS_OUTPUT 84 | There are 3 levels of debug (1, 2 or 3 - low, medium, high) 85 | 86 | IN parameters: 87 | p_data - data that is going to be encoded into QR code 88 | p_error_correction - error correction level (values L, M, Q or H) 89 | p_debug - should DBMS OUTPUT be printed 90 | p_debug_level - debug level (1, 2, 3...) - details to be printed in debug output 91 | p_masking_out - which masking (values 0-7) should be displayed; null -> the best masking will be calculated and selected automatically 92 | 93 | OUT parameters: 94 | p_qr - generated QR code data in format "row (1110100010100) || newline (chr 10) || row || newline..." 95 | p_matrix_size - matrix size in modules (21, 25, 29...) 96 | 97 | 98 | Testing code (enable DBMS OUTPUT for debug!): 99 | DECLARE 100 | lcQR varchar2(32727); 101 | lnMatrixSize pls_integer; 102 | BEGIN 103 | ZT_QR.p_qr_debug( 104 | p_data => 'http://www.zt-tech.eu', 105 | p_error_correction => 'Q', 106 | p_debug => true, 107 | p_debug_level => 2, 108 | p_qr => lcQR, 109 | p_matrix_size => lnMatrixSize 110 | ); 111 | END; 112 | 113 | */ 114 | PROCEDURE p_qr_debug( 115 | p_data varchar2, 116 | p_error_correction varchar2, 117 | p_debug boolean default true, 118 | p_debug_level pls_integer default 1, 119 | p_masking_out pls_integer default null, 120 | p_qr OUT NOCOPY varchar2, 121 | p_matrix_size OUT pls_integer 122 | ); 123 | 124 | 125 | 126 | /* 127 | Function return HTML code for HTML table element representing QR code 128 | Modules are shown as table cells 129 | No additional data (CSS or HTML code) is needed to show table in HTML page 130 | 131 | IN parameters: 132 | p_data - data that is going to be encoded into QR code 133 | p_error_correction - error correction level (values L, M, Q or H) 134 | p_module_size_in_px - width and height of module (table cell) 135 | p_margines - should white margine around QR code (4 modules wide) be generated 136 | */ 137 | FUNCTION f_qr_as_html_table( 138 | p_data varchar2, --data going to be encoded into QR code 139 | p_error_correction varchar2, --L, M, Q or H 140 | p_module_size_in_px pls_integer default 8, --module size in pixels 141 | p_margines boolean default false --margines around QR code (4 modules) 142 | ) RETURN clob; 143 | 144 | /* 145 | Procedure prints HTML code for HTML table element using HTP.P procedure 146 | HTML code is prepared in function f_qr_as_html_table 147 | 148 | IN parameters: 149 | p_data - data that is going to be encoded into QR code 150 | p_error_correction - error correction level (values L, M, Q or H) 151 | p_module_size_in_px - width and height of module (table cell) 152 | p_margines - should white margine around QR code (4 modules wide) be generated 153 | */ 154 | PROCEDURE p_qr_as_html_table( 155 | p_data varchar2, --data going to be encoded into QR code 156 | p_error_correction varchar2, --L, M, Q or H 157 | p_module_size_in_px pls_integer default 8, --module size in pixels 158 | p_margines boolean default false --margines around QR code (4 modules) 159 | ); 160 | 161 | 162 | /* 163 | Function returns black and white BMP image with QR code 164 | Modules are 8x8 pixels large 165 | 166 | IN parameters: 167 | p_data - data that is going to be encoded into QR code 168 | p_error_correction - error correction level (values L, M, Q or H) 169 | p_margines - should white margine around QR code (4 modules wide) be generated 170 | p_foreground_color -- HEX representation of the RGB values of the foreground color (default black) 171 | p_background_color -- HEX representation of the RGB values of the background color (default white) 172 | 173 | Suggested HEX foreground colors: 174 | Blue - 002db3 175 | Red - 990000 176 | Green - 008000 177 | Brown - 663300 178 | Orange - ff9900 179 | Pink - cc0066 180 | Magenta - cc00cc 181 | Gray - 737373 182 | */ 183 | 184 | FUNCTION f_qr_as_bmp( 185 | p_data varchar2, --data going to be encoded into QR code 186 | p_error_correction varchar2, --L, M, Q or H 187 | p_margines varchar2 default 'N', --margines around QR code (4 modules) - values Y or N 188 | p_foreground_color varchar2 default '000000', -- HEX representation of the RGB values of the foreground color 189 | p_background_color varchar2 default 'FFFFFF'-- HEX representation of the RGB values of the background color 190 | ) RETURN blob; 191 | 192 | FUNCTION f_qr_as_long_raw( 193 | p_data varchar2, --data going to be encoded into QR code 194 | p_error_correction varchar2, --L, M, Q or H 195 | p_margines varchar2 default 'N' --margines around QR code (4 modules) - values Y or N 196 | ) RETURN long raw; 197 | 198 | 199 | /* 200 | Procedure shows QR code as black and white BMP image 201 | Printed is HTML img tag with base64 image in it 202 | 203 | IN parameters: 204 | p_data - data that is going to be encoded into QR code 205 | p_error_correction - error correction level (values L, M, Q or H) 206 | p_image_size_px - image size in pixels 207 | p_margines - should white margine around QR code (4 modules wide) be generated 208 | */ 209 | PROCEDURE p_qr_as_img_tag_base64( 210 | p_data varchar2, --data going to be encoded into QR code 211 | p_error_correction varchar2, --L, M, Q or H 212 | p_image_size_px pls_integer, 213 | p_margines varchar2 default 'N' --margines around QR code (4 modules) - values Y or N 214 | ); 215 | 216 | 217 | 218 | /* 219 | Function returns SVG image with QR code 220 | 221 | IN parameters: 222 | p_data - data that is going to be encoded into QR code 223 | p_error_correction - error correction level (values L, M, Q or H) 224 | p_margines_yn - should white margine around QR code (4 modules wide) be generated; values 'Y' or 'N' 225 | p_module_size_px - width and height of one module 226 | p_module_color - module color; colors can be defined as named colors (for example black, red, white...), using rgb function (for example rgb(255, 0, 0) ) or HEX values (for example #FF0000) 227 | p_background_color - background color; colors can be defined as named colors (for example black, red white...), using rgb function (for example rgb(255, 0, 0) ) or HEX values (for example #FF0000) 228 | p_module_rounded_px - if modules should have rounded edges (if size of this parameter is half the module size (or larger) then modules are represented as circles) 229 | p_logo_yn - should logo be displayed on not (values Y / N) 230 | p_logo_size_percent - logo background rectangle size (in percentages) related to QR code size 231 | p_logo_image - logo image (URL reference or base64 content) 232 | p_logo_back_rect_yn - should logo background rectangle be displayed or not 233 | p_logo_back_rect_color - logo background rectangle color 234 | p_logo_back_rect_round_px - logo background rectangle rounded edges 235 | p_logo_margine_px - a margine between logo and background rectangle 236 | 237 | Procedure prints SVG image using HTP.P procedure (can be used to print SVG image directly into HTML code) 238 | */ 239 | FUNCTION f_qr_as_svg( 240 | p_data varchar2, --data going to be encoded into QR code 241 | p_error_correction varchar2, --L, M, Q or H 242 | p_module_size_px pls_integer default 8, --modul size in pixels 243 | p_margines_yn varchar2 default 'N', --margines around QR code (4 modules) - values Y or N 244 | p_module_color varchar2 default 'black', --colors are defined as SVG named colors OR rgb (with # or rgb function) 245 | p_background_color varchar2 default 'white', 246 | p_module_rounded_px pls_integer default 0, --0 - sharp corners; > 0 - rounded in pixels 247 | p_logo_yn varchar2 default 'N', 248 | p_logo_size_percent number default 20, 249 | p_logo_image clob default null, 250 | p_logo_back_rect_yn varchar2 default 'Y', 251 | p_logo_back_rect_color varchar2 default 'white', 252 | p_logo_back_rect_round_px pls_integer default 0, 253 | p_logo_margine_px number default 5 254 | ) RETURN clob; 255 | 256 | PROCEDURE p_qr_as_svg( 257 | p_data varchar2, --data going to be encoded into QR code 258 | p_error_correction varchar2, --L, M, Q or H 259 | p_module_size_px pls_integer default 8, --modul size in pixels 260 | p_margines_yn varchar2 default 'N', --margines around QR code (4 modules) - values Y or N 261 | p_module_color varchar2 default 'black', --colors are defined as SVG named colors OR rgb (with # or rgb function) 262 | p_background_color varchar2 default 'white', 263 | p_module_rounded_px pls_integer default 0, --0 - sharp corners; > 0 - rounded in pixels 264 | p_logo_yn varchar2 default 'N', 265 | p_logo_size_percent number default 20, 266 | p_logo_image clob default null, 267 | p_logo_back_rect_yn varchar2 default 'Y', 268 | p_logo_back_rect_color varchar2 default 'white', 269 | p_logo_back_rect_round_px pls_integer default 0, 270 | p_logo_margine_px number default 5 271 | ); 272 | 273 | 274 | 275 | /* 276 | Utility procedure which saves generated BMP file containing QR code on server side (directory) 277 | */ 278 | PROCEDURE p_save_file( 279 | p_document blob, 280 | p_file_name varchar2, 281 | p_folder varchar2 282 | ); 283 | 284 | END ZT_QR; 285 | / 286 | -------------------------------------------------------------------------------- /package/ZT_QR.pkb: -------------------------------------------------------------------------------- 1 | CREATE OR REPLACE PACKAGE BODY ZT_QR AS 2 | 3 | --C O N S T A N T S 4 | 5 | --data mode 6 | cNumericMode CONSTANT pls_integer := 1; 7 | cAlphanumericMode CONSTANT pls_integer := 2; 8 | cByteMode CONSTANT pls_integer := 3; 9 | cKanjiMode CONSTANT pls_integer := 4; 10 | 11 | 12 | --V A R I A B L E S 13 | 14 | --debug 15 | gpbDebug boolean := false; 16 | gpnDebugLevel pls_integer := 1; 17 | 18 | --mode and version 19 | gpnMode pls_integer; 20 | gpnVersion pls_integer; 21 | 22 | --Error Correction Code Words and Block Information 23 | TYPE r_err_cor IS RECORD( 24 | total_no_of_data_cw pls_integer, 25 | ec_cw_per_block pls_integer, 26 | blocks_in_g1 pls_integer, 27 | cw_in_g1 pls_integer, 28 | blocks_in_g2 pls_integer, 29 | cw_in_g2 pls_integer); 30 | 31 | TYPE t_err_cor IS TABLE OF r_err_cor INDEX BY varchar2(10); 32 | 33 | gprErrCorInfo t_err_cor; 34 | 35 | --logs and antilogs 36 | TYPE t_log_anti IS TABLE OF pls_integer INDEX BY pls_integer; 37 | gprLog t_log_anti; 38 | gprAntiLog t_log_anti; 39 | 40 | --matrix 41 | TYPE t_row IS TABLE OF varchar2(1); 42 | TYPE t_column IS TABLE OF t_row; 43 | TYPE t_masking IS TABLE OF t_column INDEX BY pls_integer; 44 | 45 | gprMatrix t_column := t_column(); 46 | gprMasking t_masking; 47 | 48 | 49 | 50 | --DEBUG FUNCS AND PROCS 51 | PROCEDURE p_debug( 52 | p_text varchar2, 53 | p_level pls_integer default 1, 54 | p_new_line boolean default true) IS 55 | BEGIN 56 | if gpbDebug and p_level <= gpnDebugLevel then 57 | if p_new_line then 58 | DBMS_OUTPUT.put_line(p_text); 59 | else 60 | DBMS_OUTPUT.put(p_text); 61 | end if; 62 | end if; 63 | END; 64 | 65 | 66 | PROCEDURE p_dbms_output_matrix( 67 | p_matrix t_column, 68 | p_level pls_integer default 1) IS 69 | 70 | lcQR varchar2(200); 71 | 72 | BEGIN 73 | FOR t IN 1 .. p_matrix.count LOOP 74 | lcQR := null; 75 | FOR p IN 1 .. p_matrix.count LOOP 76 | lcQR := lcQR || nvl(p_matrix(t)(p), 'X'); 77 | END LOOP; 78 | p_debug(lcQR, p_level); 79 | END LOOP; 80 | END; 81 | 82 | 83 | --UTILITY FUNCS AND PROCS 84 | FUNCTION bitor(p1 number, p2 number) RETURN number IS 85 | BEGIN 86 | RETURN p1 - bitand(p1, p2) + p2; 87 | END; 88 | 89 | FUNCTION bitxor(p1 number, p2 number) RETURN number IS 90 | BEGIN 91 | RETURN bitor(p1, p2) - bitand(p1, p2); 92 | END; 93 | 94 | FUNCTION bin2dec(p_binval varchar2) RETURN pls_integer IS 95 | lnResult number := 0; 96 | BEGIN 97 | FOR t IN 1 .. length(p_binval) LOOP 98 | lnResult := (lnResult * 2) + to_number(substr(p_binval, t, 1)); 99 | END LOOP; 100 | 101 | RETURN lnResult; 102 | END bin2dec; 103 | 104 | /* 105 | FUNCTION f_integer_2_binary(p_integer pls_integer) RETURN varchar2 IS 106 | lcBinary varchar2(100); 107 | BEGIN 108 | SELECT LISTAGG(SIGN(BITAND(p_integer, POWER(2, LEVEL-1))),'') WITHIN GROUP(ORDER BY LEVEL DESC) 109 | INTO lcBinary 110 | FROM dual 111 | CONNECT BY POWER(2, LEVEL-1) <= p_integer; 112 | 113 | RETURN lcBinary; 114 | END; 115 | */ 116 | 117 | --function changed to pure PL/SQL version 118 | --also compatible with older databases (10g) 119 | FUNCTION f_integer_2_binary(p_integer pls_integer) RETURN varchar2 IS 120 | lcBinary varchar2(100); 121 | lnTemp number := p_integer; 122 | 123 | BEGIN 124 | if p_integer <> 0 then 125 | WHILE ( lnTemp > 0 ) LOOP 126 | lcBinary := mod(lnTemp, 2) || lcBinary; 127 | lnTemp := trunc( lnTemp / 2 ); 128 | END LOOP; 129 | else 130 | lcBinary := '0'; 131 | end if; 132 | 133 | RETURN lcBinary; 134 | END f_integer_2_binary; 135 | 136 | 137 | --INIT FUNCS AND PROCS 138 | PROCEDURE p_fill_log_antilog IS 139 | lnVal pls_integer; 140 | lnPrevVal pls_integer; 141 | BEGIN 142 | FOR t IN 0 .. 255 LOOP 143 | if t = 0 then 144 | lnVal := 1; 145 | else 146 | lnVal := lnPrevVal * 2; 147 | if lnVal > 255 then 148 | lnVal := bitxor(lnVal, 285); 149 | end if; 150 | end if; 151 | 152 | gprLog(t) := lnVal; 153 | gprAntiLog(lnVal) := t; 154 | 155 | lnPrevVal := lnVal; 156 | 157 | p_debug('Log for ' || t || ': ' || gprLog(t), 4); 158 | 159 | END LOOP; 160 | END; 161 | 162 | FUNCTION f_matrix_size RETURN pls_integer IS 163 | BEGIN 164 | --minimal matrix size is 21x21 module; every next version is 4 modules larger 165 | RETURN ((gpnVersion - 1) * 4) + 21; 166 | END; 167 | 168 | 169 | 170 | PROCEDURE p_init_matrix IS 171 | 172 | TYPE t_col IS TABLE OF pls_integer; 173 | TYPE t_alignment_pos IS TABLE OF t_col; 174 | lrAlignPos t_alignment_pos := t_alignment_pos(); 175 | 176 | lcModule varchar2(1); 177 | 178 | PROCEDURE p_add_finder(p_column pls_integer, p_row pls_integer) IS 179 | BEGIN 180 | --outer black square 181 | FOR t IN 0 .. 6 LOOP 182 | gprMatrix(p_column + t)(p_row) := '3'; 183 | gprMatrix(p_column + t)(p_row + 6) := '3'; 184 | gprMatrix(p_column)(p_row + t) := '3'; 185 | gprMatrix(p_column + 6)(p_row + t) := '3'; 186 | END LOOP; 187 | 188 | --inner white square 189 | FOR t IN 0 .. 4 LOOP 190 | gprMatrix(p_column + 1 + t)(p_row + 1) := '2'; 191 | gprMatrix(p_column + 1 + t)(p_row + 1 + 4) := '2'; 192 | gprMatrix(p_column + 1)(p_row + 1 + t) := '2'; 193 | gprMatrix(p_column + 1 + 4)(p_row + 1 + t) := '2'; 194 | END LOOP; 195 | 196 | --inner black square 197 | FOR t IN 0 .. 2 LOOP 198 | FOR p IN 0 .. 2 LOOP 199 | gprMatrix(p_column + 2 + t)(p_row + 2 + p) := '3'; 200 | END LOOP; 201 | END LOOP; 202 | 203 | END; 204 | 205 | PROCEDURE p_init_alignment IS 206 | BEGIN 207 | lrAlignPos.delete; 208 | lrAlignPos.extend(40); 209 | 210 | lrAlignPos(1) := t_col(0); 211 | lrAlignPos(2) := t_col(6, 18); 212 | lrAlignPos(3) := t_col(6, 22); 213 | lrAlignPos(4) := t_col(6, 26); 214 | lrAlignPos(5) := t_col(6, 30); 215 | lrAlignPos(6) := t_col(6, 34); 216 | lrAlignPos(7) := t_col(6, 22, 38); 217 | lrAlignPos(8) := t_col(6, 24, 42); 218 | lrAlignPos(9) := t_col(6, 26, 46); 219 | lrAlignPos(10) := t_col(6, 28, 50); 220 | lrAlignPos(11) := t_col(6, 30, 54); 221 | lrAlignPos(12) := t_col(6, 32, 58); 222 | lrAlignPos(13) := t_col(6, 34, 62); 223 | lrAlignPos(14) := t_col(6, 26, 46, 66); 224 | lrAlignPos(15) := t_col(6, 26, 48, 70); 225 | lrAlignPos(16) := t_col(6, 26, 50, 74); 226 | lrAlignPos(17) := t_col(6, 30, 54, 78); 227 | lrAlignPos(18) := t_col(6, 30, 56, 82); 228 | lrAlignPos(19) := t_col(6, 30, 58, 86); 229 | lrAlignPos(20) := t_col(6, 34, 62, 90); 230 | lrAlignPos(21) := t_col(6, 28, 50, 72, 94); 231 | lrAlignPos(22) := t_col(6, 26, 50, 74, 98); 232 | lrAlignPos(23) := t_col(6, 30, 54, 78, 102); 233 | lrAlignPos(24) := t_col(6, 28, 54, 80, 106); 234 | lrAlignPos(25) := t_col(6, 32, 58, 84, 110); 235 | lrAlignPos(26) := t_col(6, 30, 58, 86, 114); 236 | lrAlignPos(27) := t_col(6, 34, 62, 90, 118); 237 | lrAlignPos(28) := t_col(6, 26, 50, 74, 98, 122 ); 238 | lrAlignPos(29) := t_col(6, 30, 54, 78, 102, 126); 239 | lrAlignPos(30) := t_col(6, 26, 52, 78, 104, 130 ); 240 | lrAlignPos(31) := t_col(6, 30, 56, 82, 108, 134 ); 241 | lrAlignPos(32) := t_col(6, 34, 60, 86, 112, 138 ); 242 | lrAlignPos(33) := t_col(6, 30, 58, 86, 114, 142 ); 243 | lrAlignPos(34) := t_col(6, 34, 62, 90, 118, 146 ); 244 | lrAlignPos(35) := t_col(6, 30, 54, 78, 102, 126, 150); 245 | lrAlignPos(36) := t_col(6, 24, 50, 76, 102, 128, 154); 246 | lrAlignPos(37) := t_col(6, 28, 54, 80, 106, 132, 158); 247 | lrAlignPos(38) := t_col(6, 32, 58, 84, 110, 136, 162); 248 | lrAlignPos(39) := t_col(6, 26, 54, 82, 110, 138, 166); 249 | lrAlignPos(40) := t_col(6, 30, 58, 86, 114, 142, 170); 250 | 251 | END; 252 | 253 | PROCEDURE p_add_alignment(p_column pls_integer, p_row pls_integer) IS 254 | BEGIN 255 | --check if coordinates are OK and alignment is on matrix 256 | if p_column - 2 < 1 or p_column + 2 > f_matrix_size or p_row - 2 < 1 or p_row + 2 > f_matrix_size then 257 | p_debug('Alignment on ' || p_column || ', ' || p_row || ' is outside of matrix! Skipping...', 2); 258 | RETURN; 259 | end if; 260 | 261 | --first check if overlap with existing finders; if overlaps then do not draw finder 262 | FOR t IN p_column - 2 .. p_column + 2 LOOP 263 | FOR p IN p_row - 2 .. p_row + 2 LOOP 264 | if gprMatrix(p)(t) is not null then 265 | p_debug('Alignment on ' || p_column || ', ' || p_row || ' overlaps with finder! Skipping...', 2); 266 | RETURN; 267 | end if; 268 | END LOOP; 269 | END LOOP; 270 | 271 | --draw alignment 272 | --outer black square 273 | FOR t IN 0 .. 4 LOOP 274 | gprMatrix(p_row - 2)(p_column - 2 + t) := '3'; 275 | gprMatrix(p_row - 2 + t)(p_column - 2) := '3'; 276 | gprMatrix(p_row + 2)(p_column - 2 + t) := '3'; 277 | gprMatrix(p_row - 2 + t)(p_column + 2) := '3'; 278 | END LOOP; 279 | 280 | --inner white square and center module 281 | FOR t IN 0 .. 2 LOOP 282 | FOR p IN 0 .. 2 LOOP 283 | gprMatrix(p_row - 1 + t)(p_column - 1 + p) := '2'; 284 | END LOOP; 285 | END LOOP; 286 | gprMatrix(p_row)(p_column) := '3'; 287 | 288 | 289 | END; 290 | 291 | BEGIN 292 | p_debug('Matrix size: ' || f_matrix_size || 'x' || f_matrix_size || ' modules', 2); 293 | 294 | --collection initialization 295 | gprMatrix.delete; 296 | 297 | gprMatrix.extend(f_matrix_size); 298 | FOR t IN 1 .. f_matrix_size LOOP 299 | gprMatrix(t) := t_row(); 300 | gprMatrix(t).extend(f_matrix_size); 301 | END LOOP; 302 | 303 | 304 | --add Finder Patterns (3x) 305 | p_add_finder(1, 1); 306 | p_add_finder(f_matrix_size - 6, 1); 307 | p_add_finder(1, f_matrix_size - 6); 308 | 309 | 310 | --add Separators 311 | FOR t IN 0 .. 7 LOOP 312 | --upper left 313 | gprMatrix(1 + t)(1 + 7) := '2'; 314 | gprMatrix(1 + 7)(1 + t) := '2'; 315 | 316 | --lower left 317 | gprMatrix(f_matrix_size - 7 + t)(1 + 7) := '2'; 318 | gprMatrix(f_matrix_size - 7)(1 + t) := '2'; 319 | 320 | --upper right 321 | gprMatrix(1 + t)(f_matrix_size - 7) := '2'; 322 | gprMatrix(1 + 7)(f_matrix_size - 7 + t) := '2'; 323 | END LOOP; 324 | 325 | 326 | --add Alignment Patterns (for versions larger then 1) 327 | p_init_alignment; 328 | 329 | if gpnVersion > 1 then 330 | FOR t IN 1 .. lrAlignPos(gpnVersion).count LOOP 331 | FOR p IN 1 .. lrAlignPos(gpnVersion).count LOOP 332 | p_add_alignment(lrAlignPos(gpnVersion)(t) + 1, lrAlignPos(gpnVersion)(p) + 1); 333 | END LOOP; 334 | END LOOP; 335 | end if; 336 | 337 | 338 | --Timing Patterns 339 | FOR t IN 9 .. f_matrix_size - 8 LOOP 340 | if t mod 2 <> 0 then 341 | lcModule := '3'; --first module is black, then white, then black... 342 | else 343 | lcModule := '2'; 344 | end if; 345 | 346 | gprMatrix(7)(t) := lcModule; 347 | gprMatrix(t)(7) := lcModule; 348 | END LOOP; 349 | 350 | 351 | --Dark Module 352 | gprMatrix(f_matrix_size - 7)(9) := '3'; 353 | 354 | --Reserved Areas (Format Information Area, Version Information Area) 355 | --will be filled with actual values later 356 | 357 | --Format Information Area, placeholder values are dots 358 | FOR t IN 1 .. 9 LOOP 359 | if gprMatrix(9)(t) is null then 360 | gprMatrix(9)(t) := '.'; 361 | end if; 362 | 363 | if gprMatrix(t)(9) is null then 364 | gprMatrix(t)(9) := '.'; 365 | end if; 366 | END LOOP; 367 | 368 | FOR t IN 1 .. 8 LOOP 369 | if gprMatrix(f_matrix_size - t + 1)(9) is null then 370 | gprMatrix(f_matrix_size - t + 1)(9) := '.'; 371 | end if; 372 | 373 | if gprMatrix(9)(f_matrix_size - t + 1) is null then 374 | gprMatrix(9)(f_matrix_size - t + 1) := '.'; 375 | end if; 376 | END LOOP; 377 | 378 | --Version Information Area, placeholder values are * 379 | --it aplies only to versions 7 and larger 380 | if gpnVersion >= 7 then 381 | FOR t IN 1 .. 6 LOOP 382 | gprMatrix(f_matrix_size - 8)(t) := '*'; 383 | gprMatrix(f_matrix_size - 9)(t) := '*'; 384 | gprMatrix(f_matrix_size - 10)(t) := '*'; 385 | 386 | gprMatrix(t)(f_matrix_size - 8) := '*'; 387 | gprMatrix(t)(f_matrix_size - 9) := '*'; 388 | gprMatrix(t)(f_matrix_size - 10) := '*'; 389 | 390 | END LOOP; 391 | end if; 392 | END; 393 | 394 | 395 | PROCEDURE p_fill_err_cor IS 396 | BEGIN 397 | gprErrCorInfo('1-L').total_no_of_data_cw := 19; gprErrCorInfo('1-L').ec_cw_per_block := 7; gprErrCorInfo('1-L').blocks_in_g1 := 1; gprErrCorInfo('1-L').cw_in_g1 := 19; gprErrCorInfo('1-L').blocks_in_g2 := null; gprErrCorInfo('1-L').cw_in_g2 := null; 398 | gprErrCorInfo('1-M').total_no_of_data_cw := 16; gprErrCorInfo('1-M').ec_cw_per_block := 10; gprErrCorInfo('1-M').blocks_in_g1 := 1; gprErrCorInfo('1-M').cw_in_g1 := 16; gprErrCorInfo('1-M').blocks_in_g2 := null; gprErrCorInfo('1-M').cw_in_g2 := null; 399 | gprErrCorInfo('1-Q').total_no_of_data_cw := 13; gprErrCorInfo('1-Q').ec_cw_per_block := 13; gprErrCorInfo('1-Q').blocks_in_g1 := 1; gprErrCorInfo('1-Q').cw_in_g1 := 13; gprErrCorInfo('1-Q').blocks_in_g2 := null; gprErrCorInfo('1-Q').cw_in_g2 := null; 400 | gprErrCorInfo('1-H').total_no_of_data_cw := 9; gprErrCorInfo('1-H').ec_cw_per_block := 17; gprErrCorInfo('1-H').blocks_in_g1 := 1; gprErrCorInfo('1-H').cw_in_g1 := 9; gprErrCorInfo('1-H').blocks_in_g2 := null; gprErrCorInfo('1-H').cw_in_g2 := null; 401 | gprErrCorInfo('2-L').total_no_of_data_cw := 34; gprErrCorInfo('2-L').ec_cw_per_block := 10; gprErrCorInfo('2-L').blocks_in_g1 := 1; gprErrCorInfo('2-L').cw_in_g1 := 34; gprErrCorInfo('2-L').blocks_in_g2 := null; gprErrCorInfo('2-L').cw_in_g2 := null; 402 | gprErrCorInfo('2-M').total_no_of_data_cw := 28; gprErrCorInfo('2-M').ec_cw_per_block := 16; gprErrCorInfo('2-M').blocks_in_g1 := 1; gprErrCorInfo('2-M').cw_in_g1 := 28; gprErrCorInfo('2-M').blocks_in_g2 := null; gprErrCorInfo('2-M').cw_in_g2 := null; 403 | gprErrCorInfo('2-Q').total_no_of_data_cw := 22; gprErrCorInfo('2-Q').ec_cw_per_block := 22; gprErrCorInfo('2-Q').blocks_in_g1 := 1; gprErrCorInfo('2-Q').cw_in_g1 := 22; gprErrCorInfo('2-Q').blocks_in_g2 := null; gprErrCorInfo('2-Q').cw_in_g2 := null; 404 | gprErrCorInfo('2-H').total_no_of_data_cw := 16; gprErrCorInfo('2-H').ec_cw_per_block := 28; gprErrCorInfo('2-H').blocks_in_g1 := 1; gprErrCorInfo('2-H').cw_in_g1 := 16; gprErrCorInfo('2-H').blocks_in_g2 := null; gprErrCorInfo('2-H').cw_in_g2 := null; 405 | gprErrCorInfo('3-L').total_no_of_data_cw := 55; gprErrCorInfo('3-L').ec_cw_per_block := 15; gprErrCorInfo('3-L').blocks_in_g1 := 1; gprErrCorInfo('3-L').cw_in_g1 := 55; gprErrCorInfo('3-L').blocks_in_g2 := null; gprErrCorInfo('3-L').cw_in_g2 := null; 406 | gprErrCorInfo('3-M').total_no_of_data_cw := 44; gprErrCorInfo('3-M').ec_cw_per_block := 26; gprErrCorInfo('3-M').blocks_in_g1 := 1; gprErrCorInfo('3-M').cw_in_g1 := 44; gprErrCorInfo('3-M').blocks_in_g2 := null; gprErrCorInfo('3-M').cw_in_g2 := null; 407 | gprErrCorInfo('3-Q').total_no_of_data_cw := 34; gprErrCorInfo('3-Q').ec_cw_per_block := 18; gprErrCorInfo('3-Q').blocks_in_g1 := 2; gprErrCorInfo('3-Q').cw_in_g1 := 17; gprErrCorInfo('3-Q').blocks_in_g2 := null; gprErrCorInfo('3-Q').cw_in_g2 := null; 408 | gprErrCorInfo('3-H').total_no_of_data_cw := 26; gprErrCorInfo('3-H').ec_cw_per_block := 22; gprErrCorInfo('3-H').blocks_in_g1 := 2; gprErrCorInfo('3-H').cw_in_g1 := 13; gprErrCorInfo('3-H').blocks_in_g2 := null; gprErrCorInfo('3-H').cw_in_g2 := null; 409 | gprErrCorInfo('4-L').total_no_of_data_cw := 80; gprErrCorInfo('4-L').ec_cw_per_block := 20; gprErrCorInfo('4-L').blocks_in_g1 := 1; gprErrCorInfo('4-L').cw_in_g1 := 80; gprErrCorInfo('4-L').blocks_in_g2 := null; gprErrCorInfo('4-L').cw_in_g2 := null; 410 | gprErrCorInfo('4-M').total_no_of_data_cw := 64; gprErrCorInfo('4-M').ec_cw_per_block := 18; gprErrCorInfo('4-M').blocks_in_g1 := 2; gprErrCorInfo('4-M').cw_in_g1 := 32; gprErrCorInfo('4-M').blocks_in_g2 := null; gprErrCorInfo('4-M').cw_in_g2 := null; 411 | gprErrCorInfo('4-Q').total_no_of_data_cw := 48; gprErrCorInfo('4-Q').ec_cw_per_block := 26; gprErrCorInfo('4-Q').blocks_in_g1 := 2; gprErrCorInfo('4-Q').cw_in_g1 := 24; gprErrCorInfo('4-Q').blocks_in_g2 := null; gprErrCorInfo('4-Q').cw_in_g2 := null; 412 | gprErrCorInfo('4-H').total_no_of_data_cw := 36; gprErrCorInfo('4-H').ec_cw_per_block := 16; gprErrCorInfo('4-H').blocks_in_g1 := 4; gprErrCorInfo('4-H').cw_in_g1 := 9; gprErrCorInfo('4-H').blocks_in_g2 := null; gprErrCorInfo('4-H').cw_in_g2 := null; 413 | gprErrCorInfo('5-L').total_no_of_data_cw := 108; gprErrCorInfo('5-L').ec_cw_per_block := 26; gprErrCorInfo('5-L').blocks_in_g1 := 1; gprErrCorInfo('5-L').cw_in_g1 := 108; gprErrCorInfo('5-L').blocks_in_g2 := null; gprErrCorInfo('5-L').cw_in_g2 := null; 414 | gprErrCorInfo('5-M').total_no_of_data_cw := 86; gprErrCorInfo('5-M').ec_cw_per_block := 24; gprErrCorInfo('5-M').blocks_in_g1 := 2; gprErrCorInfo('5-M').cw_in_g1 := 43; gprErrCorInfo('5-M').blocks_in_g2 := null; gprErrCorInfo('5-M').cw_in_g2 := null; 415 | gprErrCorInfo('5-Q').total_no_of_data_cw := 62; gprErrCorInfo('5-Q').ec_cw_per_block := 18; gprErrCorInfo('5-Q').blocks_in_g1 := 2; gprErrCorInfo('5-Q').cw_in_g1 := 15; gprErrCorInfo('5-Q').blocks_in_g2 := 2; gprErrCorInfo('5-Q').cw_in_g2 := 16; 416 | gprErrCorInfo('5-H').total_no_of_data_cw := 46; gprErrCorInfo('5-H').ec_cw_per_block := 22; gprErrCorInfo('5-H').blocks_in_g1 := 2; gprErrCorInfo('5-H').cw_in_g1 := 11; gprErrCorInfo('5-H').blocks_in_g2 := 2; gprErrCorInfo('5-H').cw_in_g2 := 12; 417 | gprErrCorInfo('6-L').total_no_of_data_cw := 136; gprErrCorInfo('6-L').ec_cw_per_block := 18; gprErrCorInfo('6-L').blocks_in_g1 := 2; gprErrCorInfo('6-L').cw_in_g1 := 68; gprErrCorInfo('6-L').blocks_in_g2 := null; gprErrCorInfo('6-L').cw_in_g2 := null; 418 | gprErrCorInfo('6-M').total_no_of_data_cw := 108; gprErrCorInfo('6-M').ec_cw_per_block := 16; gprErrCorInfo('6-M').blocks_in_g1 := 4; gprErrCorInfo('6-M').cw_in_g1 := 27; gprErrCorInfo('6-M').blocks_in_g2 := null; gprErrCorInfo('6-M').cw_in_g2 := null; 419 | gprErrCorInfo('6-Q').total_no_of_data_cw := 76; gprErrCorInfo('6-Q').ec_cw_per_block := 24; gprErrCorInfo('6-Q').blocks_in_g1 := 4; gprErrCorInfo('6-Q').cw_in_g1 := 19; gprErrCorInfo('6-Q').blocks_in_g2 := null; gprErrCorInfo('6-Q').cw_in_g2 := null; 420 | gprErrCorInfo('6-H').total_no_of_data_cw := 60; gprErrCorInfo('6-H').ec_cw_per_block := 28; gprErrCorInfo('6-H').blocks_in_g1 := 4; gprErrCorInfo('6-H').cw_in_g1 := 15; gprErrCorInfo('6-H').blocks_in_g2 := null; gprErrCorInfo('6-H').cw_in_g2 := null; 421 | gprErrCorInfo('7-L').total_no_of_data_cw := 156; gprErrCorInfo('7-L').ec_cw_per_block := 20; gprErrCorInfo('7-L').blocks_in_g1 := 2; gprErrCorInfo('7-L').cw_in_g1 := 78; gprErrCorInfo('7-L').blocks_in_g2 := null; gprErrCorInfo('7-L').cw_in_g2 := null; 422 | gprErrCorInfo('7-M').total_no_of_data_cw := 124; gprErrCorInfo('7-M').ec_cw_per_block := 18; gprErrCorInfo('7-M').blocks_in_g1 := 4; gprErrCorInfo('7-M').cw_in_g1 := 31; gprErrCorInfo('7-M').blocks_in_g2 := null; gprErrCorInfo('7-M').cw_in_g2 := null; 423 | gprErrCorInfo('7-Q').total_no_of_data_cw := 88; gprErrCorInfo('7-Q').ec_cw_per_block := 18; gprErrCorInfo('7-Q').blocks_in_g1 := 2; gprErrCorInfo('7-Q').cw_in_g1 := 14; gprErrCorInfo('7-Q').blocks_in_g2 := 4; gprErrCorInfo('7-Q').cw_in_g2 := 15; 424 | gprErrCorInfo('7-H').total_no_of_data_cw := 66; gprErrCorInfo('7-H').ec_cw_per_block := 26; gprErrCorInfo('7-H').blocks_in_g1 := 4; gprErrCorInfo('7-H').cw_in_g1 := 13; gprErrCorInfo('7-H').blocks_in_g2 := 1; gprErrCorInfo('7-H').cw_in_g2 := 14; 425 | gprErrCorInfo('8-L').total_no_of_data_cw := 194; gprErrCorInfo('8-L').ec_cw_per_block := 24; gprErrCorInfo('8-L').blocks_in_g1 := 2; gprErrCorInfo('8-L').cw_in_g1 := 97; gprErrCorInfo('8-L').blocks_in_g2 := null; gprErrCorInfo('8-L').cw_in_g2 := null; 426 | gprErrCorInfo('8-M').total_no_of_data_cw := 154; gprErrCorInfo('8-M').ec_cw_per_block := 22; gprErrCorInfo('8-M').blocks_in_g1 := 2; gprErrCorInfo('8-M').cw_in_g1 := 38; gprErrCorInfo('8-M').blocks_in_g2 := 2; gprErrCorInfo('8-M').cw_in_g2 := 39; 427 | gprErrCorInfo('8-Q').total_no_of_data_cw := 110; gprErrCorInfo('8-Q').ec_cw_per_block := 22; gprErrCorInfo('8-Q').blocks_in_g1 := 4; gprErrCorInfo('8-Q').cw_in_g1 := 18; gprErrCorInfo('8-Q').blocks_in_g2 := 2; gprErrCorInfo('8-Q').cw_in_g2 := 19; 428 | gprErrCorInfo('8-H').total_no_of_data_cw := 86; gprErrCorInfo('8-H').ec_cw_per_block := 26; gprErrCorInfo('8-H').blocks_in_g1 := 4; gprErrCorInfo('8-H').cw_in_g1 := 14; gprErrCorInfo('8-H').blocks_in_g2 := 2; gprErrCorInfo('8-H').cw_in_g2 := 15; 429 | gprErrCorInfo('9-L').total_no_of_data_cw := 232; gprErrCorInfo('9-L').ec_cw_per_block := 30; gprErrCorInfo('9-L').blocks_in_g1 := 2; gprErrCorInfo('9-L').cw_in_g1 := 116; gprErrCorInfo('9-L').blocks_in_g2 := null; gprErrCorInfo('9-L').cw_in_g2 := null; 430 | gprErrCorInfo('9-M').total_no_of_data_cw := 182; gprErrCorInfo('9-M').ec_cw_per_block := 22; gprErrCorInfo('9-M').blocks_in_g1 := 3; gprErrCorInfo('9-M').cw_in_g1 := 36; gprErrCorInfo('9-M').blocks_in_g2 := 2; gprErrCorInfo('9-M').cw_in_g2 := 37; 431 | gprErrCorInfo('9-Q').total_no_of_data_cw := 132; gprErrCorInfo('9-Q').ec_cw_per_block := 20; gprErrCorInfo('9-Q').blocks_in_g1 := 4; gprErrCorInfo('9-Q').cw_in_g1 := 16; gprErrCorInfo('9-Q').blocks_in_g2 := 4; gprErrCorInfo('9-Q').cw_in_g2 := 17; 432 | gprErrCorInfo('9-H').total_no_of_data_cw := 100; gprErrCorInfo('9-H').ec_cw_per_block := 24; gprErrCorInfo('9-H').blocks_in_g1 := 4; gprErrCorInfo('9-H').cw_in_g1 := 12; gprErrCorInfo('9-H').blocks_in_g2 := 4; gprErrCorInfo('9-H').cw_in_g2 := 13; 433 | gprErrCorInfo('10-L').total_no_of_data_cw := 274; gprErrCorInfo('10-L').ec_cw_per_block := 18; gprErrCorInfo('10-L').blocks_in_g1 := 2; gprErrCorInfo('10-L').cw_in_g1 := 68; gprErrCorInfo('10-L').blocks_in_g2 := 2; gprErrCorInfo('10-L').cw_in_g2 := 69; 434 | gprErrCorInfo('10-M').total_no_of_data_cw := 216; gprErrCorInfo('10-M').ec_cw_per_block := 26; gprErrCorInfo('10-M').blocks_in_g1 := 4; gprErrCorInfo('10-M').cw_in_g1 := 43; gprErrCorInfo('10-M').blocks_in_g2 := 1; gprErrCorInfo('10-M').cw_in_g2 := 44; 435 | gprErrCorInfo('10-Q').total_no_of_data_cw := 154; gprErrCorInfo('10-Q').ec_cw_per_block := 24; gprErrCorInfo('10-Q').blocks_in_g1 := 6; gprErrCorInfo('10-Q').cw_in_g1 := 19; gprErrCorInfo('10-Q').blocks_in_g2 := 2; gprErrCorInfo('10-Q').cw_in_g2 := 20; 436 | gprErrCorInfo('10-H').total_no_of_data_cw := 122; gprErrCorInfo('10-H').ec_cw_per_block := 28; gprErrCorInfo('10-H').blocks_in_g1 := 6; gprErrCorInfo('10-H').cw_in_g1 := 15; gprErrCorInfo('10-H').blocks_in_g2 := 2; gprErrCorInfo('10-H').cw_in_g2 := 16; 437 | gprErrCorInfo('11-L').total_no_of_data_cw := 324; gprErrCorInfo('11-L').ec_cw_per_block := 20; gprErrCorInfo('11-L').blocks_in_g1 := 4; gprErrCorInfo('11-L').cw_in_g1 := 81; gprErrCorInfo('11-L').blocks_in_g2 := null; gprErrCorInfo('11-L').cw_in_g2 := null; 438 | gprErrCorInfo('11-M').total_no_of_data_cw := 254; gprErrCorInfo('11-M').ec_cw_per_block := 30; gprErrCorInfo('11-M').blocks_in_g1 := 1; gprErrCorInfo('11-M').cw_in_g1 := 50; gprErrCorInfo('11-M').blocks_in_g2 := 4; gprErrCorInfo('11-M').cw_in_g2 := 51; 439 | gprErrCorInfo('11-Q').total_no_of_data_cw := 180; gprErrCorInfo('11-Q').ec_cw_per_block := 28; gprErrCorInfo('11-Q').blocks_in_g1 := 4; gprErrCorInfo('11-Q').cw_in_g1 := 22; gprErrCorInfo('11-Q').blocks_in_g2 := 4; gprErrCorInfo('11-Q').cw_in_g2 := 23; 440 | gprErrCorInfo('11-H').total_no_of_data_cw := 140; gprErrCorInfo('11-H').ec_cw_per_block := 24; gprErrCorInfo('11-H').blocks_in_g1 := 3; gprErrCorInfo('11-H').cw_in_g1 := 12; gprErrCorInfo('11-H').blocks_in_g2 := 8; gprErrCorInfo('11-H').cw_in_g2 := 13; 441 | gprErrCorInfo('12-L').total_no_of_data_cw := 370; gprErrCorInfo('12-L').ec_cw_per_block := 24; gprErrCorInfo('12-L').blocks_in_g1 := 2; gprErrCorInfo('12-L').cw_in_g1 := 92; gprErrCorInfo('12-L').blocks_in_g2 := 2; gprErrCorInfo('12-L').cw_in_g2 := 93; 442 | gprErrCorInfo('12-M').total_no_of_data_cw := 290; gprErrCorInfo('12-M').ec_cw_per_block := 22; gprErrCorInfo('12-M').blocks_in_g1 := 6; gprErrCorInfo('12-M').cw_in_g1 := 36; gprErrCorInfo('12-M').blocks_in_g2 := 2; gprErrCorInfo('12-M').cw_in_g2 := 37; 443 | gprErrCorInfo('12-Q').total_no_of_data_cw := 206; gprErrCorInfo('12-Q').ec_cw_per_block := 26; gprErrCorInfo('12-Q').blocks_in_g1 := 4; gprErrCorInfo('12-Q').cw_in_g1 := 20; gprErrCorInfo('12-Q').blocks_in_g2 := 6; gprErrCorInfo('12-Q').cw_in_g2 := 21; 444 | gprErrCorInfo('12-H').total_no_of_data_cw := 158; gprErrCorInfo('12-H').ec_cw_per_block := 28; gprErrCorInfo('12-H').blocks_in_g1 := 7; gprErrCorInfo('12-H').cw_in_g1 := 14; gprErrCorInfo('12-H').blocks_in_g2 := 4; gprErrCorInfo('12-H').cw_in_g2 := 15; 445 | gprErrCorInfo('13-L').total_no_of_data_cw := 428; gprErrCorInfo('13-L').ec_cw_per_block := 26; gprErrCorInfo('13-L').blocks_in_g1 := 4; gprErrCorInfo('13-L').cw_in_g1 := 107; gprErrCorInfo('13-L').blocks_in_g2 := null; gprErrCorInfo('13-L').cw_in_g2 := null; 446 | gprErrCorInfo('13-M').total_no_of_data_cw := 334; gprErrCorInfo('13-M').ec_cw_per_block := 22; gprErrCorInfo('13-M').blocks_in_g1 := 8; gprErrCorInfo('13-M').cw_in_g1 := 37; gprErrCorInfo('13-M').blocks_in_g2 := 1; gprErrCorInfo('13-M').cw_in_g2 := 38; 447 | gprErrCorInfo('13-Q').total_no_of_data_cw := 244; gprErrCorInfo('13-Q').ec_cw_per_block := 24; gprErrCorInfo('13-Q').blocks_in_g1 := 8; gprErrCorInfo('13-Q').cw_in_g1 := 20; gprErrCorInfo('13-Q').blocks_in_g2 := 4; gprErrCorInfo('13-Q').cw_in_g2 := 21; 448 | gprErrCorInfo('13-H').total_no_of_data_cw := 180; gprErrCorInfo('13-H').ec_cw_per_block := 22; gprErrCorInfo('13-H').blocks_in_g1 := 12; gprErrCorInfo('13-H').cw_in_g1 := 11; gprErrCorInfo('13-H').blocks_in_g2 := 4; gprErrCorInfo('13-H').cw_in_g2 := 12; 449 | gprErrCorInfo('14-L').total_no_of_data_cw := 461; gprErrCorInfo('14-L').ec_cw_per_block := 30; gprErrCorInfo('14-L').blocks_in_g1 := 3; gprErrCorInfo('14-L').cw_in_g1 := 115; gprErrCorInfo('14-L').blocks_in_g2 := 1; gprErrCorInfo('14-L').cw_in_g2 := 116; 450 | gprErrCorInfo('14-M').total_no_of_data_cw := 365; gprErrCorInfo('14-M').ec_cw_per_block := 24; gprErrCorInfo('14-M').blocks_in_g1 := 4; gprErrCorInfo('14-M').cw_in_g1 := 40; gprErrCorInfo('14-M').blocks_in_g2 := 5; gprErrCorInfo('14-M').cw_in_g2 := 41; 451 | gprErrCorInfo('14-Q').total_no_of_data_cw := 261; gprErrCorInfo('14-Q').ec_cw_per_block := 20; gprErrCorInfo('14-Q').blocks_in_g1 := 11; gprErrCorInfo('14-Q').cw_in_g1 := 16; gprErrCorInfo('14-Q').blocks_in_g2 := 5; gprErrCorInfo('14-Q').cw_in_g2 := 17; 452 | gprErrCorInfo('14-H').total_no_of_data_cw := 197; gprErrCorInfo('14-H').ec_cw_per_block := 24; gprErrCorInfo('14-H').blocks_in_g1 := 11; gprErrCorInfo('14-H').cw_in_g1 := 12; gprErrCorInfo('14-H').blocks_in_g2 := 5; gprErrCorInfo('14-H').cw_in_g2 := 13; 453 | gprErrCorInfo('15-L').total_no_of_data_cw := 523; gprErrCorInfo('15-L').ec_cw_per_block := 22; gprErrCorInfo('15-L').blocks_in_g1 := 5; gprErrCorInfo('15-L').cw_in_g1 := 87; gprErrCorInfo('15-L').blocks_in_g2 := 1; gprErrCorInfo('15-L').cw_in_g2 := 88; 454 | gprErrCorInfo('15-M').total_no_of_data_cw := 415; gprErrCorInfo('15-M').ec_cw_per_block := 24; gprErrCorInfo('15-M').blocks_in_g1 := 5; gprErrCorInfo('15-M').cw_in_g1 := 41; gprErrCorInfo('15-M').blocks_in_g2 := 5; gprErrCorInfo('15-M').cw_in_g2 := 42; 455 | gprErrCorInfo('15-Q').total_no_of_data_cw := 295; gprErrCorInfo('15-Q').ec_cw_per_block := 30; gprErrCorInfo('15-Q').blocks_in_g1 := 5; gprErrCorInfo('15-Q').cw_in_g1 := 24; gprErrCorInfo('15-Q').blocks_in_g2 := 7; gprErrCorInfo('15-Q').cw_in_g2 := 25; 456 | gprErrCorInfo('15-H').total_no_of_data_cw := 223; gprErrCorInfo('15-H').ec_cw_per_block := 24; gprErrCorInfo('15-H').blocks_in_g1 := 11; gprErrCorInfo('15-H').cw_in_g1 := 12; gprErrCorInfo('15-H').blocks_in_g2 := 7; gprErrCorInfo('15-H').cw_in_g2 := 13; 457 | gprErrCorInfo('16-L').total_no_of_data_cw := 589; gprErrCorInfo('16-L').ec_cw_per_block := 24; gprErrCorInfo('16-L').blocks_in_g1 := 5; gprErrCorInfo('16-L').cw_in_g1 := 98; gprErrCorInfo('16-L').blocks_in_g2 := 1; gprErrCorInfo('16-L').cw_in_g2 := 99; 458 | gprErrCorInfo('16-M').total_no_of_data_cw := 453; gprErrCorInfo('16-M').ec_cw_per_block := 28; gprErrCorInfo('16-M').blocks_in_g1 := 7; gprErrCorInfo('16-M').cw_in_g1 := 45; gprErrCorInfo('16-M').blocks_in_g2 := 3; gprErrCorInfo('16-M').cw_in_g2 := 46; 459 | gprErrCorInfo('16-Q').total_no_of_data_cw := 325; gprErrCorInfo('16-Q').ec_cw_per_block := 24; gprErrCorInfo('16-Q').blocks_in_g1 := 15; gprErrCorInfo('16-Q').cw_in_g1 := 19; gprErrCorInfo('16-Q').blocks_in_g2 := 2; gprErrCorInfo('16-Q').cw_in_g2 := 20; 460 | gprErrCorInfo('16-H').total_no_of_data_cw := 253; gprErrCorInfo('16-H').ec_cw_per_block := 30; gprErrCorInfo('16-H').blocks_in_g1 := 3; gprErrCorInfo('16-H').cw_in_g1 := 15; gprErrCorInfo('16-H').blocks_in_g2 := 13; gprErrCorInfo('16-H').cw_in_g2 := 16; 461 | gprErrCorInfo('17-L').total_no_of_data_cw := 647; gprErrCorInfo('17-L').ec_cw_per_block := 28; gprErrCorInfo('17-L').blocks_in_g1 := 1; gprErrCorInfo('17-L').cw_in_g1 := 107; gprErrCorInfo('17-L').blocks_in_g2 := 5; gprErrCorInfo('17-L').cw_in_g2 := 108; 462 | gprErrCorInfo('17-M').total_no_of_data_cw := 507; gprErrCorInfo('17-M').ec_cw_per_block := 28; gprErrCorInfo('17-M').blocks_in_g1 := 10; gprErrCorInfo('17-M').cw_in_g1 := 46; gprErrCorInfo('17-M').blocks_in_g2 := 1; gprErrCorInfo('17-M').cw_in_g2 := 47; 463 | gprErrCorInfo('17-Q').total_no_of_data_cw := 367; gprErrCorInfo('17-Q').ec_cw_per_block := 28; gprErrCorInfo('17-Q').blocks_in_g1 := 1; gprErrCorInfo('17-Q').cw_in_g1 := 22; gprErrCorInfo('17-Q').blocks_in_g2 := 15; gprErrCorInfo('17-Q').cw_in_g2 := 23; 464 | gprErrCorInfo('17-H').total_no_of_data_cw := 283; gprErrCorInfo('17-H').ec_cw_per_block := 28; gprErrCorInfo('17-H').blocks_in_g1 := 2; gprErrCorInfo('17-H').cw_in_g1 := 14; gprErrCorInfo('17-H').blocks_in_g2 := 17; gprErrCorInfo('17-H').cw_in_g2 := 15; 465 | gprErrCorInfo('18-L').total_no_of_data_cw := 721; gprErrCorInfo('18-L').ec_cw_per_block := 30; gprErrCorInfo('18-L').blocks_in_g1 := 5; gprErrCorInfo('18-L').cw_in_g1 := 120; gprErrCorInfo('18-L').blocks_in_g2 := 1; gprErrCorInfo('18-L').cw_in_g2 := 121; 466 | gprErrCorInfo('18-M').total_no_of_data_cw := 563; gprErrCorInfo('18-M').ec_cw_per_block := 26; gprErrCorInfo('18-M').blocks_in_g1 := 9; gprErrCorInfo('18-M').cw_in_g1 := 43; gprErrCorInfo('18-M').blocks_in_g2 := 4; gprErrCorInfo('18-M').cw_in_g2 := 44; 467 | gprErrCorInfo('18-Q').total_no_of_data_cw := 397; gprErrCorInfo('18-Q').ec_cw_per_block := 28; gprErrCorInfo('18-Q').blocks_in_g1 := 17; gprErrCorInfo('18-Q').cw_in_g1 := 22; gprErrCorInfo('18-Q').blocks_in_g2 := 1; gprErrCorInfo('18-Q').cw_in_g2 := 23; 468 | gprErrCorInfo('18-H').total_no_of_data_cw := 313; gprErrCorInfo('18-H').ec_cw_per_block := 28; gprErrCorInfo('18-H').blocks_in_g1 := 2; gprErrCorInfo('18-H').cw_in_g1 := 14; gprErrCorInfo('18-H').blocks_in_g2 := 19; gprErrCorInfo('18-H').cw_in_g2 := 15; 469 | gprErrCorInfo('19-L').total_no_of_data_cw := 795; gprErrCorInfo('19-L').ec_cw_per_block := 28; gprErrCorInfo('19-L').blocks_in_g1 := 3; gprErrCorInfo('19-L').cw_in_g1 := 113; gprErrCorInfo('19-L').blocks_in_g2 := 4; gprErrCorInfo('19-L').cw_in_g2 := 114; 470 | gprErrCorInfo('19-M').total_no_of_data_cw := 627; gprErrCorInfo('19-M').ec_cw_per_block := 26; gprErrCorInfo('19-M').blocks_in_g1 := 3; gprErrCorInfo('19-M').cw_in_g1 := 44; gprErrCorInfo('19-M').blocks_in_g2 := 11; gprErrCorInfo('19-M').cw_in_g2 := 45; 471 | gprErrCorInfo('19-Q').total_no_of_data_cw := 445; gprErrCorInfo('19-Q').ec_cw_per_block := 26; gprErrCorInfo('19-Q').blocks_in_g1 := 17; gprErrCorInfo('19-Q').cw_in_g1 := 21; gprErrCorInfo('19-Q').blocks_in_g2 := 4; gprErrCorInfo('19-Q').cw_in_g2 := 22; 472 | gprErrCorInfo('19-H').total_no_of_data_cw := 341; gprErrCorInfo('19-H').ec_cw_per_block := 26; gprErrCorInfo('19-H').blocks_in_g1 := 9; gprErrCorInfo('19-H').cw_in_g1 := 13; gprErrCorInfo('19-H').blocks_in_g2 := 16; gprErrCorInfo('19-H').cw_in_g2 := 14; 473 | gprErrCorInfo('20-L').total_no_of_data_cw := 861; gprErrCorInfo('20-L').ec_cw_per_block := 28; gprErrCorInfo('20-L').blocks_in_g1 := 3; gprErrCorInfo('20-L').cw_in_g1 := 107; gprErrCorInfo('20-L').blocks_in_g2 := 5; gprErrCorInfo('20-L').cw_in_g2 := 108; 474 | gprErrCorInfo('20-M').total_no_of_data_cw := 669; gprErrCorInfo('20-M').ec_cw_per_block := 26; gprErrCorInfo('20-M').blocks_in_g1 := 3; gprErrCorInfo('20-M').cw_in_g1 := 41; gprErrCorInfo('20-M').blocks_in_g2 := 13; gprErrCorInfo('20-M').cw_in_g2 := 42; 475 | gprErrCorInfo('20-Q').total_no_of_data_cw := 485; gprErrCorInfo('20-Q').ec_cw_per_block := 30; gprErrCorInfo('20-Q').blocks_in_g1 := 15; gprErrCorInfo('20-Q').cw_in_g1 := 24; gprErrCorInfo('20-Q').blocks_in_g2 := 5; gprErrCorInfo('20-Q').cw_in_g2 := 25; 476 | gprErrCorInfo('20-H').total_no_of_data_cw := 385; gprErrCorInfo('20-H').ec_cw_per_block := 28; gprErrCorInfo('20-H').blocks_in_g1 := 15; gprErrCorInfo('20-H').cw_in_g1 := 15; gprErrCorInfo('20-H').blocks_in_g2 := 10; gprErrCorInfo('20-H').cw_in_g2 := 16; 477 | gprErrCorInfo('21-L').total_no_of_data_cw := 932; gprErrCorInfo('21-L').ec_cw_per_block := 28; gprErrCorInfo('21-L').blocks_in_g1 := 4; gprErrCorInfo('21-L').cw_in_g1 := 116; gprErrCorInfo('21-L').blocks_in_g2 := 4; gprErrCorInfo('21-L').cw_in_g2 := 117; 478 | gprErrCorInfo('21-M').total_no_of_data_cw := 714; gprErrCorInfo('21-M').ec_cw_per_block := 26; gprErrCorInfo('21-M').blocks_in_g1 := 17; gprErrCorInfo('21-M').cw_in_g1 := 42; gprErrCorInfo('21-M').blocks_in_g2 := null; gprErrCorInfo('21-M').cw_in_g2 := null; 479 | gprErrCorInfo('21-Q').total_no_of_data_cw := 512; gprErrCorInfo('21-Q').ec_cw_per_block := 28; gprErrCorInfo('21-Q').blocks_in_g1 := 17; gprErrCorInfo('21-Q').cw_in_g1 := 22; gprErrCorInfo('21-Q').blocks_in_g2 := 6; gprErrCorInfo('21-Q').cw_in_g2 := 23; 480 | gprErrCorInfo('21-H').total_no_of_data_cw := 406; gprErrCorInfo('21-H').ec_cw_per_block := 30; gprErrCorInfo('21-H').blocks_in_g1 := 19; gprErrCorInfo('21-H').cw_in_g1 := 16; gprErrCorInfo('21-H').blocks_in_g2 := 6; gprErrCorInfo('21-H').cw_in_g2 := 17; 481 | gprErrCorInfo('22-L').total_no_of_data_cw := 1006; gprErrCorInfo('22-L').ec_cw_per_block := 28; gprErrCorInfo('22-L').blocks_in_g1 := 2; gprErrCorInfo('22-L').cw_in_g1 := 111; gprErrCorInfo('22-L').blocks_in_g2 := 7; gprErrCorInfo('22-L').cw_in_g2 := 112; 482 | gprErrCorInfo('22-M').total_no_of_data_cw := 782; gprErrCorInfo('22-M').ec_cw_per_block := 28; gprErrCorInfo('22-M').blocks_in_g1 := 17; gprErrCorInfo('22-M').cw_in_g1 := 46; gprErrCorInfo('22-M').blocks_in_g2 := null; gprErrCorInfo('22-M').cw_in_g2 := null; 483 | gprErrCorInfo('22-Q').total_no_of_data_cw := 568; gprErrCorInfo('22-Q').ec_cw_per_block := 30; gprErrCorInfo('22-Q').blocks_in_g1 := 7; gprErrCorInfo('22-Q').cw_in_g1 := 24; gprErrCorInfo('22-Q').blocks_in_g2 := 16; gprErrCorInfo('22-Q').cw_in_g2 := 25; 484 | gprErrCorInfo('22-H').total_no_of_data_cw := 442; gprErrCorInfo('22-H').ec_cw_per_block := 24; gprErrCorInfo('22-H').blocks_in_g1 := 34; gprErrCorInfo('22-H').cw_in_g1 := 13; gprErrCorInfo('22-H').blocks_in_g2 := null; gprErrCorInfo('22-H').cw_in_g2 := null; 485 | gprErrCorInfo('23-L').total_no_of_data_cw := 1094; gprErrCorInfo('23-L').ec_cw_per_block := 30; gprErrCorInfo('23-L').blocks_in_g1 := 4; gprErrCorInfo('23-L').cw_in_g1 := 121; gprErrCorInfo('23-L').blocks_in_g2 := 5; gprErrCorInfo('23-L').cw_in_g2 := 122; 486 | gprErrCorInfo('23-M').total_no_of_data_cw := 860; gprErrCorInfo('23-M').ec_cw_per_block := 28; gprErrCorInfo('23-M').blocks_in_g1 := 4; gprErrCorInfo('23-M').cw_in_g1 := 47; gprErrCorInfo('23-M').blocks_in_g2 := 14; gprErrCorInfo('23-M').cw_in_g2 := 48; 487 | gprErrCorInfo('23-Q').total_no_of_data_cw := 614; gprErrCorInfo('23-Q').ec_cw_per_block := 30; gprErrCorInfo('23-Q').blocks_in_g1 := 11; gprErrCorInfo('23-Q').cw_in_g1 := 24; gprErrCorInfo('23-Q').blocks_in_g2 := 14; gprErrCorInfo('23-Q').cw_in_g2 := 25; 488 | gprErrCorInfo('23-H').total_no_of_data_cw := 464; gprErrCorInfo('23-H').ec_cw_per_block := 30; gprErrCorInfo('23-H').blocks_in_g1 := 16; gprErrCorInfo('23-H').cw_in_g1 := 15; gprErrCorInfo('23-H').blocks_in_g2 := 14; gprErrCorInfo('23-H').cw_in_g2 := 16; 489 | gprErrCorInfo('24-L').total_no_of_data_cw := 1174; gprErrCorInfo('24-L').ec_cw_per_block := 30; gprErrCorInfo('24-L').blocks_in_g1 := 6; gprErrCorInfo('24-L').cw_in_g1 := 117; gprErrCorInfo('24-L').blocks_in_g2 := 4; gprErrCorInfo('24-L').cw_in_g2 := 118; 490 | gprErrCorInfo('24-M').total_no_of_data_cw := 914; gprErrCorInfo('24-M').ec_cw_per_block := 28; gprErrCorInfo('24-M').blocks_in_g1 := 6; gprErrCorInfo('24-M').cw_in_g1 := 45; gprErrCorInfo('24-M').blocks_in_g2 := 14; gprErrCorInfo('24-M').cw_in_g2 := 46; 491 | gprErrCorInfo('24-Q').total_no_of_data_cw := 664; gprErrCorInfo('24-Q').ec_cw_per_block := 30; gprErrCorInfo('24-Q').blocks_in_g1 := 11; gprErrCorInfo('24-Q').cw_in_g1 := 24; gprErrCorInfo('24-Q').blocks_in_g2 := 16; gprErrCorInfo('24-Q').cw_in_g2 := 25; 492 | gprErrCorInfo('24-H').total_no_of_data_cw := 514; gprErrCorInfo('24-H').ec_cw_per_block := 30; gprErrCorInfo('24-H').blocks_in_g1 := 30; gprErrCorInfo('24-H').cw_in_g1 := 16; gprErrCorInfo('24-H').blocks_in_g2 := 2; gprErrCorInfo('24-H').cw_in_g2 := 17; 493 | gprErrCorInfo('25-L').total_no_of_data_cw := 1276; gprErrCorInfo('25-L').ec_cw_per_block := 26; gprErrCorInfo('25-L').blocks_in_g1 := 8; gprErrCorInfo('25-L').cw_in_g1 := 106; gprErrCorInfo('25-L').blocks_in_g2 := 4; gprErrCorInfo('25-L').cw_in_g2 := 107; 494 | gprErrCorInfo('25-M').total_no_of_data_cw := 1000; gprErrCorInfo('25-M').ec_cw_per_block := 28; gprErrCorInfo('25-M').blocks_in_g1 := 8; gprErrCorInfo('25-M').cw_in_g1 := 47; gprErrCorInfo('25-M').blocks_in_g2 := 13; gprErrCorInfo('25-M').cw_in_g2 := 48; 495 | gprErrCorInfo('25-Q').total_no_of_data_cw := 718; gprErrCorInfo('25-Q').ec_cw_per_block := 30; gprErrCorInfo('25-Q').blocks_in_g1 := 7; gprErrCorInfo('25-Q').cw_in_g1 := 24; gprErrCorInfo('25-Q').blocks_in_g2 := 22; gprErrCorInfo('25-Q').cw_in_g2 := 25; 496 | gprErrCorInfo('25-H').total_no_of_data_cw := 538; gprErrCorInfo('25-H').ec_cw_per_block := 30; gprErrCorInfo('25-H').blocks_in_g1 := 22; gprErrCorInfo('25-H').cw_in_g1 := 15; gprErrCorInfo('25-H').blocks_in_g2 := 13; gprErrCorInfo('25-H').cw_in_g2 := 16; 497 | gprErrCorInfo('26-L').total_no_of_data_cw := 1370; gprErrCorInfo('26-L').ec_cw_per_block := 28; gprErrCorInfo('26-L').blocks_in_g1 := 10; gprErrCorInfo('26-L').cw_in_g1 := 114; gprErrCorInfo('26-L').blocks_in_g2 := 2; gprErrCorInfo('26-L').cw_in_g2 := 115; 498 | gprErrCorInfo('26-M').total_no_of_data_cw := 1062; gprErrCorInfo('26-M').ec_cw_per_block := 28; gprErrCorInfo('26-M').blocks_in_g1 := 19; gprErrCorInfo('26-M').cw_in_g1 := 46; gprErrCorInfo('26-M').blocks_in_g2 := 4; gprErrCorInfo('26-M').cw_in_g2 := 47; 499 | gprErrCorInfo('26-Q').total_no_of_data_cw := 754; gprErrCorInfo('26-Q').ec_cw_per_block := 28; gprErrCorInfo('26-Q').blocks_in_g1 := 28; gprErrCorInfo('26-Q').cw_in_g1 := 22; gprErrCorInfo('26-Q').blocks_in_g2 := 6; gprErrCorInfo('26-Q').cw_in_g2 := 23; 500 | gprErrCorInfo('26-H').total_no_of_data_cw := 596; gprErrCorInfo('26-H').ec_cw_per_block := 30; gprErrCorInfo('26-H').blocks_in_g1 := 33; gprErrCorInfo('26-H').cw_in_g1 := 16; gprErrCorInfo('26-H').blocks_in_g2 := 4; gprErrCorInfo('26-H').cw_in_g2 := 17; 501 | gprErrCorInfo('27-L').total_no_of_data_cw := 1468; gprErrCorInfo('27-L').ec_cw_per_block := 30; gprErrCorInfo('27-L').blocks_in_g1 := 8; gprErrCorInfo('27-L').cw_in_g1 := 122; gprErrCorInfo('27-L').blocks_in_g2 := 4; gprErrCorInfo('27-L').cw_in_g2 := 123; 502 | gprErrCorInfo('27-M').total_no_of_data_cw := 1128; gprErrCorInfo('27-M').ec_cw_per_block := 28; gprErrCorInfo('27-M').blocks_in_g1 := 22; gprErrCorInfo('27-M').cw_in_g1 := 45; gprErrCorInfo('27-M').blocks_in_g2 := 3; gprErrCorInfo('27-M').cw_in_g2 := 46; 503 | gprErrCorInfo('27-Q').total_no_of_data_cw := 808; gprErrCorInfo('27-Q').ec_cw_per_block := 30; gprErrCorInfo('27-Q').blocks_in_g1 := 8; gprErrCorInfo('27-Q').cw_in_g1 := 23; gprErrCorInfo('27-Q').blocks_in_g2 := 26; gprErrCorInfo('27-Q').cw_in_g2 := 24; 504 | gprErrCorInfo('27-H').total_no_of_data_cw := 628; gprErrCorInfo('27-H').ec_cw_per_block := 30; gprErrCorInfo('27-H').blocks_in_g1 := 12; gprErrCorInfo('27-H').cw_in_g1 := 15; gprErrCorInfo('27-H').blocks_in_g2 := 28; gprErrCorInfo('27-H').cw_in_g2 := 16; 505 | gprErrCorInfo('28-L').total_no_of_data_cw := 1531; gprErrCorInfo('28-L').ec_cw_per_block := 30; gprErrCorInfo('28-L').blocks_in_g1 := 3; gprErrCorInfo('28-L').cw_in_g1 := 117; gprErrCorInfo('28-L').blocks_in_g2 := 10; gprErrCorInfo('28-L').cw_in_g2 := 118; 506 | gprErrCorInfo('28-M').total_no_of_data_cw := 1193; gprErrCorInfo('28-M').ec_cw_per_block := 28; gprErrCorInfo('28-M').blocks_in_g1 := 3; gprErrCorInfo('28-M').cw_in_g1 := 45; gprErrCorInfo('28-M').blocks_in_g2 := 23; gprErrCorInfo('28-M').cw_in_g2 := 46; 507 | gprErrCorInfo('28-Q').total_no_of_data_cw := 871; gprErrCorInfo('28-Q').ec_cw_per_block := 30; gprErrCorInfo('28-Q').blocks_in_g1 := 4; gprErrCorInfo('28-Q').cw_in_g1 := 24; gprErrCorInfo('28-Q').blocks_in_g2 := 31; gprErrCorInfo('28-Q').cw_in_g2 := 25; 508 | gprErrCorInfo('28-H').total_no_of_data_cw := 661; gprErrCorInfo('28-H').ec_cw_per_block := 30; gprErrCorInfo('28-H').blocks_in_g1 := 11; gprErrCorInfo('28-H').cw_in_g1 := 15; gprErrCorInfo('28-H').blocks_in_g2 := 31; gprErrCorInfo('28-H').cw_in_g2 := 16; 509 | gprErrCorInfo('29-L').total_no_of_data_cw := 1631; gprErrCorInfo('29-L').ec_cw_per_block := 30; gprErrCorInfo('29-L').blocks_in_g1 := 7; gprErrCorInfo('29-L').cw_in_g1 := 116; gprErrCorInfo('29-L').blocks_in_g2 := 7; gprErrCorInfo('29-L').cw_in_g2 := 117; 510 | gprErrCorInfo('29-M').total_no_of_data_cw := 1267; gprErrCorInfo('29-M').ec_cw_per_block := 28; gprErrCorInfo('29-M').blocks_in_g1 := 21; gprErrCorInfo('29-M').cw_in_g1 := 45; gprErrCorInfo('29-M').blocks_in_g2 := 7; gprErrCorInfo('29-M').cw_in_g2 := 46; 511 | gprErrCorInfo('29-Q').total_no_of_data_cw := 911; gprErrCorInfo('29-Q').ec_cw_per_block := 30; gprErrCorInfo('29-Q').blocks_in_g1 := 1; gprErrCorInfo('29-Q').cw_in_g1 := 23; gprErrCorInfo('29-Q').blocks_in_g2 := 37; gprErrCorInfo('29-Q').cw_in_g2 := 24; 512 | gprErrCorInfo('29-H').total_no_of_data_cw := 701; gprErrCorInfo('29-H').ec_cw_per_block := 30; gprErrCorInfo('29-H').blocks_in_g1 := 19; gprErrCorInfo('29-H').cw_in_g1 := 15; gprErrCorInfo('29-H').blocks_in_g2 := 26; gprErrCorInfo('29-H').cw_in_g2 := 16; 513 | gprErrCorInfo('30-L').total_no_of_data_cw := 1735; gprErrCorInfo('30-L').ec_cw_per_block := 30; gprErrCorInfo('30-L').blocks_in_g1 := 5; gprErrCorInfo('30-L').cw_in_g1 := 115; gprErrCorInfo('30-L').blocks_in_g2 := 10; gprErrCorInfo('30-L').cw_in_g2 := 116; 514 | gprErrCorInfo('30-M').total_no_of_data_cw := 1373; gprErrCorInfo('30-M').ec_cw_per_block := 28; gprErrCorInfo('30-M').blocks_in_g1 := 19; gprErrCorInfo('30-M').cw_in_g1 := 47; gprErrCorInfo('30-M').blocks_in_g2 := 10; gprErrCorInfo('30-M').cw_in_g2 := 48; 515 | gprErrCorInfo('30-Q').total_no_of_data_cw := 985; gprErrCorInfo('30-Q').ec_cw_per_block := 30; gprErrCorInfo('30-Q').blocks_in_g1 := 15; gprErrCorInfo('30-Q').cw_in_g1 := 24; gprErrCorInfo('30-Q').blocks_in_g2 := 25; gprErrCorInfo('30-Q').cw_in_g2 := 25; 516 | gprErrCorInfo('30-H').total_no_of_data_cw := 745; gprErrCorInfo('30-H').ec_cw_per_block := 30; gprErrCorInfo('30-H').blocks_in_g1 := 23; gprErrCorInfo('30-H').cw_in_g1 := 15; gprErrCorInfo('30-H').blocks_in_g2 := 25; gprErrCorInfo('30-H').cw_in_g2 := 16; 517 | gprErrCorInfo('31-L').total_no_of_data_cw := 1843; gprErrCorInfo('31-L').ec_cw_per_block := 30; gprErrCorInfo('31-L').blocks_in_g1 := 13; gprErrCorInfo('31-L').cw_in_g1 := 115; gprErrCorInfo('31-L').blocks_in_g2 := 3; gprErrCorInfo('31-L').cw_in_g2 := 116; 518 | gprErrCorInfo('31-M').total_no_of_data_cw := 1455; gprErrCorInfo('31-M').ec_cw_per_block := 28; gprErrCorInfo('31-M').blocks_in_g1 := 2; gprErrCorInfo('31-M').cw_in_g1 := 46; gprErrCorInfo('31-M').blocks_in_g2 := 29; gprErrCorInfo('31-M').cw_in_g2 := 47; 519 | gprErrCorInfo('31-Q').total_no_of_data_cw := 1033; gprErrCorInfo('31-Q').ec_cw_per_block := 30; gprErrCorInfo('31-Q').blocks_in_g1 := 42; gprErrCorInfo('31-Q').cw_in_g1 := 24; gprErrCorInfo('31-Q').blocks_in_g2 := 1; gprErrCorInfo('31-Q').cw_in_g2 := 25; 520 | gprErrCorInfo('31-H').total_no_of_data_cw := 793; gprErrCorInfo('31-H').ec_cw_per_block := 30; gprErrCorInfo('31-H').blocks_in_g1 := 23; gprErrCorInfo('31-H').cw_in_g1 := 15; gprErrCorInfo('31-H').blocks_in_g2 := 28; gprErrCorInfo('31-H').cw_in_g2 := 16; 521 | gprErrCorInfo('32-L').total_no_of_data_cw := 1955; gprErrCorInfo('32-L').ec_cw_per_block := 30; gprErrCorInfo('32-L').blocks_in_g1 := 17; gprErrCorInfo('32-L').cw_in_g1 := 115; gprErrCorInfo('32-L').blocks_in_g2 := null; gprErrCorInfo('32-L').cw_in_g2 := null; 522 | gprErrCorInfo('32-M').total_no_of_data_cw := 1541; gprErrCorInfo('32-M').ec_cw_per_block := 28; gprErrCorInfo('32-M').blocks_in_g1 := 10; gprErrCorInfo('32-M').cw_in_g1 := 46; gprErrCorInfo('32-M').blocks_in_g2 := 23; gprErrCorInfo('32-M').cw_in_g2 := 47; 523 | gprErrCorInfo('32-Q').total_no_of_data_cw := 1115; gprErrCorInfo('32-Q').ec_cw_per_block := 30; gprErrCorInfo('32-Q').blocks_in_g1 := 10; gprErrCorInfo('32-Q').cw_in_g1 := 24; gprErrCorInfo('32-Q').blocks_in_g2 := 35; gprErrCorInfo('32-Q').cw_in_g2 := 25; 524 | gprErrCorInfo('32-H').total_no_of_data_cw := 845; gprErrCorInfo('32-H').ec_cw_per_block := 30; gprErrCorInfo('32-H').blocks_in_g1 := 19; gprErrCorInfo('32-H').cw_in_g1 := 15; gprErrCorInfo('32-H').blocks_in_g2 := 35; gprErrCorInfo('32-H').cw_in_g2 := 16; 525 | gprErrCorInfo('33-L').total_no_of_data_cw := 2071; gprErrCorInfo('33-L').ec_cw_per_block := 30; gprErrCorInfo('33-L').blocks_in_g1 := 17; gprErrCorInfo('33-L').cw_in_g1 := 115; gprErrCorInfo('33-L').blocks_in_g2 := 1; gprErrCorInfo('33-L').cw_in_g2 := 116; 526 | gprErrCorInfo('33-M').total_no_of_data_cw := 1631; gprErrCorInfo('33-M').ec_cw_per_block := 28; gprErrCorInfo('33-M').blocks_in_g1 := 14; gprErrCorInfo('33-M').cw_in_g1 := 46; gprErrCorInfo('33-M').blocks_in_g2 := 21; gprErrCorInfo('33-M').cw_in_g2 := 47; 527 | gprErrCorInfo('33-Q').total_no_of_data_cw := 1171; gprErrCorInfo('33-Q').ec_cw_per_block := 30; gprErrCorInfo('33-Q').blocks_in_g1 := 29; gprErrCorInfo('33-Q').cw_in_g1 := 24; gprErrCorInfo('33-Q').blocks_in_g2 := 19; gprErrCorInfo('33-Q').cw_in_g2 := 25; 528 | gprErrCorInfo('33-H').total_no_of_data_cw := 901; gprErrCorInfo('33-H').ec_cw_per_block := 30; gprErrCorInfo('33-H').blocks_in_g1 := 11; gprErrCorInfo('33-H').cw_in_g1 := 15; gprErrCorInfo('33-H').blocks_in_g2 := 46; gprErrCorInfo('33-H').cw_in_g2 := 16; 529 | gprErrCorInfo('34-L').total_no_of_data_cw := 2191; gprErrCorInfo('34-L').ec_cw_per_block := 30; gprErrCorInfo('34-L').blocks_in_g1 := 13; gprErrCorInfo('34-L').cw_in_g1 := 115; gprErrCorInfo('34-L').blocks_in_g2 := 6; gprErrCorInfo('34-L').cw_in_g2 := 116; 530 | gprErrCorInfo('34-M').total_no_of_data_cw := 1725; gprErrCorInfo('34-M').ec_cw_per_block := 28; gprErrCorInfo('34-M').blocks_in_g1 := 14; gprErrCorInfo('34-M').cw_in_g1 := 46; gprErrCorInfo('34-M').blocks_in_g2 := 23; gprErrCorInfo('34-M').cw_in_g2 := 47; 531 | gprErrCorInfo('34-Q').total_no_of_data_cw := 1231; gprErrCorInfo('34-Q').ec_cw_per_block := 30; gprErrCorInfo('34-Q').blocks_in_g1 := 44; gprErrCorInfo('34-Q').cw_in_g1 := 24; gprErrCorInfo('34-Q').blocks_in_g2 := 7; gprErrCorInfo('34-Q').cw_in_g2 := 25; 532 | gprErrCorInfo('34-H').total_no_of_data_cw := 961; gprErrCorInfo('34-H').ec_cw_per_block := 30; gprErrCorInfo('34-H').blocks_in_g1 := 59; gprErrCorInfo('34-H').cw_in_g1 := 16; gprErrCorInfo('34-H').blocks_in_g2 := 1; gprErrCorInfo('34-H').cw_in_g2 := 17; 533 | gprErrCorInfo('35-L').total_no_of_data_cw := 2306; gprErrCorInfo('35-L').ec_cw_per_block := 30; gprErrCorInfo('35-L').blocks_in_g1 := 12; gprErrCorInfo('35-L').cw_in_g1 := 121; gprErrCorInfo('35-L').blocks_in_g2 := 7; gprErrCorInfo('35-L').cw_in_g2 := 122; 534 | gprErrCorInfo('35-M').total_no_of_data_cw := 1812; gprErrCorInfo('35-M').ec_cw_per_block := 28; gprErrCorInfo('35-M').blocks_in_g1 := 12; gprErrCorInfo('35-M').cw_in_g1 := 47; gprErrCorInfo('35-M').blocks_in_g2 := 26; gprErrCorInfo('35-M').cw_in_g2 := 48; 535 | gprErrCorInfo('35-Q').total_no_of_data_cw := 1286; gprErrCorInfo('35-Q').ec_cw_per_block := 30; gprErrCorInfo('35-Q').blocks_in_g1 := 39; gprErrCorInfo('35-Q').cw_in_g1 := 24; gprErrCorInfo('35-Q').blocks_in_g2 := 14; gprErrCorInfo('35-Q').cw_in_g2 := 25; 536 | gprErrCorInfo('35-H').total_no_of_data_cw := 986; gprErrCorInfo('35-H').ec_cw_per_block := 30; gprErrCorInfo('35-H').blocks_in_g1 := 22; gprErrCorInfo('35-H').cw_in_g1 := 15; gprErrCorInfo('35-H').blocks_in_g2 := 41; gprErrCorInfo('35-H').cw_in_g2 := 16; 537 | gprErrCorInfo('36-L').total_no_of_data_cw := 2434; gprErrCorInfo('36-L').ec_cw_per_block := 30; gprErrCorInfo('36-L').blocks_in_g1 := 6; gprErrCorInfo('36-L').cw_in_g1 := 121; gprErrCorInfo('36-L').blocks_in_g2 := 14; gprErrCorInfo('36-L').cw_in_g2 := 122; 538 | gprErrCorInfo('36-M').total_no_of_data_cw := 1914; gprErrCorInfo('36-M').ec_cw_per_block := 28; gprErrCorInfo('36-M').blocks_in_g1 := 6; gprErrCorInfo('36-M').cw_in_g1 := 47; gprErrCorInfo('36-M').blocks_in_g2 := 34; gprErrCorInfo('36-M').cw_in_g2 := 48; 539 | gprErrCorInfo('36-Q').total_no_of_data_cw := 1354; gprErrCorInfo('36-Q').ec_cw_per_block := 30; gprErrCorInfo('36-Q').blocks_in_g1 := 46; gprErrCorInfo('36-Q').cw_in_g1 := 24; gprErrCorInfo('36-Q').blocks_in_g2 := 10; gprErrCorInfo('36-Q').cw_in_g2 := 25; 540 | gprErrCorInfo('36-H').total_no_of_data_cw := 1054; gprErrCorInfo('36-H').ec_cw_per_block := 30; gprErrCorInfo('36-H').blocks_in_g1 := 2; gprErrCorInfo('36-H').cw_in_g1 := 15; gprErrCorInfo('36-H').blocks_in_g2 := 64; gprErrCorInfo('36-H').cw_in_g2 := 16; 541 | gprErrCorInfo('37-L').total_no_of_data_cw := 2566; gprErrCorInfo('37-L').ec_cw_per_block := 30; gprErrCorInfo('37-L').blocks_in_g1 := 17; gprErrCorInfo('37-L').cw_in_g1 := 122; gprErrCorInfo('37-L').blocks_in_g2 := 4; gprErrCorInfo('37-L').cw_in_g2 := 123; 542 | gprErrCorInfo('37-M').total_no_of_data_cw := 1992; gprErrCorInfo('37-M').ec_cw_per_block := 28; gprErrCorInfo('37-M').blocks_in_g1 := 29; gprErrCorInfo('37-M').cw_in_g1 := 46; gprErrCorInfo('37-M').blocks_in_g2 := 14; gprErrCorInfo('37-M').cw_in_g2 := 47; 543 | gprErrCorInfo('37-Q').total_no_of_data_cw := 1426; gprErrCorInfo('37-Q').ec_cw_per_block := 30; gprErrCorInfo('37-Q').blocks_in_g1 := 49; gprErrCorInfo('37-Q').cw_in_g1 := 24; gprErrCorInfo('37-Q').blocks_in_g2 := 10; gprErrCorInfo('37-Q').cw_in_g2 := 25; 544 | gprErrCorInfo('37-H').total_no_of_data_cw := 1096; gprErrCorInfo('37-H').ec_cw_per_block := 30; gprErrCorInfo('37-H').blocks_in_g1 := 24; gprErrCorInfo('37-H').cw_in_g1 := 15; gprErrCorInfo('37-H').blocks_in_g2 := 46; gprErrCorInfo('37-H').cw_in_g2 := 16; 545 | gprErrCorInfo('38-L').total_no_of_data_cw := 2702; gprErrCorInfo('38-L').ec_cw_per_block := 30; gprErrCorInfo('38-L').blocks_in_g1 := 4; gprErrCorInfo('38-L').cw_in_g1 := 122; gprErrCorInfo('38-L').blocks_in_g2 := 18; gprErrCorInfo('38-L').cw_in_g2 := 123; 546 | gprErrCorInfo('38-M').total_no_of_data_cw := 2102; gprErrCorInfo('38-M').ec_cw_per_block := 28; gprErrCorInfo('38-M').blocks_in_g1 := 13; gprErrCorInfo('38-M').cw_in_g1 := 46; gprErrCorInfo('38-M').blocks_in_g2 := 32; gprErrCorInfo('38-M').cw_in_g2 := 47; 547 | gprErrCorInfo('38-Q').total_no_of_data_cw := 1502; gprErrCorInfo('38-Q').ec_cw_per_block := 30; gprErrCorInfo('38-Q').blocks_in_g1 := 48; gprErrCorInfo('38-Q').cw_in_g1 := 24; gprErrCorInfo('38-Q').blocks_in_g2 := 14; gprErrCorInfo('38-Q').cw_in_g2 := 25; 548 | gprErrCorInfo('38-H').total_no_of_data_cw := 1142; gprErrCorInfo('38-H').ec_cw_per_block := 30; gprErrCorInfo('38-H').blocks_in_g1 := 42; gprErrCorInfo('38-H').cw_in_g1 := 15; gprErrCorInfo('38-H').blocks_in_g2 := 32; gprErrCorInfo('38-H').cw_in_g2 := 16; 549 | gprErrCorInfo('39-L').total_no_of_data_cw := 2812; gprErrCorInfo('39-L').ec_cw_per_block := 30; gprErrCorInfo('39-L').blocks_in_g1 := 20; gprErrCorInfo('39-L').cw_in_g1 := 117; gprErrCorInfo('39-L').blocks_in_g2 := 4; gprErrCorInfo('39-L').cw_in_g2 := 118; 550 | gprErrCorInfo('39-M').total_no_of_data_cw := 2216; gprErrCorInfo('39-M').ec_cw_per_block := 28; gprErrCorInfo('39-M').blocks_in_g1 := 40; gprErrCorInfo('39-M').cw_in_g1 := 47; gprErrCorInfo('39-M').blocks_in_g2 := 7; gprErrCorInfo('39-M').cw_in_g2 := 48; 551 | gprErrCorInfo('39-Q').total_no_of_data_cw := 1582; gprErrCorInfo('39-Q').ec_cw_per_block := 30; gprErrCorInfo('39-Q').blocks_in_g1 := 43; gprErrCorInfo('39-Q').cw_in_g1 := 24; gprErrCorInfo('39-Q').blocks_in_g2 := 22; gprErrCorInfo('39-Q').cw_in_g2 := 25; 552 | gprErrCorInfo('39-H').total_no_of_data_cw := 1222; gprErrCorInfo('39-H').ec_cw_per_block := 30; gprErrCorInfo('39-H').blocks_in_g1 := 10; gprErrCorInfo('39-H').cw_in_g1 := 15; gprErrCorInfo('39-H').blocks_in_g2 := 67; gprErrCorInfo('39-H').cw_in_g2 := 16; 553 | gprErrCorInfo('40-L').total_no_of_data_cw := 2956; gprErrCorInfo('40-L').ec_cw_per_block := 30; gprErrCorInfo('40-L').blocks_in_g1 := 19; gprErrCorInfo('40-L').cw_in_g1 := 118; gprErrCorInfo('40-L').blocks_in_g2 := 6; gprErrCorInfo('40-L').cw_in_g2 := 119; 554 | gprErrCorInfo('40-M').total_no_of_data_cw := 2334; gprErrCorInfo('40-M').ec_cw_per_block := 28; gprErrCorInfo('40-M').blocks_in_g1 := 18; gprErrCorInfo('40-M').cw_in_g1 := 47; gprErrCorInfo('40-M').blocks_in_g2 := 31; gprErrCorInfo('40-M').cw_in_g2 := 48; 555 | gprErrCorInfo('40-Q').total_no_of_data_cw := 1666; gprErrCorInfo('40-Q').ec_cw_per_block := 30; gprErrCorInfo('40-Q').blocks_in_g1 := 34; gprErrCorInfo('40-Q').cw_in_g1 := 24; gprErrCorInfo('40-Q').blocks_in_g2 := 34; gprErrCorInfo('40-Q').cw_in_g2 := 25; 556 | gprErrCorInfo('40-H').total_no_of_data_cw := 1276; gprErrCorInfo('40-H').ec_cw_per_block := 30; gprErrCorInfo('40-H').blocks_in_g1 := 20; gprErrCorInfo('40-H').cw_in_g1 := 15; gprErrCorInfo('40-H').blocks_in_g2 := 61; gprErrCorInfo('40-H').cw_in_g2 := 16; 557 | END; 558 | 559 | 560 | --CALCULATION FUNC AND PROC 561 | 562 | FUNCTION f_mode_name(p_type pls_integer) RETURN varchar2 IS 563 | lcMode varchar2(50); 564 | BEGIN 565 | lcMode := 566 | CASE p_type 567 | WHEN cNumericMode THEN 'Numeric Mode' 568 | WHEN cAlphanumericMode THEN 'Alphanumeric Mode' 569 | WHEN cByteMode THEN 'Byte Mode' 570 | WHEN cKanjiMode THEN 'Kanji mode' 571 | ELSE null 572 | END; 573 | 574 | RETURN lcMode; 575 | END; 576 | 577 | 578 | 579 | /* 580 | function returns QR code mode depending of data going to be encoded: 581 | 1 - Numeric mode (for decimal digits 0 through 9) 582 | 2 - Alphanumeric mode (specific table encoded in this function) 583 | 3 - Byte mode (ISO-8859-1 character set or UTF-8) 584 | 4 - Double-byte mode (Kanji) 585 | 586 | UTF-8 ascii values for kanji: 587 | 3000 - 303f: Japanese-style punctuation 588 | 3040 - 309f: Hiragana 589 | 30a0 - 30ff: Katakana 590 | ff00 - ff9f: Full-width Roman characters and half-width Katakana 591 | 4e00 - 9faf: CJK unified ideographs - Common and uncommon Kanji 592 | 3400 - 4dbf: CJK unified ideographs Extension A - Rare Kanji 593 | 594 | */ 595 | FUNCTION f_get_mode(p_data varchar2) RETURN pls_integer IS 596 | lnType pls_integer := 0; 597 | lcChar varchar2(1 char); 598 | 599 | FUNCTION f_is_char_kanji(p_char varchar2) RETURN boolean IS 600 | lnAscii number := ascii(p_char); 601 | lbReturn boolean := false; 602 | BEGIN 603 | if 604 | lnAscii between to_number('3000', 'xxxx') and to_number('30FF', 'xxxx') or 605 | lnAscii between to_number('FF00', 'xxxx') and to_number('FF9F', 'xxxx') or 606 | lnAscii between to_number('4E00', 'xxxx') and to_number('9FAF', 'xxxx') or 607 | lnAscii between to_number('3400', 'xxxx') and to_number('4DBF', 'xxxx') 608 | then 609 | lbReturn := true; 610 | end if; 611 | 612 | RETURN lbReturn; 613 | END; 614 | 615 | BEGIN 616 | FOR t IN 1 .. length(p_data) LOOP 617 | lcChar := substr(p_data, t, 1); 618 | 619 | if instr('0123456789', lcChar) > 0 then --numeric mode (1) 620 | p_debug(f_mode_name(cNumericMode) || ': char ' || lcChar, 2); 621 | lnType := greatest(lnType, cNumericMode); 622 | 623 | elsif instr('ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:', lcChar) > 0 then --alphanumeric mode (2) 624 | p_debug(f_mode_name(cAlphanumericMode) || ': char ' || lcChar, 2); 625 | lnType := greatest(lnType, cAlphanumericMode); 626 | 627 | elsif not f_is_char_kanji(lcChar) then --Byte mode including UTF-8 except kanji (3) 628 | p_debug(f_mode_name(cByteMode) || ': char ' || lcChar, 2); 629 | lnType := greatest(lnType, cByteMode); 630 | 631 | else --kanji mode (4) 632 | lnType := cKanjiMode; 633 | 634 | end if; 635 | 636 | END LOOP; 637 | 638 | --debug 639 | p_debug('mode for qr code: ' || f_mode_name(lnType) ); 640 | 641 | RETURN lnType; 642 | END; 643 | 644 | FUNCTION f_err_cor_2_number(p_error_correction varchar2) RETURN number IS 645 | lnNumber pls_integer; 646 | BEGIN 647 | --conversion to number 648 | lnNumber := CASE p_error_correction 649 | WHEN 'L' THEN 1 650 | WHEN 'M' THEN 2 651 | WHEN 'Q' THEN 3 652 | WHEN 'H' THEN 4 653 | ELSE 0 END; 654 | 655 | --error if mode can not be determined 656 | if lnNumber = 0 then 657 | RAISE_APPLICATION_ERROR(-20000, 'unknown error correction mode!'); 658 | end if; 659 | 660 | --return value 661 | RETURN lnNumber; 662 | END f_err_cor_2_number; 663 | 664 | 665 | /* 666 | 4 different indicators which are encoded into QR code 667 | */ 668 | FUNCTION f_mode_indicator RETURN varchar2 IS 669 | lcMode varchar2(4); 670 | BEGIN 671 | lcMode := 672 | CASE gpnMode 673 | WHEN cNumericMode THEN '0001' 674 | WHEN cAlphanumericMode THEN '0010' 675 | WHEN cByteMode THEN '0100' 676 | WHEN cKanjiMode THEN '1000' 677 | ELSE null 678 | END; 679 | 680 | p_debug('Mode indicator: ' || lcMode, 2); 681 | 682 | RETURN lcMode; 683 | END; 684 | 685 | 686 | 687 | 688 | /* 689 | character count indicator - final length in bits depends of mode and version 690 | */ 691 | FUNCTION f_char_count_indicator(p_data varchar2) RETURN varchar2 IS 692 | lnLength pls_integer; 693 | lcIndicator varchar2(16); 694 | lnCCILength pls_integer; 695 | 696 | BEGIN 697 | --length in bytes to binary; in case of UTF-8 one char can be more than 1 byte 698 | --that's why lengthb function is used instead of length 699 | lnLength := lengthb(p_data); 700 | lcIndicator := f_integer_2_binary(lnLength); 701 | 702 | p_debug('CCI Binary: ' || lcIndicator, 2); 703 | 704 | --padding 705 | if gpnVersion <= 9 then 706 | lnCCILength := 707 | CASE gpnMode 708 | WHEN cNumericMode THEN 10 709 | WHEN cAlphanumericMode THEN 9 710 | WHEN cByteMode THEN 8 711 | WHEN cKanjiMode THEN 8 712 | ELSE 0 713 | END; 714 | elsif gpnVersion between 10 and 26 then 715 | lnCCILength := 716 | CASE gpnMode 717 | WHEN cNumericMode THEN 12 718 | WHEN cAlphanumericMode THEN 11 719 | WHEN cByteMode THEN 16 720 | WHEN cKanjiMode THEN 10 721 | ELSE 0 722 | END; 723 | 724 | elsif gpnVersion >= 27 then 725 | lnCCILength := 726 | CASE gpnMode 727 | WHEN cNumericMode THEN 14 728 | WHEN cAlphanumericMode THEN 13 729 | WHEN cByteMode THEN 16 730 | WHEN cKanjiMode THEN 12 731 | ELSE 0 732 | END; 733 | 734 | end if; 735 | p_debug('Character Count Indicator length: ' || lnCCILength, 2); 736 | 737 | 738 | lcIndicator := lpad(lcIndicator, lnCCILength, '0'); 739 | 740 | p_debug('Character Count Indicator: ' || lcIndicator, 2); 741 | 742 | 743 | RETURN lcIndicator; 744 | END f_char_count_indicator; 745 | 746 | 747 | /* 748 | function determins and returns a QR code version (size), which depends of 3 values: 749 | - error correction level 750 | - mode (numeric, alphanumeric, byte or double byte) 751 | - length of data 752 | 753 | Version is determined from a table, where 3 dimensions are values from previous list 754 | We are searching for a smallest value, which can contain our data (error correction level and mode are fixed) 755 | 756 | For example, for: 757 | - correction level "M" 758 | - data "HELLO TO ALL PEOPLE IN THE WORLD" (data length is 32, mode is alphanumeric) 759 | a version is 2, because for given dimensions a version 2 can contain maximal of 38 characters and we have 32 characters 760 | Version 1 can contain maximal 20 characters and it is not enough. 761 | */ 762 | FUNCTION f_get_version( 763 | p_data varchar2, 764 | p_error_correction varchar2) RETURN pls_integer IS 765 | 766 | TYPE t_values IS TABLE OF varchar2(1000) INDEX BY pls_integer; 767 | lrValues t_values; 768 | 769 | TYPE t_numbers IS TABLE OF pls_integer; 770 | lrData t_numbers; 771 | 772 | lnVersion pls_integer := 0; 773 | lnLength pls_integer; 774 | 775 | lnElements pls_integer; 776 | lnPosition pls_integer; 777 | 778 | 779 | FUNCTION f_explode( 780 | p_text varchar2, 781 | p_delimiter varchar2 782 | ) RETURN t_numbers IS 783 | 784 | lrList t_numbers := t_numbers(); 785 | lnCounter pls_integer := 0; 786 | lcText varchar2(32000) := p_text; 787 | 788 | BEGIN 789 | LOOP 790 | lnCounter := instr(lcText, p_delimiter); 791 | 792 | if lnCounter > 0 then 793 | lrList.extend(1); 794 | lrList(lrList.count) := substr(lcText, 1, lnCounter - 1); 795 | lcText := substr(lcText, lnCounter + length(p_delimiter)); 796 | else 797 | lrList.extend(1); 798 | lrList(lrList.count) := lcText; 799 | RETURN lrList; 800 | end if; 801 | 802 | END LOOP; 803 | END f_explode; 804 | 805 | BEGIN 806 | --initial values to determine version 807 | lnLength := lengthb(p_data); 808 | 809 | /* 810 | values are separated in sets; each set has 4 values 811 | first value in set is for numeric mode, second for alphanumeric, then byte and at the end for double-byte 812 | first set is for error level "L", next set for "M", then "Q" then "H" 813 | example for version 1 (values are maximal number of characters for error level correction and mode) 814 | numeric alphanumeric byte double-byte 815 | L 41 25 17 10 816 | M 34 20 14 8 817 | Q 27 16 11 7 818 | H 17 10 7 4 819 | 820 | index for variable lrValues is version 821 | values are parsed in collection during runtime 822 | */ 823 | 824 | lrValues(1) := '41,25,17,10,34,20,14,8,27,16,11,7,17,10,7,4'; 825 | lrValues(2) := '77,47,32,20,63,38,26,16,48,29,20,12,34,20,14,8'; 826 | lrValues(3) := '127,77,53,32,101,61,42,26,77,47,32,20,58,35,24,15'; 827 | lrValues(4) := '187,114,78,48,149,90,62,38,111,67,46,28,82,50,34,21'; 828 | lrValues(5) := '255,154,106,65,202,122,84,52,144,87,60,37,106,64,44,27'; 829 | lrValues(6) := '322,195,134,82,255,154,106,65,178,108,74,45,139,84,58,36'; 830 | lrValues(7) := '370,224,154,95,293,178,122,75,207,125,86,53,154,93,64,39'; 831 | lrValues(8) := '461,279,192,118,365,221,152,93,259,157,108,66,202,122,84,52'; 832 | lrValues(9) := '552,335,230,141,432,262,180,111,312,189,130,80,235,143,98,60'; 833 | lrValues(10) := '652,395,271,167,513,311,213,131,364,221,151,93,288,174,119,74'; 834 | lrValues(11) := '772,468,321,198,604,366,251,155,427,259,177,109,331,200,137,85'; 835 | lrValues(12) := '883,535,367,226,691,419,287,177,489,296,203,125,374,227,155,96'; 836 | lrValues(13) := '1022,619,425,262,796,483,331,204,580,352,241,149,427,259,177,109'; 837 | lrValues(14) := '1101,667,458,282,871,528,362,223,621,376,258,159,468,283,194,120'; 838 | lrValues(15) := '1250,758,520,320,991,600,412,254,703,426,292,180,530,321,220,136'; 839 | lrValues(16) := '1408,854,586,361,1082,656,450,277,775,470,322,198,602,365,250,154'; 840 | lrValues(17) := '1548,938,644,397,1212,734,504,310,876,531,364,224,674,408,280,173'; 841 | lrValues(18) := '1725,1046,718,442,1346,816,560,345,948,574,394,243,746,452,310,191'; 842 | lrValues(19) := '1903,1153,792,488,1500,909,624,384,1063,644,442,272,813,493,338,208'; 843 | lrValues(20) := '2061,1249,858,528,1600,970,666,410,1159,702,482,297,919,557,382,235'; 844 | lrValues(21) := '2232,1352,929,572,1708,1035,711,438,1224,742,509,314,969,587,403,248'; 845 | lrValues(22) := '2409,1460,1003,618,1872,1134,779,480,1358,823,565,348,1056,640,439,270'; 846 | lrValues(23) := '2620,1588,1091,672,2059,1248,857,528,1468,890,611,376,1108,672,461,284'; 847 | lrValues(24) := '2812,1704,1171,721,2188,1326,911,561,1588,963,661,407,1228,744,511,315'; 848 | lrValues(25) := '3057,1853,1273,784,2395,1451,997,614,1718,1041,715,440,1286,779,535,330'; 849 | lrValues(26) := '3283,1990,1367,842,2544,1542,1059,652,1804,1094,751,462,1425,864,593,365'; 850 | lrValues(27) := '3517,2132,1465,902,2701,1637,1125,692,1933,1172,805,496,1501,910,625,385'; 851 | lrValues(28) := '3669,2223,1528,940,2857,1732,1190,732,2085,1263,868,534,1581,958,658,405'; 852 | lrValues(29) := '3909,2369,1628,1002,3035,1839,1264,778,2181,1322,908,559,1677,1016,698,430'; 853 | lrValues(30) := '4158,2520,1732,1066,3289,1994,1370,843,2358,1429,982,604,1782,1080,742,457'; 854 | lrValues(31) := '4417,2677,1840,1132,3486,2113,1452,894,2473,1499,1030,634,1897,1150,790,486'; 855 | lrValues(32) := '4686,2840,1952,1201,3693,2238,1538,947,2670,1618,1112,684,2022,1226,842,518'; 856 | lrValues(33) := '4965,3009,2068,1273,3909,2369,1628,1002,2805,1700,1168,719,2157,1307,898,553'; 857 | lrValues(34) := '5253,3183,2188,1347,4134,2506,1722,1060,2949,1787,1228,756,2301,1394,958,590'; 858 | lrValues(35) := '5529,3351,2303,1417,4343,2632,1809,1113,3081,1867,1283,790,2361,1431,983,605'; 859 | lrValues(36) := '5836,3537,2431,1496,4588,2780,1911,1176,3244,1966,1351,832,2524,1530,1051,647'; 860 | lrValues(37) := '6153,3729,2563,1577,4775,2894,1989,1224,3417,2071,1423,876,2625,1591,1093,673'; 861 | lrValues(38) := '6479,3927,2699,1661,5039,3054,2099,1292,3599,2181,1499,923,2735,1658,1139,701'; 862 | lrValues(39) := '6743,4087,2809,1729,5313,3220,2213,1362,3791,2298,1579,972,2927,1774,1219,750'; 863 | lrValues(40) := '7089,4296,2953,1817,5596,3391,2331,1435,3993,2420,1663,1024,3057,1852,1273,784'; 864 | 865 | 866 | --a version depending of error correction method, mode and data length 867 | lnPosition := (f_err_cor_2_number(p_error_correction) - 1) * 4 + gpnMode; 868 | 869 | p_debug('length: ' || lnLength, 2); 870 | 871 | FOR t IN 1 .. 40 LOOP 872 | p_debug(lrValues(t), 4); 873 | 874 | /* 875 | SELECT to_number(column_value) a 876 | BULK COLLECT INTO lrData 877 | FROM XMLTABLE(lrValues(t)); 878 | */ 879 | lrData := f_explode( 880 | p_text => lrValues(t), 881 | p_delimiter => ',' 882 | ); 883 | 884 | p_debug('Value on position ' || lnPosition || ': ' || lrData(lnPosition), 2); 885 | 886 | if lrData(lnPosition) >= lnLength then 887 | lnVersion := t; 888 | EXIT; 889 | end if; 890 | 891 | END LOOP; 892 | 893 | --if version can not be determined then throw error 894 | if lnVersion = 0 then 895 | RAISE_APPLICATION_ERROR(-20000, 'Data length is too big to be encoded in one QR code.'); 896 | end if; 897 | 898 | --debug 899 | p_debug('version: ' || lnVersion); 900 | 901 | RETURN lnVersion; 902 | 903 | END f_get_version; 904 | 905 | 906 | FUNCTION f_encode_data( 907 | p_data varchar2, 908 | p_error_correction varchar2) RETURN varchar2 IS 909 | 910 | lcData varchar2(32000); 911 | lnCounter pls_integer := 1; 912 | lcSub varchar2(3); 913 | lnReqNumOfBits pls_integer; 914 | lcChar varchar2(1 char); 915 | 916 | --function returns value of character in alphanumeric mode 917 | FUNCTION f_get_code(p_char varchar2) RETURN pls_integer IS 918 | lnCode pls_integer; 919 | BEGIN 920 | --0 - 9 921 | if instr('0123456789', p_char) > 0 then 922 | lnCode := to_number(p_char); 923 | elsif instr('ABCDEFGHIJKLMNOPQRSTUVWXYZ', p_char) > 0 then 924 | lnCode := ascii(p_char) - 55; 925 | elsif p_char = ' ' then 926 | lnCode := 36; 927 | elsif p_char = '$' then 928 | lnCode := 37; 929 | elsif p_char = '%' then 930 | lnCode := 38; 931 | elsif p_char = '*' then 932 | lnCode := 39; 933 | elsif p_char = '+' then 934 | lnCode := 40; 935 | elsif p_char = '-' then 936 | lnCode := 41; 937 | elsif p_char = '.' then 938 | lnCode := 42; 939 | elsif p_char = '/' then 940 | lnCode := 43; 941 | elsif p_char = ':' then 942 | lnCode := 44; 943 | end if; 944 | 945 | RETURN lnCode; 946 | END f_get_code; 947 | 948 | 949 | BEGIN 950 | --encoded data regardless of mode always start with mode indicator and character count indicator 951 | lcData := f_mode_indicator || f_char_count_indicator(p_data); 952 | 953 | --data encoding - different for different modes 954 | if gpnMode = cNumericMode then 955 | LOOP 956 | lcSub := substr(p_data, lnCounter, 3); 957 | 958 | p_debug(lcSub, 2); 959 | 960 | if length(lcSub) = 3 then 961 | lcData := lcData || lpad(f_integer_2_binary( to_number(lcSub) ), 10, '0'); 962 | elsif length(lcSub) = 2 then 963 | lcData := lcData || lpad(f_integer_2_binary( to_number(lcSub) ), 7, '0'); 964 | elsif length(lcSub) = 1 then 965 | lcData := lcData || lpad(f_integer_2_binary( to_number(lcSub) ), 4, '0'); 966 | end if; 967 | 968 | EXIT WHEN lnCounter >= length(p_data); 969 | 970 | lnCounter := lnCounter + 3; 971 | END LOOP; 972 | 973 | elsif gpnMode = cAlphanumericMode then 974 | 975 | LOOP 976 | lcSub := substr(p_data, lnCounter, 2); 977 | 978 | p_debug(lcSub, 2); 979 | 980 | if length(lcSub) = 2 then 981 | lcData := lcData || lpad(f_integer_2_binary( f_get_code(substr(lcSub, 1, 1)) * 45 + f_get_code(substr(lcSub, 2, 1)) ), 11, '0'); 982 | elsif length(lcSub) = 1 then 983 | lcData := lcData || lpad(f_integer_2_binary( f_get_code(lcSub) ), 6, '0'); 984 | end if; 985 | 986 | EXIT WHEN lnCounter >= length(p_data); 987 | 988 | lnCounter := lnCounter + 2; 989 | END LOOP; 990 | 991 | elsif gpnMode = cByteMode then 992 | FOR t IN 1 .. length(p_data) LOOP 993 | lcChar := substr(p_data, t, 1); 994 | lcData := lcData || lpad(f_integer_2_binary( ascii(lcChar) ), 8 * lengthb(lcChar), '0'); 995 | 996 | END LOOP; 997 | 998 | elsif gpnMode = cKanjiMode then 999 | --TODO for Kanji mode 1000 | null; 1001 | end if; 1002 | 1003 | p_debug('Data without right padding (number of bits ' || length(lcData) || '): ' || lcData, 2); 1004 | 1005 | --terminator zeros 1006 | lnReqNumOfBits := gprErrCorInfo(gpnVersion || '-' || p_error_correction).total_no_of_data_cw * 8; 1007 | p_debug('Required number of bits: ' || lnReqNumOfBits, 2); 1008 | 1009 | p_debug('Terminator zeros to add: ' || (lnReqNumOfBits - lengthb(lcData)), 2); 1010 | 1011 | if lnReqNumOfBits - lengthb(lcData) >= 4 then 1012 | lcData := lcData || '0000'; 1013 | else 1014 | lcData := rpad(lcData, lnReqNumOfBits, '0'); 1015 | end if; 1016 | 1017 | p_debug('Data with right padding (number of bits ' || length(lcData) || '): ' || lcData, 2); 1018 | 1019 | --additional right padding with 0 to reach a string length multiple of 8 1020 | LOOP 1021 | EXIT WHEN length(lcData) mod 8 = 0; 1022 | lcData := lcData || '0'; 1023 | p_debug('Additional right padding zeros: 0', 2); 1024 | END LOOP; 1025 | 1026 | --final filling of data with 11101100 and 00010001 alternatively until full length is reached 1027 | LOOP 1028 | EXIT WHEN length(lcData) = lnReqNumOfBits; 1029 | lcData := lcData || '11101100'; 1030 | p_debug('Additional padding with: 11101100', 2); 1031 | EXIT WHEN length(lcData) = lnReqNumOfBits; 1032 | lcData := lcData || '00010001'; 1033 | p_debug('Additional padding with: 00010001', 2); 1034 | END LOOP; 1035 | 1036 | 1037 | --debug 1038 | p_debug('Data (number of bits ' || length(lcData) || '): ' || lcData); 1039 | 1040 | RETURN lcData; 1041 | 1042 | END f_encode_data; 1043 | 1044 | 1045 | 1046 | FUNCTION f_final_data_with_ec( 1047 | p_encoded_data varchar2, 1048 | p_error_correction varchar2) RETURN varchar2 IS 1049 | 1050 | TYPE t_cw IS TABLE OF pls_integer; 1051 | TYPE r_block IS RECORD (cw t_cw); 1052 | TYPE t_block IS TABLE OF r_block INDEX BY varchar2(10); 1053 | 1054 | lrBlock t_block; 1055 | 1056 | lcVersionEC varchar2(10); 1057 | lcBlock varchar2(10); 1058 | lnCounter pls_integer := 1; 1059 | lcCW varchar2(8); 1060 | lnCW pls_integer; 1061 | lnGroups pls_integer; 1062 | lcDebug varchar2(10000); 1063 | lnReminderBits pls_integer := 0; 1064 | 1065 | lcResult varchar2(32000); 1066 | 1067 | FUNCTION f_blocks_in_group(p_group pls_integer) RETURN pls_integer IS 1068 | BEGIN 1069 | RETURN 1070 | CASE 1071 | WHEN p_group = 1 THEN gprErrCorInfo(lcVersionEC).blocks_in_g1 1072 | ELSE nvl(gprErrCorInfo(lcVersionEC).blocks_in_g2, 0) 1073 | END; 1074 | END; 1075 | 1076 | FUNCTION f_cw_in_group(p_group pls_integer) RETURN pls_integer IS 1077 | BEGIN 1078 | RETURN 1079 | CASE 1080 | WHEN p_group = 1 THEN gprErrCorInfo(lcVersionEC).cw_in_g1 1081 | ELSE nvl(gprErrCorInfo(lcVersionEC).cw_in_g2, 0) 1082 | END; 1083 | END; 1084 | 1085 | PROCEDURE p_add_cw_to_block(p_gb varchar2, p_cw pls_integer) IS 1086 | BEGIN 1087 | lrBlock(p_gb).cw.extend; 1088 | lrBlock(p_gb).cw(lrBlock(p_gb).cw.count) := p_cw; 1089 | END; 1090 | 1091 | PROCEDURE p_debug_collection( 1092 | p_description varchar2, 1093 | p_collection t_cw, 1094 | p_level pls_integer default 1) IS 1095 | 1096 | BEGIN 1097 | lcDebug := p_description; 1098 | FOR t IN p_collection.first .. p_collection.last LOOP 1099 | lcDebug := lcDebug || p_collection(t) || ', '; 1100 | END LOOP; 1101 | p_debug(rtrim(lcDebug, ', '), p_level); 1102 | END; 1103 | 1104 | FUNCTION f_poly_divide(p_mess_poly t_cw, p_gen_poly t_cw) RETURN t_cw IS 1105 | lrEC t_cw := t_cw(); 1106 | lrDivider t_cw := t_cw(); 1107 | lrResult t_cw := t_cw(); 1108 | 1109 | lnAnti pls_integer; 1110 | BEGIN 1111 | --copy message polynomial to lrEC 1112 | lrEC := lrEc MULTISET UNION ALL p_mess_poly; 1113 | 1114 | --To make sure that the exponent of the lead term doesn't become too small during the division 1115 | --multiply the message polynomial by xn where n is the number of error correction codewords that are needed 1116 | --so, we extend the collection and fill those elements with 0 1117 | lrEC.extend(p_gen_poly.count - 1); 1118 | FOR t IN REVERSE lrEC.first .. lrEC.last LOOP 1119 | EXIT WHEN lrEC(t) is not null; 1120 | lrEC(t) := 0; 1121 | END LOOP; 1122 | 1123 | FOR t IN 1 .. p_mess_poly.count LOOP 1124 | p_debug('Step ' || t || ':', 2); 1125 | 1126 | if lrEC(t) > 0 then 1127 | --Lead Term of the Message Polynomial (in first cycle) or result from previous cycle 1128 | --antilog is needed for multipilcation with generator polynomial (next step) 1129 | lnAnti := gprAntiLog( lrEC(t) ); 1130 | p_debug('Lead Term of the Message Polynomial: ' || lrEC(t) || ' (antiLog ' || lnAnti || ')', 2); 1131 | 1132 | --copy generator polynomial to lrDivider 1133 | lrDivider.delete; 1134 | lrDivider := lrDivider MULTISET UNION ALL p_gen_poly; 1135 | 1136 | --Multiply the Generator Polynomial by the Lead Term of the Message Polynomial 1137 | --everything is happening in antilog - generator polynomial is already in antilog 1138 | --basicly we add two antilogs 1139 | FOR p IN 1 .. lrDivider.count LOOP 1140 | lrDivider(p) := lrDivider(p) + lnAnti; 1141 | if lrDivider(p) >= 255 then 1142 | lrDivider(p) := lrDivider(p) - 255; 1143 | end if; 1144 | END LOOP; 1145 | 1146 | p_debug_collection( 1147 | 'Generator polynomial multiplied with Lead Term antiLog (in antiLog): ', 1148 | lrDivider, 1149 | 2); 1150 | 1151 | --XOR the result with the message polynomial (first cycle) or result from previous cycle 1152 | --Message or result from previous cycle is already in log, so we convert generated polynomial from previous step into log 1153 | --leading terms, which are already 0 are discarded (index is "p + t - 1") 1154 | FOR p IN 1 .. lrDivider.count LOOP 1155 | lrEC(p + t - 1) := bitxor( lrEC(p + t - 1), gprLog(lrDivider(p)) ); 1156 | END LOOP; 1157 | 1158 | p_debug_collection( 1159 | 'XOR the result with the message polynomial or result from previous cycle (in Log): ', 1160 | lrEC, 1161 | 2); 1162 | else 1163 | p_debug('skipping this step and discarding next lead term 0...', 2); 1164 | end if; 1165 | 1166 | END LOOP; 1167 | 1168 | --last remaining elements are error correction codewords 1169 | FOR t IN lrEC.count - (p_gen_poly.count - 2) .. lrEC.count LOOP 1170 | lrResult.extend; 1171 | lrResult(lrResult.count) := lrEC(t); 1172 | END LOOP; 1173 | 1174 | RETURN lrResult; 1175 | END; 1176 | 1177 | 1178 | BEGIN 1179 | --Version and EC Level 1180 | lcVersionEC := gpnVersion || '-' || p_error_correction; 1181 | p_debug('Version and EC Level: ' || lcVersionEC, 2); 1182 | 1183 | --generator polynomial - init for all 13 possible options 1184 | --generator polynomial has the same structure as message polynomial (block) and so the same type is used 1185 | lrBlock('7').cw := t_cw(0, 87, 229, 146, 149, 238, 102, 21); 1186 | lrBlock('10').cw := t_cw(0, 251, 67, 46, 61, 118, 70, 64, 94, 32, 45); 1187 | lrBlock('13').cw := t_cw(0, 74, 152, 176, 100, 86, 100, 106, 104, 130, 218, 206, 140, 78); 1188 | lrBlock('15').cw := t_cw(0, 8, 183, 61, 91, 202, 37, 51, 58, 58, 237, 140, 124, 5, 99, 105); 1189 | lrBlock('16').cw := t_cw(0, 120, 104, 107, 109, 102, 161, 76, 3, 91, 191, 147, 169, 182, 194, 225, 120); 1190 | lrBlock('17').cw := t_cw(0, 43, 139, 206, 78, 43, 239, 123, 206, 214, 147, 24, 99, 150, 39, 243, 163, 136); 1191 | lrBlock('18').cw := t_cw(0, 215, 234, 158, 94, 184, 97, 118, 170, 79, 187, 152, 148, 252, 179, 5, 98, 96, 153); 1192 | lrBlock('20').cw := t_cw(0, 17, 60, 79, 50, 61, 163, 26, 187, 202, 180, 221, 225, 83, 239, 156, 164, 212, 212, 188, 190); 1193 | lrBlock('22').cw := t_cw(0, 210, 171, 247, 242, 93, 230, 14, 109, 221, 53, 200, 74, 8, 172, 98, 80, 219, 134, 160, 105, 165, 231); 1194 | lrBlock('24').cw := t_cw(0, 229, 121, 135, 48, 211, 117, 251, 126, 159, 180, 169, 152, 192, 226, 228, 218, 111, 0, 117, 232, 87, 96, 227, 21); 1195 | lrBlock('26').cw := t_cw(0, 173, 125, 158, 2, 103, 182, 118, 17, 145, 201, 111, 28, 165, 53, 161, 21, 245, 142, 13, 102, 48, 227, 153, 145, 218, 70); 1196 | lrBlock('28').cw := t_cw(0, 168, 223, 200, 104, 224, 234, 108, 180, 110, 190, 195, 147, 205, 27, 232, 201, 21, 43, 245, 87, 42, 195, 212, 119, 242, 37, 9, 123); 1197 | lrBlock('30').cw := t_cw(0, 41, 173, 145, 152, 216, 31, 179, 182, 50, 48, 110, 86, 239, 96, 222, 125, 42, 173, 226, 193, 224, 130, 156, 37, 251, 216, 238, 40, 192, 180); 1198 | 1199 | --debug - Generator Polynomial used 1200 | p_debug_collection( 1201 | 'Generator Polynomial (' || gprErrCorInfo(lcVersionEC).ec_cw_per_block || '): ', 1202 | lrBlock(gprErrCorInfo(lcVersionEC).ec_cw_per_block).cw, 1203 | 2); 1204 | 1205 | --how many groups 1206 | lnGroups := (CASE WHEN gprErrCorInfo(lcVersionEC).blocks_in_g2 is null THEN 1 ELSE 2 END); 1207 | 1208 | --debug - number of groups and blocks in each group, number of codewords for each block in group 1209 | p_debug('Number of groups: ' || lnGroups, 2); 1210 | FOR gr IN 1 .. lnGroups LOOP 1211 | p_debug('Group ' || gr || ' - number of blocks in group: ' || f_blocks_in_group(gr), 2); 1212 | p_debug('Group ' || gr || ' - number of codewords in each block: ' || f_cw_in_group(gr), 2); 1213 | END LOOP; 1214 | 1215 | --prepare message polynomial for each group and block (G1B1, G1B2 ... G2B1, G2B2...) 1216 | FOR gr IN 1 .. lnGroups LOOP 1217 | FOR blk IN 1 .. f_blocks_in_group(gr) LOOP 1218 | --init block 1219 | lcBlock := 'G' || gr || 'B' || blk; 1220 | lrBlock(lcBlock).cw := t_cw(); 1221 | 1222 | p_debug('Group ' || gr || ', block ' || blk || ' - message polynomial:', 2); 1223 | 1224 | --fill block with data codewords (codewords are converted to decimal) 1225 | FOR cw IN 1 .. f_cw_in_group(gr) LOOP 1226 | lcCW := substr(p_encoded_data, lnCounter, 8); 1227 | lnCW := bin2dec(lcCW); 1228 | 1229 | p_add_cw_to_block(lcBlock, lnCW); 1230 | p_debug('Codeword ' || cw || ': ' || lcCW || ' (' || lnCW || ')', 2); 1231 | 1232 | lnCounter := lnCounter + 8; 1233 | END LOOP; 1234 | 1235 | END LOOP; 1236 | END LOOP; 1237 | 1238 | 1239 | --calculate error correction data for each group and block (G1B1EC, G1B2EC... G2B1EC, G2B2EC...) 1240 | FOR gr IN 1 .. lnGroups LOOP 1241 | FOR blk IN 1 .. f_blocks_in_group(gr) LOOP 1242 | lrBlock('G' || gr || 'B' || blk || 'EC').cw := f_poly_divide( 1243 | lrBlock('G' || gr || 'B' || blk).cw, --message polynomial 1244 | lrBlock(gprErrCorInfo(lcVersionEC).ec_cw_per_block).cw --generator polynomial 1245 | ); 1246 | 1247 | p_debug_collection( 1248 | 'Final error correction codewords for group ' || gr || ' and block ' || blk || ': ', 1249 | lrBlock('G' || gr || 'B' || blk || 'EC').cw, 1250 | 2); 1251 | 1252 | END LOOP; 1253 | END LOOP; 1254 | 1255 | 1256 | --structure final message (interleaving) - data codewords 1257 | lcDebug := 'Interleaved data codewords: '; 1258 | FOR cnt IN 1 .. greatest( f_cw_in_group(1), f_cw_in_group(2) ) LOOP 1259 | FOR gr IN 1 .. lnGroups LOOP 1260 | FOR blk IN 1 .. f_blocks_in_group(gr) LOOP 1261 | 1262 | if lrBlock('G' || gr || 'B' || blk).cw.count >= cnt then 1263 | lcResult := lcResult || lpad(f_integer_2_binary( lrBlock('G' || gr || 'B' || blk).cw(cnt) ), 8, '0'); 1264 | lcDebug := lcDebug || lrBlock('G' || gr || 'B' || blk).cw(cnt) || ', '; 1265 | end if; 1266 | 1267 | END LOOP; 1268 | END LOOP; 1269 | END LOOP; 1270 | p_debug(rtrim(lcDebug, ', '), 2); 1271 | 1272 | 1273 | --structure final message (interleaving) - error correction codewords 1274 | lcDebug := 'Interleaved error correction codewords: '; 1275 | FOR cnt IN 1 .. gprErrCorInfo(lcVersionEC).ec_cw_per_block LOOP 1276 | FOR gr IN 1 .. lnGroups LOOP 1277 | FOR blk IN 1 .. f_blocks_in_group(gr) LOOP 1278 | lcResult := lcResult || lpad(f_integer_2_binary( lrBlock('G' || gr || 'B' || blk || 'EC').cw(cnt) ), 8, '0'); 1279 | lcDebug := lcDebug || lrBlock('G' || gr || 'B' || blk || 'EC').cw(cnt) || ', '; 1280 | END LOOP; 1281 | END LOOP; 1282 | END LOOP; 1283 | p_debug(rtrim(lcDebug, ', '), 2); 1284 | 1285 | 1286 | --Add Remainder Bits for some QR versions, if necessary 1287 | lnReminderBits := 1288 | CASE 1289 | WHEN gpnVersion between 2 and 6 THEN 7 1290 | WHEN gpnVersion between 21 and 27 THEN 4 1291 | WHEN gpnVersion between 14 and 20 or gpnVersion between 28 and 34 THEN 3 1292 | ELSE 0 1293 | END; 1294 | p_debug('Reminder bits: ' || lnReminderBits, 2); 1295 | 1296 | if lnReminderBits > 0 then 1297 | lcResult := rpad(lcResult, length(lcResult) + lnReminderBits, '0'); 1298 | end if; 1299 | 1300 | p_debug('Final message (length ' || length(lcResult) || '): ' || lcResult); 1301 | 1302 | 1303 | RETURN lcResult; 1304 | END f_final_data_with_ec; 1305 | 1306 | 1307 | 1308 | PROCEDURE p_place_fm_in_matrix(lcData varchar2) IS 1309 | 1310 | lnColumn pls_integer; 1311 | lnRow pls_integer; 1312 | lnDirection pls_integer; 1313 | 1314 | lnCounter pls_integer; 1315 | 1316 | 1317 | PROCEDURE p_set_module(p_column pls_integer, p_row pls_integer) IS 1318 | BEGIN 1319 | if gprMatrix(p_row)(p_column) is null then 1320 | gprMatrix(p_row)(p_column) := substr(lcData, lnCounter, 1); 1321 | lnCounter := lnCounter + 1; 1322 | end if; 1323 | END; 1324 | 1325 | BEGIN 1326 | --staring values 1327 | lnColumn := f_matrix_size; 1328 | 1329 | lnRow := f_matrix_size; 1330 | lnDirection := -1; 1331 | 1332 | lnCounter := 1; 1333 | 1334 | LOOP 1335 | EXIT WHEN lnColumn < 1; 1336 | 1337 | --fill data in column 1338 | FOR t IN 1 .. f_matrix_size LOOP 1339 | p_set_module(lnColumn, lnRow); 1340 | p_set_module(lnColumn - 1, lnRow); 1341 | 1342 | lnRow := lnRow + lnDirection; 1343 | END LOOP; 1344 | 1345 | --change of direction 1346 | lnDirection := lnDirection * -1; 1347 | 1348 | --first position for next column (because the last iteration of loop breached through matrix margine) 1349 | lnRow := lnRow + lnDirection; 1350 | 1351 | --next column 1352 | lnColumn := lnColumn - 2; 1353 | --exception is vertical time pattern - if pattern is reached then column shifts to the first column on the left 1354 | if lnColumn = 7 then 1355 | lnColumn := 6; 1356 | end if; 1357 | 1358 | END LOOP; 1359 | 1360 | --debug filled matrix 1361 | p_debug('Matrix filled with final message (modules marked with dots are for format data; marked with stars are for version - those data will be filled in masking step):', 2); 1362 | p_dbms_output_matrix(gprMatrix, 2); 1363 | END; 1364 | 1365 | 1366 | PROCEDURE p_masking_format_version(p_error_correction varchar2) IS 1367 | 1368 | TYPE t_format_version IS TABLE OF varchar2(20) INDEX BY varchar2(2); 1369 | 1370 | lrFormat t_format_version; 1371 | lrVersion t_format_version; 1372 | 1373 | lnR pls_integer; 1374 | lnC pls_integer; 1375 | 1376 | PROCEDURE p_init_format_version IS 1377 | BEGIN 1378 | --init format 1379 | lrFormat('L0') := '111011111000100'; 1380 | lrFormat('L1') := '111001011110011'; 1381 | lrFormat('L2') := '111110110101010'; 1382 | lrFormat('L3') := '111100010011101'; 1383 | lrFormat('L4') := '110011000101111'; 1384 | lrFormat('L5') := '110001100011000'; 1385 | lrFormat('L6') := '110110001000001'; 1386 | lrFormat('L7') := '110100101110110'; 1387 | lrFormat('M0') := '101010000010010'; 1388 | lrFormat('M1') := '101000100100101'; 1389 | lrFormat('M2') := '101111001111100'; 1390 | lrFormat('M3') := '101101101001011'; 1391 | lrFormat('M4') := '100010111111001'; 1392 | lrFormat('M5') := '100000011001110'; 1393 | lrFormat('M6') := '100111110010111'; 1394 | lrFormat('M7') := '100101010100000'; 1395 | lrFormat('Q0') := '011010101011111'; 1396 | lrFormat('Q1') := '011000001101000'; 1397 | lrFormat('Q2') := '011111100110001'; 1398 | lrFormat('Q3') := '011101000000110'; 1399 | lrFormat('Q4') := '010010010110100'; 1400 | lrFormat('Q5') := '010000110000011'; 1401 | lrFormat('Q6') := '010111011011010'; 1402 | lrFormat('Q7') := '010101111101101'; 1403 | lrFormat('H0') := '001011010001001'; 1404 | lrFormat('H1') := '001001110111110'; 1405 | lrFormat('H2') := '001110011100111'; 1406 | lrFormat('H3') := '001100111010000'; 1407 | lrFormat('H4') := '000011101100010'; 1408 | lrFormat('H5') := '000001001010101'; 1409 | lrFormat('H6') := '000110100001100'; 1410 | lrFormat('H7') := '000100000111011'; 1411 | 1412 | --init version 1413 | lrVersion('7') := '000111110010010100'; 1414 | lrVersion('8') := '001000010110111100'; 1415 | lrVersion('9') := '001001101010011001'; 1416 | lrVersion('10') := '001010010011010011'; 1417 | lrVersion('11') := '001011101111110110'; 1418 | lrVersion('12') := '001100011101100010'; 1419 | lrVersion('13') := '001101100001000111'; 1420 | lrVersion('14') := '001110011000001101'; 1421 | lrVersion('15') := '001111100100101000'; 1422 | lrVersion('16') := '010000101101111000'; 1423 | lrVersion('17') := '010001010001011101'; 1424 | lrVersion('18') := '010010101000010111'; 1425 | lrVersion('19') := '010011010100110010'; 1426 | lrVersion('20') := '010100100110100110'; 1427 | lrVersion('21') := '010101011010000011'; 1428 | lrVersion('22') := '010110100011001001'; 1429 | lrVersion('23') := '010111011111101100'; 1430 | lrVersion('24') := '011000111011000100'; 1431 | lrVersion('25') := '011001000111100001'; 1432 | lrVersion('26') := '011010111110101011'; 1433 | lrVersion('27') := '011011000010001110'; 1434 | lrVersion('28') := '011100110000011010'; 1435 | lrVersion('29') := '011101001100111111'; 1436 | lrVersion('30') := '011110110101110101'; 1437 | lrVersion('31') := '011111001001010000'; 1438 | lrVersion('32') := '100000100111010101'; 1439 | lrVersion('33') := '100001011011110000'; 1440 | lrVersion('34') := '100010100010111010'; 1441 | lrVersion('35') := '100011011110011111'; 1442 | lrVersion('36') := '100100101100001011'; 1443 | lrVersion('37') := '100101010000101110'; 1444 | lrVersion('38') := '100110101001100100'; 1445 | lrVersion('39') := '100111010101000001'; 1446 | lrVersion('40') := '101000110001101001'; 1447 | END p_init_format_version; 1448 | 1449 | 1450 | PROCEDURE p_format_version(p_mask pls_integer) IS 1451 | lcFormat varchar2(20); 1452 | lcVersion varchar2(20); 1453 | lnCounter pls_integer; 1454 | 1455 | PROCEDURE p_set_module( 1456 | p_row pls_integer, 1457 | p_column pls_integer, 1458 | p_pos pls_integer, 1459 | p_format_version varchar2 --F for format and V for version 1460 | ) IS 1461 | BEGIN 1462 | --modules are reserved and values 2 and 3 are set (not 0 and 1) 1463 | gprMasking(p_mask)(p_row)(p_column) := 1464 | (CASE WHEN substr( (CASE WHEN p_format_version = 'F' THEN lcFormat ELSE lcVersion END), p_pos, 1) = '1' THEN '3' ELSE '2' END); 1465 | END; 1466 | 1467 | BEGIN 1468 | --put format in matrix (for all 8 maskings) 1469 | lcFormat := lrFormat(p_error_correction || p_mask); 1470 | p_debug('Format for error correction ' || p_error_correction || ' and masking ' || p_mask || ': ' || lcFormat, 3); 1471 | 1472 | --top left finder 1473 | p_set_module(9, 1, 1, 'F'); 1474 | p_set_module(9, 2, 2, 'F'); 1475 | p_set_module(9, 3, 3, 'F'); 1476 | p_set_module(9, 4, 4, 'F'); 1477 | p_set_module(9, 5, 5, 'F'); 1478 | p_set_module(9, 6, 6, 'F'); 1479 | p_set_module(9, 8, 7, 'F'); 1480 | p_set_module(9, 9, 8, 'F'); 1481 | p_set_module(8, 9, 9, 'F'); 1482 | p_set_module(6, 9, 10, 'F'); 1483 | p_set_module(5, 9, 11, 'F'); 1484 | p_set_module(4, 9, 12, 'F'); 1485 | p_set_module(3, 9, 13, 'F'); 1486 | p_set_module(2, 9, 14, 'F'); 1487 | p_set_module(1, 9, 15, 'F'); 1488 | 1489 | --lower left and top right finder 1490 | p_set_module(f_matrix_size, 9, 1, 'F'); 1491 | p_set_module(f_matrix_size - 1, 9, 2, 'F'); 1492 | p_set_module(f_matrix_size - 2, 9, 3, 'F'); 1493 | p_set_module(f_matrix_size - 3, 9, 4, 'F'); 1494 | p_set_module(f_matrix_size - 4, 9, 5, 'F'); 1495 | p_set_module(f_matrix_size - 5, 9, 6, 'F'); 1496 | p_set_module(f_matrix_size - 6, 9, 7, 'F'); 1497 | 1498 | p_set_module(9, f_matrix_size - 7, 8, 'F'); 1499 | p_set_module(9, f_matrix_size - 6, 9, 'F'); 1500 | p_set_module(9, f_matrix_size - 5, 10, 'F'); 1501 | p_set_module(9, f_matrix_size - 4, 11, 'F'); 1502 | p_set_module(9, f_matrix_size - 3, 12, 'F'); 1503 | p_set_module(9, f_matrix_size - 2, 13, 'F'); 1504 | p_set_module(9, f_matrix_size - 1, 14, 'F'); 1505 | p_set_module(9, f_matrix_size, 15, 'F'); 1506 | 1507 | 1508 | --put version in matrix (for 7 and higher) 1509 | if gpnVersion >= 7 then 1510 | lcVersion := lrVersion(gpnVersion); 1511 | p_debug('Version (' || gpnVersion || ') for matrix: ' || lcVersion, 3); 1512 | 1513 | 1514 | lnCounter := 1; 1515 | FOR c IN REVERSE 1 .. 6 LOOP 1516 | FOR r IN 8 .. 10 LOOP 1517 | --bottom left 1518 | p_set_module(f_matrix_size - r, c, lnCounter, 'V'); 1519 | 1520 | --top right 1521 | p_set_module(c, f_matrix_size - r, lnCounter, 'V'); 1522 | 1523 | lnCounter := lnCounter + 1; 1524 | END LOOP; 1525 | END LOOP; 1526 | 1527 | else 1528 | p_debug('Version (' || gpnVersion || ') is not needed for matrix', 3); 1529 | end if; 1530 | 1531 | 1532 | END p_format_version; 1533 | 1534 | BEGIN 1535 | --init format and version collection 1536 | p_init_format_version; 1537 | 1538 | --copy matrix for 8 different maskings 1539 | FOR t IN 0 .. 7 LOOP 1540 | gprMasking(t) := t_column(); 1541 | gprMasking(t) := gprMasking(t) MULTISET UNION ALL gprMatrix; 1542 | END LOOP; 1543 | 1544 | --mask every copy with different masking 1545 | FOR t IN 0 .. 7 LOOP 1546 | 1547 | FOR r IN 1 .. f_matrix_size LOOP 1548 | FOR c IN 1 .. f_matrix_size LOOP 1549 | 1550 | --matrix (collection) in Oracle begins with 1 1551 | lnR := r - 1; 1552 | lnC := c - 1; 1553 | 1554 | --masking is done only on data and error correction modules (matrix values 0 or 1 - other values are fixed) 1555 | if gprMasking(t)(r)(c) in ('1', '0') then 1556 | 1557 | --mask patterns 1558 | if 1559 | (t=0 and (lnR + lnC) mod 2 = 0) or 1560 | (t=1 and lnR mod 2 = 0) or 1561 | (t=2 and lnC mod 3 = 0) or 1562 | (t=3 and (lnR + lnC) mod 3 = 0) or 1563 | (t=4 and (floor(lnR / 2) + floor(lnC / 3)) mod 2 = 0) or 1564 | (t=5 and ((lnR * lnC) mod 2) + ((lnR * lnC) mod 3) = 0) or 1565 | (t=6 and (((lnR * lnC) mod 2) + ((lnR * lnC) mod 3)) mod 2 = 0) or 1566 | (t=7 and (((lnR + lnC) mod 2) + ((lnR * lnC) mod 3)) mod 2 = 0) then 1567 | 1568 | --switch black and white module 1569 | if gprMasking(t)(r)(c) = '1' then 1570 | gprMasking(t)(r)(c) := '0'; 1571 | else 1572 | gprMasking(t)(r)(c) := '1'; 1573 | end if; 1574 | 1575 | end if; 1576 | 1577 | end if; 1578 | 1579 | END LOOP; 1580 | END LOOP; 1581 | 1582 | p_format_version(t); 1583 | 1584 | p_debug('Mask pattern ' || t || ':', 3); 1585 | p_dbms_output_matrix(gprMasking(t), 3); 1586 | p_debug('------------------------------------------------------------------------------------------', 3); 1587 | 1588 | END LOOP; 1589 | 1590 | --reserved fields marked with 2 and 3 are not necessary any more - change them to 0 and 1 1591 | FOR t IN 0 .. 7 LOOP 1592 | FOR r IN 1 .. f_matrix_size LOOP 1593 | FOR c IN 1 .. f_matrix_size LOOP 1594 | gprMasking(t)(r)(c) := CASE gprMasking(t)(r)(c) WHEN '3' THEN '1' WHEN '2' THEN '0' ELSE gprMasking(t)(r)(c) END; 1595 | END LOOP; 1596 | END LOOP; 1597 | END LOOP; 1598 | 1599 | END p_masking_format_version; 1600 | 1601 | 1602 | PROCEDURE p_penalty_rules(p_masking_out pls_integer default null) IS 1603 | lnRule1 pls_integer; 1604 | lnRule2 pls_integer; 1605 | lnRule3 pls_integer; 1606 | lnRule4 pls_integer; 1607 | 1608 | lnCounter pls_integer; 1609 | lcPattern varchar2(11); 1610 | lnPercent pls_integer; 1611 | 1612 | lnLowestPenalty pls_integer; 1613 | lnChosenMasking pls_integer; 1614 | 1615 | lnDebugTemp pls_integer; 1616 | 1617 | BEGIN 1618 | --large initial values to be sure that first masking (0) is lower than those values 1619 | lnLowestPenalty := 100000000; 1620 | lnChosenMasking := 8; 1621 | 1622 | 1623 | --iterate through all 8 maskings, calculate penalty and find lowest penalty score 1624 | FOR t IN 0 .. 7 LOOP 1625 | 1626 | --rule 1 - five or more same-colored modules in a row (or column) 1627 | lnRule1 := 0; 1628 | 1629 | FOR r IN 1 .. f_matrix_size LOOP --horizontal direction 1630 | lnCounter := 1; 1631 | FOR c IN 2 .. f_matrix_size LOOP 1632 | if gprMasking(t)(r)(c) = gprMasking(t)(r)(c - 1) then 1633 | lnCounter := lnCounter + 1; 1634 | end if; 1635 | if gprMasking(t)(r)(c) <> gprMasking(t)(r)(c - 1) or c = f_matrix_size then 1636 | if lnCounter >= 5 then 1637 | lnRule1 := lnRule1 + 3 + (lnCounter - 5); --if 5 modules are the same color then penalty is 3 plus 1 for every additional module (4 for 6 modules...) 1638 | end if; 1639 | lnCounter := 1; 1640 | end if; 1641 | END LOOP; 1642 | END LOOP; 1643 | 1644 | lnDebugTemp := lnRule1; 1645 | p_debug('Masking ' || t || ', rule 1 - horizontal direction: ' || lnRule1, 2); 1646 | 1647 | FOR c IN 1 .. f_matrix_size LOOP --vertical direction 1648 | lnCounter := 1; 1649 | FOR r IN 2 .. f_matrix_size LOOP 1650 | if gprMasking(t)(r)(c) = gprMasking(t)(r - 1)(c) then 1651 | lnCounter := lnCounter + 1; 1652 | end if; 1653 | if gprMasking(t)(r)(c) <> gprMasking(t)(r - 1)(c) or r = f_matrix_size then 1654 | if lnCounter >= 5 then 1655 | lnRule1 := lnRule1 + 3 + (lnCounter - 5); --if 5 modules are the same color then penalty is 3 plus 1 for every additional module (4 for 6 modules...) 1656 | end if; 1657 | lnCounter := 1; 1658 | end if; 1659 | END LOOP; 1660 | END LOOP; 1661 | 1662 | p_debug('Masking ' || t || ', rule 1 - vertical direction: ' || (lnRule1 - lnDebugTemp), 2); 1663 | p_debug('Masking ' || t || ', rule 1 - sum: ' || lnRule1, 2); 1664 | p_debug(' ', 2); 1665 | 1666 | 1667 | --rule 2 - areas of the same color that are 2x2 modules 1668 | lnRule2 := 0; 1669 | 1670 | FOR r IN 1 .. f_matrix_size - 1 LOOP 1671 | FOR c IN 1 .. f_matrix_size - 1 LOOP 1672 | if 1673 | gprMasking(t)(r)(c) = gprMasking(t)(r + 1)(c) and 1674 | gprMasking(t)(r)(c) = gprMasking(t)(r)(c + 1) and 1675 | gprMasking(t)(r)(c) = gprMasking(t)(r + 1)(c + 1) 1676 | then 1677 | lnRule2 := lnRule2 + 3; 1678 | end if; 1679 | END LOOP; 1680 | END LOOP; 1681 | 1682 | p_debug('Masking ' || t || ', rule 2 - sum: ' || lnRule2, 2); 1683 | p_debug(' ', 2); 1684 | 1685 | 1686 | --rule 3 - patterns of dark-light-dark-dark-dark-light-dark that have four light modules on either side (10111010000 or 00001011101) 1687 | lnRule3 := 0; 1688 | 1689 | FOR r IN 1 .. f_matrix_size LOOP --horizontal direction 1690 | FOR c IN 1 .. f_matrix_size - 10 LOOP 1691 | lcPattern := null; 1692 | FOR p IN 0 .. 10 LOOP 1693 | lcPattern := lcPattern || gprMasking(t)(r)(c + p); 1694 | END LOOP; 1695 | 1696 | if lcPattern in ('10111010000', '00001011101') then 1697 | p_debug(lcPattern || ' (horizontal) found in row ' || r || ' and column ' || c, 3); 1698 | lnRule3 := lnRule3 + 40; 1699 | end if; 1700 | END LOOP; 1701 | END LOOP; 1702 | 1703 | lnDebugTemp := lnRule3; 1704 | p_debug('Masking ' || t || ', rule 3 - horizontal direction: ' || lnRule3, 2); 1705 | 1706 | FOR c IN 1 .. f_matrix_size LOOP --horizontal direction 1707 | FOR r IN 1 .. f_matrix_size - 10 LOOP 1708 | lcPattern := null; 1709 | FOR p IN 0 .. 10 LOOP 1710 | lcPattern := lcPattern || gprMasking(t)(r + p)(c); 1711 | END LOOP; 1712 | 1713 | if lcPattern in ('10111010000', '00001011101') then 1714 | p_debug(lcPattern || ' (vertical) found in row ' || r || ' and column ' || c, 3); 1715 | lnRule3 := lnRule3 + 40; 1716 | end if; 1717 | END LOOP; 1718 | END LOOP; 1719 | 1720 | p_debug('Masking ' || t || ', rule 3 - vertical direction: ' || (lnRule3 - lnDebugTemp), 2); 1721 | p_debug('Masking ' || t || ', rule 3 - sum: ' || lnRule3, 2); 1722 | p_debug(' ', 2); 1723 | 1724 | 1725 | --rule 4 - ratio of light modules to dark modules 1726 | lnCounter := 0; --count dark modules 1727 | FOR r IN 1 .. f_matrix_size LOOP 1728 | FOR c IN 1 .. f_matrix_size LOOP 1729 | if gprMasking(t)(r)(c) = '1' then 1730 | lnCounter := lnCounter + 1; 1731 | end if; 1732 | END LOOP; 1733 | END LOOP; 1734 | 1735 | lnPercent := trim(lnCounter * 100 / (f_matrix_size * f_matrix_size)); --calculate percent of dark modules 1736 | 1737 | p_debug('Masking ' || t || ', rule 4 - total number of modules: ' || (f_matrix_size * f_matrix_size), 2); 1738 | p_debug('Masking ' || t || ', rule 4 - dark modules: ' || lnCounter, 2); 1739 | p_debug('Masking ' || t || ', rule 4 - % of dark modules: ' || lnPercent, 2); 1740 | 1741 | LOOP --find lower multiple of 5 1742 | EXIT WHEN lnPercent mod 5 = 0; 1743 | lnPercent := lnPercent - 1; 1744 | END LOOP; 1745 | 1746 | lnRule4 := least( --subtract 50 from lower and upper multiple of 5; take absolute value; use smallest value; multiply with 10 1747 | abs(lnPercent - 50) / 5, 1748 | abs(lnPercent + 5 - 50) / 5) * 10; 1749 | 1750 | p_debug('Masking ' || t || ', rule 4 - value: ' || lnRule4, 2); 1751 | p_debug(' ', 2); 1752 | 1753 | 1754 | p_debug('Masking ' || t || ', final penalty value: ' || (lnRule1 + lnRule2 + lnRule3 + lnRule4), 2); 1755 | p_debug('-----------------------------------------', 2); 1756 | 1757 | --check if penalty for current masking is lowest 1758 | if (lnRule1 + lnRule2 + lnRule3 + lnRule4) < lnLowestPenalty then 1759 | lnLowestPenalty := (lnRule1 + lnRule2 + lnRule3 + lnRule4); 1760 | lnChosenMasking := t; 1761 | end if; 1762 | 1763 | END LOOP; 1764 | 1765 | p_debug('Masking ' || lnChosenMasking || ' has lowest penalty of ' || lnLowestPenalty || ' and will be used for QR code matrix.', 2); 1766 | 1767 | --copy the best masking into original matrix and use it as result of QR code calculation 1768 | --in case of debugging and selected masking output - use this value instead calculated and make an output 1769 | gprMatrix.delete; 1770 | gprMatrix := gprMatrix MULTISET UNION ALL gprMasking( nvl(p_masking_out, lnChosenMasking) ); 1771 | 1772 | END p_penalty_rules; 1773 | 1774 | 1775 | 1776 | PROCEDURE p_generate_qr( 1777 | p_data varchar2, 1778 | p_error_correction varchar2, 1779 | p_debug boolean default false, 1780 | p_debug_level pls_integer default 1, 1781 | p_masking_out pls_integer default null 1782 | ) IS 1783 | 1784 | lcData varchar2(32000); 1785 | lcFinal varchar2(32000); 1786 | 1787 | BEGIN 1788 | --global variables and tables, which has the same values during QR code generation 1789 | gpbDebug := p_debug; 1790 | gpnDebugLevel := p_debug_level; 1791 | 1792 | gpnMode := f_get_mode(p_data); 1793 | gpnVersion := f_get_version(p_data, p_error_correction); 1794 | 1795 | p_fill_err_cor; 1796 | p_fill_log_antilog; 1797 | 1798 | --init matrix collection and fill static elements 1799 | --gpnVersion := 14; --only for debugging 1800 | p_init_matrix; 1801 | 1802 | --OPERATIONAL PART 1803 | 1804 | --encoded data with all parts (terminal zeros, padding bytes...) 1805 | lcData := f_encode_data(p_data, p_error_correction); 1806 | 1807 | --final structured message (data plus error correction) 1808 | lcFinal := f_final_data_with_ec(lcData, p_error_correction); 1809 | 1810 | --place final message in matrix 1811 | p_place_fm_in_matrix(lcFinal); 1812 | 1813 | --masking; format and version info 1814 | p_masking_format_version(p_error_correction); 1815 | 1816 | --Four Penalty Rules - choose which masking is the easiest to read and copy that masking in matrix variable 1817 | p_penalty_rules(p_masking_out); 1818 | 1819 | 1820 | END p_generate_qr; 1821 | 1822 | 1823 | FUNCTION f_matrix_2_vc2 RETURN varchar2 IS 1824 | lcQR varchar2(32727); 1825 | BEGIN 1826 | FOR t IN 1 .. gprMatrix.count LOOP 1827 | FOR p IN 1 .. gprMatrix.count LOOP 1828 | lcQR := lcQR || nvl(gprMatrix(t)(p), 'X'); 1829 | END LOOP; 1830 | lcQR := lcQR || chr(10); 1831 | END LOOP; 1832 | 1833 | RETURN lcQR; 1834 | END; 1835 | 1836 | 1837 | 1838 | 1839 | 1840 | 1841 | PROCEDURE p_generate_qr_data( 1842 | p_data varchar2, --data going to be encoded into QR code 1843 | p_error_correction varchar2, --L, M, Q or H (see bellow) 1844 | p_qr OUT NOCOPY varchar2, --generated QR code data in format row || newline (chr 10) || row || newline...; 1 for black module, 0 for white 1845 | p_matrix_size OUT pls_integer --matrix size in modules (21, 25, 29...) 1846 | ) IS 1847 | 1848 | BEGIN 1849 | --generate matrix 1850 | p_generate_qr( 1851 | p_data => p_data, 1852 | p_error_correction => p_error_correction, 1853 | p_debug => false, 1854 | p_debug_level => 1); 1855 | 1856 | --convert matrix to vc2 (output) 1857 | p_qr := f_matrix_2_vc2; 1858 | 1859 | --matrix size 1860 | p_matrix_size := f_matrix_size; 1861 | 1862 | END p_generate_qr_data; 1863 | 1864 | 1865 | PROCEDURE p_qr_debug( 1866 | p_data varchar2, --data going to be encoded into QR code 1867 | p_error_correction varchar2, --L, M, Q or H (see bellow) 1868 | p_debug boolean default true, --should DBMS OUTPUT be printed 1869 | p_debug_level pls_integer default 1, --debug level (1, 2, 3...) - details to be printed in debug output 1870 | p_masking_out pls_integer default null, 1871 | p_qr OUT NOCOPY varchar2, 1872 | p_matrix_size OUT pls_integer 1873 | ) IS 1874 | 1875 | BEGIN 1876 | --generate matrix 1877 | p_generate_qr( 1878 | p_data => p_data, 1879 | p_error_correction => p_error_correction, 1880 | p_debug => p_debug, 1881 | p_debug_level => p_debug_level, 1882 | p_masking_out => p_masking_out); 1883 | 1884 | --convert matrix to debug form 1885 | p_qr := f_matrix_2_vc2; 1886 | 1887 | --matrix size 1888 | p_matrix_size := f_matrix_size; 1889 | 1890 | END p_qr_debug; 1891 | 1892 | 1893 | 1894 | FUNCTION f_qr_as_html_table( 1895 | p_data varchar2, --data going to be encoded into QR code 1896 | p_error_correction varchar2, --L, M, Q or H 1897 | p_module_size_in_px pls_integer default 8, --module size in pixels 1898 | p_margines boolean default false --margines around QR code (4 modules) 1899 | ) RETURN clob IS 1900 | 1901 | lcQR varchar2(32727); 1902 | lnMatrixSize pls_integer; 1903 | lcClob clob; 1904 | 1905 | PROCEDURE p_add_clob(lcText varchar2) IS 1906 | BEGIN 1907 | lcClob := lcClob || lcText || chr(10); 1908 | END; 1909 | 1910 | BEGIN 1911 | if p_data is null then 1912 | lcClob := 'no data to display.'; 1913 | RETURN lcClob; 1914 | end if; 1915 | 1916 | 1917 | p_generate_qr_data( 1918 | p_data => p_data, 1919 | p_error_correction => p_error_correction, 1920 | p_qr => lcQR, 1921 | p_matrix_size => lnMatrixSize 1922 | ); 1923 | 1924 | p_add_clob(''); 1925 | 1926 | --columns (for column width defined in style - inline on page) 1927 | FOR t IN 1 .. lnMatrixSize + (CASE WHEN p_margines THEN 8 ELSE 0 END) LOOP 1928 | p_add_clob(''); 1929 | END LOOP; 1930 | 1931 | --top margine - 4 module rows 1932 | if p_margines then 1933 | FOR t in 1 .. 4 LOOP 1934 | p_add_clob(''); 1935 | END LOOP; 1936 | end if; 1937 | 1938 | 1939 | FOR t IN 1 .. lnMatrixSize LOOP 1940 | 1941 | --new row 1942 | p_add_clob(''); 1943 | 1944 | --left margine - 4 modules 1945 | if p_margines then 1946 | FOR z in 1 .. 4 LOOP 1947 | p_add_clob(''); 1948 | END LOOP; 1949 | end if; 1950 | 1951 | --modules in row 1952 | FOR p IN 1 .. lnMatrixSize LOOP 1953 | 1954 | p_add_clob(''); 1960 | 1961 | END LOOP; 1962 | 1963 | --right margine - 4 modules 1964 | if p_margines then 1965 | FOR z in 1 .. 4 LOOP 1966 | p_add_clob(''); 1967 | END LOOP; 1968 | end if; 1969 | 1970 | p_add_clob(''); 1971 | 1972 | END LOOP; 1973 | 1974 | --bottom margine - 4 module rows 1975 | if p_margines then 1976 | FOR t in 1 .. 4 LOOP 1977 | p_add_clob(''); 1978 | END LOOP; 1979 | end if; 1980 | 1981 | p_add_clob('
'); 1982 | 1983 | RETURN lcClob; 1984 | 1985 | END f_qr_as_html_table; 1986 | 1987 | 1988 | PROCEDURE p_print_clob_htp( 1989 | p_clob IN OUT NOCOPY clob 1990 | ) IS 1991 | 1992 | lnFrom pls_integer := 1; 1993 | lnTo pls_integer; 1994 | 1995 | BEGIN 1996 | LOOP 1997 | lnTo := instr(p_clob, chr(10), lnFrom); 1998 | if lnTo = 0 then 1999 | lnTo := length(p_clob); 2000 | end if; 2001 | 2002 | htp.p(substr(p_clob, lnFrom, lnTo - lnFrom)); 2003 | 2004 | lnFrom := lnTo + 1; 2005 | 2006 | EXIT WHEN lnTo = length(p_clob); 2007 | END LOOP; 2008 | 2009 | END p_print_clob_htp; 2010 | 2011 | 2012 | PROCEDURE p_print_clob_htp_dbms_lob( 2013 | p_clob IN OUT NOCOPY clob 2014 | ) IS 2015 | 2016 | L_POSITION NUMBER; 2017 | L_LENGTH NUMBER; 2018 | L_BUFFER VARCHAR(8000 CHAR); 2019 | 2020 | BEGIN 2021 | L_LENGTH := DBMS_LOB.GETLENGTH(p_clob); 2022 | L_POSITION := 1; 2023 | LOOP 2024 | EXIT WHEN L_POSITION > L_LENGTH ; 2025 | L_BUFFER := DBMS_LOB.SUBSTR(p_clob, 8000, L_POSITION); 2026 | HTP.PRN(L_BUFFER); 2027 | L_POSITION := L_POSITION + 8000; 2028 | END LOOP; 2029 | END p_print_clob_htp_dbms_lob; 2030 | 2031 | 2032 | PROCEDURE p_qr_as_html_table( 2033 | p_data varchar2, --data going to be encoded into QR code 2034 | p_error_correction varchar2, --L, M, Q or H 2035 | p_module_size_in_px pls_integer default 8, --module size in pixels 2036 | p_margines boolean default false --margines around QR code (4 modules) 2037 | ) IS 2038 | 2039 | lcClob clob; 2040 | 2041 | BEGIN 2042 | if p_data is null then 2043 | htp.p('no data to display.'); 2044 | RETURN; 2045 | end if; 2046 | 2047 | lcClob := f_qr_as_html_table(p_data, p_error_correction, p_module_size_in_px, p_margines); 2048 | 2049 | p_print_clob_htp(lcClob); 2050 | 2051 | /* 2052 | LOOP 2053 | lnTo := instr(lcClob, chr(10), lnFrom); 2054 | if lnTo = 0 then 2055 | lnTo := length(lcClob); 2056 | end if; 2057 | 2058 | htp.p(substr(lcClob, lnFrom, lnTo - lnFrom)); 2059 | 2060 | lnFrom := lnTo + 1; 2061 | 2062 | EXIT WHEN lnTo = length(lcClob); 2063 | END LOOP; 2064 | */ 2065 | 2066 | END p_qr_as_html_table; 2067 | 2068 | 2069 | 2070 | 2071 | FUNCTION unsigned_short(s in pls_integer) RETURN raw IS 2072 | lrRet raw(4); 2073 | BEGIN 2074 | lrRet := UTL_RAW.reverse( UTL_RAW.cast_from_binary_integer(s) ); 2075 | RETURN UTL_RAW.substr(lrRet, 1, 2); 2076 | END unsigned_short; 2077 | 2078 | 2079 | FUNCTION unsigned_int(i in pls_integer) RETURN raw IS 2080 | lrRet raw(4); 2081 | BEGIN 2082 | lrRet := UTL_RAW.reverse( UTL_RAW.cast_from_binary_integer(i) ); 2083 | RETURN lrRet; 2084 | END unsigned_int; 2085 | 2086 | 2087 | 2088 | FUNCTION f_qr_as_bmp( 2089 | p_data varchar2, --data going to be encoded into QR code 2090 | p_error_correction varchar2, --L, M, Q or H 2091 | p_margines varchar2 default 'N', --margines around QR code (4 modules) - values Y or N 2092 | p_foreground_color varchar2 default '000000', -- HEX representation of the RGB values of the foreground color 2093 | p_background_color varchar2 default 'FFFFFF'-- HEX representation of the RGB values of the background color 2094 | ) RETURN blob IS 2095 | 2096 | lcQR varchar2(32727); 2097 | lnMatrixSize pls_integer; 2098 | lnZeros pls_integer; 2099 | lnImageBytes pls_integer; 2100 | lnWidthHeight pls_integer; 2101 | 2102 | lbBlob blob; 2103 | lrLine raw(500); 2104 | 2105 | BEGIN 2106 | --if no data passed then return null 2107 | if p_data is null then 2108 | return null; 2109 | end if; 2110 | 2111 | p_generate_qr_data( 2112 | p_data => p_data, 2113 | p_error_correction => p_error_correction, 2114 | p_qr => lcQR, 2115 | p_matrix_size => lnMatrixSize 2116 | ); 2117 | 2118 | 2119 | DBMS_LOB.createTemporary(lbBlob, true); 2120 | 2121 | --Header 2122 | lnWidthHeight := lnMatrixSize + (CASE WHEN p_margines = 'Y' THEN 8 ELSE 0 END); 2123 | lnImageBytes := lnWidthHeight * lnWidthHeight * 8; 2124 | 2125 | dbms_lob.append(lbBlob, utl_raw.cast_to_raw('BM')); -- Pos 0 - fixed 2126 | dbms_lob.append(lbBlob, unsigned_int(14 + 40 + 8 + lnImageBytes)); -- Pos 2 - file size (62 as header size + data size + color pallete) 2127 | dbms_lob.append(lbBlob, unsigned_int(0)); -- Pos 6, unused / reserved, value 0 2128 | dbms_lob.append(lbBlob, unsigned_int(14 + 40 + 8)); -- Pos 10, offset to image data - header size + information size + color pallete 2129 | 2130 | -- Information 2131 | dbms_lob.append(lbBlob, unsigned_int(40)); -- Pos 14 - size of information header (always 40) 2132 | dbms_lob.append(lbBlob, unsigned_int(lnWidthHeight * 8)); -- Pos 18 - width 2133 | dbms_lob.append(lbBlob, unsigned_int(lnWidthHeight * 8)); -- Pos 22 - height 2134 | dbms_lob.append(lbBlob, unsigned_short(1)); -- Pos 26, planes 2135 | dbms_lob.append(lbBlob, unsigned_short(1)); -- Pos 28, bits per pixel 2136 | dbms_lob.append(lbBlob, unsigned_int(0)); -- Pos 30, no compression 2137 | dbms_lob.append(lbBlob, unsigned_int(lnImageBytes)); -- Pos 34 - image data size 2138 | dbms_lob.append(lbBlob, unsigned_int(0)); -- Pos 38, x pixels/meter 2139 | dbms_lob.append(lbBlob, unsigned_int(0)); -- Pos 42, y pixels/meter 2140 | dbms_lob.append(lbBlob, unsigned_int(0)); -- Pos 46, Number of colors 2141 | dbms_lob.append(lbBlob, unsigned_int(0)); -- Pos 50, Important colors 2142 | 2143 | --Colors 2144 | dbms_lob.append(lbBlob, unsigned_int(to_number(p_background_color, 'xxxxxx'))); 2145 | dbms_lob.append(lbBlob, unsigned_int(to_number(p_foreground_color, 'xxxxxx'))); 2146 | 2147 | 2148 | 2149 | --Data 2150 | 2151 | --zeros at the end of the scan line (scan line in bytes must be mod 4) 2152 | lnZeros := 0; 2153 | LOOP 2154 | EXIT WHEN (lnWidthHeight + lnZeros) mod 4 = 0; 2155 | lnZeros := lnZeros + 1; 2156 | END LOOP; 2157 | 2158 | --bottom margine 2159 | if p_margines = 'Y' then 2160 | lrLine := utl_raw.copies( utl_raw.cast_to_raw(chr(0)), lnWidthHeight + lnZeros); 2161 | 2162 | FOR t IN 1 .. 32 LOOP 2163 | dbms_lob.append(lbBlob, utl_raw.substr(lrLine, 1, lnWidthHeight + lnZeros)); 2164 | END LOOP; 2165 | end if; 2166 | 2167 | --data for scan lines 2168 | FOR r IN REVERSE 1 .. lnMatrixSize LOOP 2169 | --first prepare scan line as raw data 2170 | if p_margines = 'Y' then 2171 | --left margine 2172 | lrLine := utl_raw.copies( utl_raw.cast_to_raw(chr(0)), 4); 2173 | else 2174 | --no margines 2175 | lrLine := null; 2176 | end if; 2177 | 2178 | --data from matrix 2179 | FOR c IN 1 .. lnMatrixSize LOOP 2180 | lrLine := lrLine || utl_raw.cast_to_raw(chr( 2181 | CASE WHEN substr(lcQR, (r - 1) * (lnMatrixSize + 1) + c, 1) = '1' THEN 255 ELSE 0 END 2182 | )); 2183 | END LOOP; 2184 | 2185 | --right margine 2186 | if p_margines = 'Y' then 2187 | lrLine := lrLine || utl_raw.copies( utl_raw.cast_to_raw(chr(0)), 4); 2188 | end if; 2189 | 2190 | --trailing zeroes (mod 4) 2191 | FOR c IN 1 .. lnZeros LOOP 2192 | lrLine := lrLine || utl_raw.cast_to_raw(chr(0)); 2193 | END LOOP; 2194 | 2195 | --8 scan lines in file because module is 8x8 pixels 2196 | FOR t IN 1 .. 8 LOOP 2197 | dbms_lob.append(lbBlob, utl_raw.substr(lrLine, 1, lnWidthHeight + lnZeros)); 2198 | END LOOP; 2199 | END LOOP; 2200 | 2201 | --top margine (4 modules) 2202 | if p_margines = 'Y' then 2203 | lrLine := utl_raw.copies( utl_raw.cast_to_raw(chr(0)), lnWidthHeight + lnZeros); 2204 | 2205 | FOR t IN 1 .. 32 LOOP 2206 | dbms_lob.append(lbBlob, utl_raw.substr(lrLine, 1, lnWidthHeight + lnZeros)); 2207 | END LOOP; 2208 | end if; 2209 | 2210 | RETURN lbBlob; 2211 | END f_qr_as_bmp; 2212 | 2213 | 2214 | 2215 | FUNCTION f_qr_as_long_raw( 2216 | p_data varchar2, --data going to be encoded into QR code 2217 | p_error_correction varchar2, --L, M, Q or H 2218 | p_margines varchar2 default 'N' --margines around QR code (4 modules) - values Y or N 2219 | ) RETURN long raw IS 2220 | 2221 | lcQR varchar2(32727); 2222 | lnMatrixSize pls_integer; 2223 | lnZeros pls_integer; 2224 | lnImageBytes pls_integer; 2225 | lnWidthHeight pls_integer; 2226 | 2227 | lbBlob long raw; 2228 | lrLine raw(500); 2229 | 2230 | BEGIN 2231 | --if no data passed then return 2232 | if p_data is null then 2233 | return null; 2234 | end if; 2235 | 2236 | p_generate_qr_data( 2237 | p_data => p_data, 2238 | p_error_correction => p_error_correction, 2239 | p_qr => lcQR, 2240 | p_matrix_size => lnMatrixSize 2241 | ); 2242 | 2243 | --Header 2244 | lnWidthHeight := lnMatrixSize + (CASE WHEN p_margines = 'Y' THEN 8 ELSE 0 END); 2245 | lnImageBytes := lnWidthHeight * lnWidthHeight * 8; 2246 | 2247 | lbBlob := utl_raw.concat(lbBlob, utl_raw.cast_to_raw('BM')); -- Pos 0 - fixed 2248 | lbBlob := utl_raw.concat(lbBlob, unsigned_int(14 + 40 + 8 + lnImageBytes)); -- Pos 2 - file size (62 as header size + data size + color pallete) 2249 | lbBlob := utl_raw.concat(lbBlob, unsigned_int(0)); -- Pos 6, unused / reserved, value 0 2250 | lbBlob := utl_raw.concat(lbBlob, unsigned_int(14 + 40 + 8)); -- Pos 10, offset to image data - header size + information size + color pallete 2251 | 2252 | -- Information 2253 | lbBlob := utl_raw.concat(lbBlob, unsigned_int(40)); -- Pos 14 - size of information header (always 40) 2254 | lbBlob := utl_raw.concat(lbBlob, unsigned_int(lnWidthHeight * 8)); -- Pos 18 - width 2255 | lbBlob := utl_raw.concat(lbBlob, unsigned_int(lnWidthHeight * 8)); -- Pos 22 - height 2256 | lbBlob := utl_raw.concat(lbBlob, unsigned_short(1)); -- Pos 26, planes 2257 | lbBlob := utl_raw.concat(lbBlob, unsigned_short(1)); -- Pos 28, bits per pixel 2258 | lbBlob := utl_raw.concat(lbBlob, unsigned_int(0)); -- Pos 30, no compression 2259 | lbBlob := utl_raw.concat(lbBlob, unsigned_int(lnImageBytes)); -- Pos 34 - image data size 2260 | lbBlob := utl_raw.concat(lbBlob, unsigned_int(0)); -- Pos 38, x pixels/meter 2261 | lbBlob := utl_raw.concat(lbBlob, unsigned_int(0)); -- Pos 42, y pixels/meter 2262 | lbBlob := utl_raw.concat(lbBlob, unsigned_int(0)); -- Pos 46, Number of colors 2263 | lbBlob := utl_raw.concat(lbBlob, unsigned_int(0)); -- Pos 50, Important colors 2264 | 2265 | --Colors 2266 | lbBlob := utl_raw.concat(lbBlob, unsigned_int(16777215)); -- White (FF FF FF 00) 2267 | lbBlob := utl_raw.concat(lbBlob, unsigned_int(0)); -- Black (00 00 00 00) 2268 | 2269 | 2270 | 2271 | --Data 2272 | 2273 | --zeros at the end of the scan line (scan line in bytes must be mod 4) 2274 | lnZeros := 0; 2275 | LOOP 2276 | EXIT WHEN (lnWidthHeight + lnZeros) mod 4 = 0; 2277 | lnZeros := lnZeros + 1; 2278 | END LOOP; 2279 | 2280 | --bottom margine 2281 | if p_margines = 'Y' then 2282 | lrLine := utl_raw.copies( utl_raw.cast_to_raw(chr(0)), lnWidthHeight + lnZeros); 2283 | 2284 | FOR t IN 1 .. 32 LOOP 2285 | lbBlob := utl_raw.concat(lbBlob, utl_raw.substr(lrLine, 1, lnWidthHeight + lnZeros)); 2286 | END LOOP; 2287 | end if; 2288 | 2289 | --data for scan lines 2290 | FOR r IN REVERSE 1 .. lnMatrixSize LOOP 2291 | --first prepare scan line as raw data 2292 | if p_margines = 'Y' then 2293 | --left margine 2294 | lrLine := utl_raw.copies( utl_raw.cast_to_raw(chr(0)), 4); 2295 | else 2296 | --no margines 2297 | lrLine := null; 2298 | end if; 2299 | 2300 | --data from matrix 2301 | FOR c IN 1 .. lnMatrixSize LOOP 2302 | lrLine := lrLine || utl_raw.cast_to_raw(chr( 2303 | CASE WHEN substr(lcQR, (r - 1) * (lnMatrixSize + 1) + c, 1) = '1' THEN 255 ELSE 0 END 2304 | )); 2305 | END LOOP; 2306 | 2307 | --right margine 2308 | if p_margines = 'Y' then 2309 | lrLine := lrLine || utl_raw.copies( utl_raw.cast_to_raw(chr(0)), 4); 2310 | end if; 2311 | 2312 | --trailing zeroes (mod 4) 2313 | FOR c IN 1 .. lnZeros LOOP 2314 | lrLine := lrLine || utl_raw.cast_to_raw(chr(0)); 2315 | END LOOP; 2316 | 2317 | --8 scan lines in file because module is 8x8 pixels 2318 | FOR t IN 1 .. 8 LOOP 2319 | lbBlob := utl_raw.concat(lbBlob, utl_raw.substr(lrLine, 1, lnWidthHeight + lnZeros)); 2320 | END LOOP; 2321 | END LOOP; 2322 | 2323 | --top margine (4 modules) 2324 | if p_margines = 'Y' then 2325 | lrLine := utl_raw.copies( utl_raw.cast_to_raw(chr(0)), lnWidthHeight + lnZeros); 2326 | 2327 | FOR t IN 1 .. 32 LOOP 2328 | lbBlob := utl_raw.concat(lbBlob, utl_raw.substr(lrLine, 1, lnWidthHeight + lnZeros)); 2329 | END LOOP; 2330 | end if; 2331 | 2332 | RETURN lbBlob; 2333 | END f_qr_as_long_raw; 2334 | 2335 | 2336 | 2337 | PROCEDURE p_qr_as_img_tag_base64( 2338 | p_data varchar2, --data going to be encoded into QR code 2339 | p_error_correction varchar2, --L, M, Q or H 2340 | p_image_size_px pls_integer, 2341 | p_margines varchar2 default 'N' --margines around QR code (4 modules) - values Y or N 2342 | ) IS 2343 | 2344 | lbBlob blob; 2345 | l_step PLS_INTEGER := 12000; -- make sure you set a multiple of 3 not higher than 24573 2346 | 2347 | BEGIN 2348 | lbBlob := f_qr_as_bmp(p_data, p_error_correction, p_margines); 2349 | 2350 | htp.prn('qr code'); 2357 | 2358 | END; 2359 | 2360 | 2361 | 2362 | FUNCTION f_qr_as_svg( 2363 | p_data varchar2, --data going to be encoded into QR code 2364 | p_error_correction varchar2, --L, M, Q or H 2365 | p_module_size_px pls_integer default 8, --modul size in pixels 2366 | p_margines_yn varchar2 default 'N', --margines around QR code (4 modules) - values Y or N 2367 | p_module_color varchar2 default 'black', --colors are defined as SVG named colors OR rgb (with # or rgb function) 2368 | p_background_color varchar2 default 'white', 2369 | p_module_rounded_px pls_integer default 0, --0 - sharp corners; > 0 - rounded in pixels 2370 | p_logo_yn varchar2 default 'N', 2371 | p_logo_size_percent number default 20, 2372 | p_logo_image clob default null, 2373 | p_logo_back_rect_yn varchar2 default 'Y', 2374 | p_logo_back_rect_color varchar2 default 'white', 2375 | p_logo_back_rect_round_px pls_integer default 0, 2376 | p_logo_margine_px number default 5 2377 | ) RETURN clob IS 2378 | 2379 | lcQR varchar2(32727); 2380 | lnMatrixSize pls_integer; 2381 | 2382 | lnCanvasSize pls_integer; 2383 | lnX pls_integer; 2384 | lnY pls_integer; 2385 | 2386 | lcClob clob; 2387 | 2388 | PROCEDURE p_add_clob(lcText varchar2) IS 2389 | BEGIN 2390 | lcClob := lcClob || lcText || chr(10); 2391 | END; 2392 | 2393 | BEGIN 2394 | if p_data is null then 2395 | lcClob := 'no data to display.'; 2396 | RETURN lcClob; 2397 | end if; 2398 | 2399 | 2400 | p_generate_qr_data( 2401 | p_data => p_data, 2402 | p_error_correction => p_error_correction, 2403 | p_qr => lcQR, 2404 | p_matrix_size => lnMatrixSize 2405 | ); 2406 | 2407 | --canvas size and top left coordinate of first module (dependent of margins parameter) 2408 | lnCanvasSize := (lnMatrixSize + (CASE WHEN p_margines_yn = 'Y' THEN 8 ELSE 0 END) ) * p_module_size_px; 2409 | lnX := CASE WHEN p_margines_yn = 'Y' THEN 4 * p_module_size_px ELSE 0 END; 2410 | lnY := lnX; 2411 | 2412 | --init SVG tag 2413 | p_add_clob(''); 2414 | 2415 | --draw black modules (background is already white) 2416 | FOR t IN 1 .. length(lcQR) LOOP 2417 | 2418 | if substr(lcQR, t, 1) = '1' then 2419 | p_add_clob(' 0 THEN 'rx="' || p_module_rounded_px || '"' ELSE null END || '/>'); 2420 | lnX := lnX + p_module_size_px; 2421 | 2422 | elsif substr(lcQR, t, 1) = chr(10) then 2423 | lnX := CASE WHEN p_margines_yn = 'Y' THEN 4 * p_module_size_px ELSE 0 END; 2424 | lnY := lnY + p_module_size_px; 2425 | 2426 | else 2427 | lnX := lnX + p_module_size_px; 2428 | 2429 | end if; 2430 | 2431 | END LOOP; 2432 | 2433 | 2434 | --add logo (optional) 2435 | if p_logo_yn = 'Y' then 2436 | DECLARE 2437 | lnLogoBckWidth number; 2438 | lnLogoBckPos number; 2439 | lnLogoWidth number; 2440 | lnLogoPos number; 2441 | 2442 | BEGIN 2443 | lnLogoBckWidth := round(lnMatrixSize * p_module_size_px * p_logo_size_percent / 100, 2); 2444 | lnLogoBckPos := (lnCanvasSize / 2) - (lnLogoBckWidth / 2); 2445 | lnLogoWidth := lnLogoBckWidth - p_logo_margine_px * 2; 2446 | lnLogoPos := lnLogoBckPos + p_logo_margine_px; 2447 | 2448 | if p_logo_back_rect_yn = 'Y' then 2449 | p_add_clob(''); 2450 | end if; 2451 | 2452 | p_add_clob(''); 2453 | 2454 | END; 2455 | end if; 2456 | 2457 | 2458 | --finish SVG 2459 | p_add_clob(''); 2460 | 2461 | RETURN lcClob; 2462 | 2463 | END f_qr_as_svg; 2464 | 2465 | 2466 | PROCEDURE p_qr_as_svg( 2467 | p_data varchar2, --data going to be encoded into QR code 2468 | p_error_correction varchar2, --L, M, Q or H 2469 | p_module_size_px pls_integer default 8, --modul size in pixels 2470 | p_margines_yn varchar2 default 'N', --margines around QR code (4 modules) - values Y or N 2471 | p_module_color varchar2 default 'black', --colors are defined as SVG named colors OR rgb (with # or rgb function) 2472 | p_background_color varchar2 default 'white', 2473 | p_module_rounded_px pls_integer default 0, --0 - sharp corners; > 0 - rounded in pixels 2474 | p_logo_yn varchar2 default 'N', 2475 | p_logo_size_percent number default 20, 2476 | p_logo_image clob default null, 2477 | p_logo_back_rect_yn varchar2 default 'Y', 2478 | p_logo_back_rect_color varchar2 default 'white', 2479 | p_logo_back_rect_round_px pls_integer default 0, 2480 | p_logo_margine_px number default 5 2481 | ) IS 2482 | 2483 | lcClob clob; 2484 | 2485 | BEGIN 2486 | lcClob := ZT_QR.f_qr_as_svg( 2487 | p_data => p_data, 2488 | p_error_correction => p_error_correction, 2489 | p_margines_yn => p_margines_yn, 2490 | p_module_size_px => p_module_size_px, 2491 | p_module_color => p_module_color, 2492 | p_background_color => p_background_color, 2493 | p_module_rounded_px => p_module_rounded_px, 2494 | p_logo_yn => p_logo_yn, 2495 | p_logo_size_percent => p_logo_size_percent, 2496 | p_logo_image => p_logo_image, 2497 | p_logo_back_rect_yn => p_logo_back_rect_yn, 2498 | p_logo_back_rect_color => p_logo_back_rect_color, 2499 | p_logo_back_rect_round_px => p_logo_back_rect_round_px, 2500 | p_logo_margine_px => p_logo_margine_px 2501 | ); 2502 | 2503 | p_print_clob_htp(lcClob); 2504 | 2505 | END p_qr_as_svg; 2506 | 2507 | 2508 | PROCEDURE p_save_file( 2509 | p_document blob, 2510 | p_file_name varchar2, 2511 | p_folder varchar2 2512 | ) IS 2513 | 2514 | lfFile utl_file.file_type; 2515 | lnLen pls_integer := 32767; 2516 | 2517 | BEGIN 2518 | lfFile := utl_file.fopen(p_folder, p_file_name, 'wb'); 2519 | FOR i in 0 .. trunc( (dbms_lob.getlength(p_document) - 1 ) / lnLen ) LOOP 2520 | utl_file.put_raw(lfFile, dbms_lob.substr(p_document, lnLen, i * lnLen + 1)); 2521 | END LOOP; 2522 | utl_file.fclose(lfFile); 2523 | END; 2524 | 2525 | 2526 | 2527 | END ZT_QR; 2528 | / 2529 | --------------------------------------------------------------------------------