├── Templates ├── Front.jpeg └── back.jpeg ├── resources └── amma's Arrow.png ├── Print Template └── Print Template.jpeg ├── icons ├── square-fill.svg ├── Phone.svg ├── User.svg └── Employe_Code.svg ├── print.html ├── README.md ├── index.html ├── printstyle.css ├── print.js ├── style.css └── index.js /Templates/Front.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ungaaaabungaaa/ID-Card-Generator/HEAD/Templates/Front.jpeg -------------------------------------------------------------------------------- /Templates/back.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ungaaaabungaaa/ID-Card-Generator/HEAD/Templates/back.jpeg -------------------------------------------------------------------------------- /resources/amma's Arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ungaaaabungaaa/ID-Card-Generator/HEAD/resources/amma's Arrow.png -------------------------------------------------------------------------------- /Print Template/Print Template.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ungaaaabungaaa/ID-Card-Generator/HEAD/Print Template/Print Template.jpeg -------------------------------------------------------------------------------- /icons/square-fill.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/Phone.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/User.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icons/Employe_Code.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /print.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Print 10 | 11 | 12 | 13 |
14 |
15 | 17 | 18 |
19 |
20 | 22 | 23 |
24 | 25 |
26 | 28 | 29 | 31 |
32 |
33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ID-Card-Generator 2 | ## 🔍 Overview: 3 | ![alt text](https://i.imgur.com/vN5LWqx.png) 4 | IDCard Generator is a powerful and user-friendly web application designed specifically for HR professionals and administrators. This innovative tool simplifies the process of creating personalized employee ID cards with ease. The web app comes equipped with a convenient print template feature, allowing you to effortlessly print the generated ID cards. 5 | ## 🖼️ Features: 6 | ![alt text](https://i.imgur.com/NUsVj0p.png) 7 | 1. User-Friendly Interface: 8 | The intuitive interface ensures a seamless experience for users, even with minimal technical expertise. 9 | Simple and easy-to-navigate design for quick ID card generation. 10 | 2. Customizable Fields: 11 | Input employee details such as Name, Employee Code, Emergency Contact, and Blood Group effortlessly. 12 | Select a profile image to be displayed on the ID card. 13 | 14 | 3.Preview Options: 15 | Preview the generated ID card in real-time before finalizing. 16 | Toggle between front and back views to ensure accuracy. 17 | 18 | 4.Print Template: 19 | Access a comprehensive print template that allows for easy printing of the generated ID cards. 20 | Print both the front and back views for a complete and professional ID card. 21 | 22 | 5.Toasting Messages: 23 | Receive informative toast messages for important actions, ensuring a smooth user experience. 24 | Messages provide real-time feedback on successful ID card generation and other events. 25 | 26 | ## How It Works: 27 | 28 | 1. Enter employee details in the customizable fields. 29 | 2. Upload a profile image for the ID card. 30 | 3. Preview the ID card in both front and back views. 31 | 4. Generate the ID card and utilize the print template for physical copies. 32 | 5. Download and share the professionally designed ID cards. 33 | 34 | ## 📄 Compatibility: 35 | Compatible with modern web browsers, ensuring a consistent experience for users across different platforms. 36 | 37 | ## 🔄 Switch between Views: 38 | Easily navigate between the form input view and the ID card preview view with just a click. 39 | Dynamic interaction for a user-friendly experience. 40 | Get started with IDCard Generator now and elevate your employee ID card creation process. Simplify, personalize, and print professional ID cards effortlessly! 41 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | IDCard Genarator 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 | 19 | 20 |
21 | 32 |
33 | 34 | 36 | Preview Pick 37 |
38 |
39 |
40 |
41 |
42 |
43 | 45 |
46 |
47 | ID Card Preview Item 48 |
49 |
50 | 51 | 52 | 54 |
55 |
56 |
57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /printstyle.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | margin: 0; 4 | padding: 0; 5 | width: 100vw; 6 | height: 100vh; 7 | background-color: #FF7315; 8 | display: grid; 9 | overflow: hidden; 10 | grid-template-columns: 4% 34% 1% 36% 19% 4%; 11 | grid-template-rows: 5% 8% 74% 8% 5%; 12 | grid-column-gap: 0px; 13 | grid-row-gap: 0px; 14 | } 15 | 16 | ::-webkit-scrollbar { 17 | width: 0; 18 | background: transparent; 19 | } 20 | 21 | /* SnackBar Toast */ 22 | 23 | #snackbar { 24 | visibility: hidden; 25 | min-width: 250px; 26 | margin-left: -125px; 27 | background-color: #000; 28 | color: #FFF; 29 | font-size: 18px; 30 | outline: none; 31 | text-overflow: ellipsis; 32 | text-align: center; 33 | border-radius: 12px; 34 | padding: 16px; 35 | position: fixed; 36 | z-index: 1; 37 | left: 50%; 38 | bottom: 30px; 39 | font-family: 'Roboto', sans-serif; 40 | } 41 | 42 | /* SnackBar Toast */ 43 | #snackbar.show { 44 | visibility: visible; 45 | -webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s; 46 | animation: fadein 0.5s, fadeout 0.5s 2.5s; 47 | } 48 | 49 | /* Animations to fade the snackbar in and out */ 50 | @-webkit-keyframes fadein { 51 | from { 52 | bottom: 0; 53 | opacity: 0; 54 | } 55 | 56 | to { 57 | bottom: 30px; 58 | opacity: 1; 59 | } 60 | } 61 | 62 | @keyframes fadein { 63 | from { 64 | bottom: 0; 65 | opacity: 0; 66 | } 67 | 68 | to { 69 | bottom: 30px; 70 | opacity: 1; 71 | } 72 | } 73 | 74 | @-webkit-keyframes fadeout { 75 | from { 76 | bottom: 30px; 77 | opacity: 1; 78 | } 79 | 80 | to { 81 | bottom: 0; 82 | opacity: 0; 83 | } 84 | } 85 | 86 | @keyframes fadeout { 87 | from { 88 | bottom: 30px; 89 | opacity: 1; 90 | } 91 | 92 | to { 93 | bottom: 0; 94 | opacity: 0; 95 | } 96 | } 97 | 98 | /* SnackBar Toast */ 99 | 100 | .div_1 { 101 | width: 100%; 102 | height: 100%; 103 | background-color: #000000; 104 | grid-row-start: 3; 105 | grid-row-end: 3; 106 | grid-column-start: 2; 107 | grid-column-end: 4; 108 | box-shadow: rgba(0, 0, 0, 0.2) 0px 12px 28px 0px, rgba(0, 0, 0, 0.1) 0px 2px 4px 0px, rgba(255, 255, 255, 0.05) 0px 0px 0px 1px inset; 109 | } 110 | 111 | .div_2 { 112 | width: 85%; 113 | height: 100%; 114 | border-radius: 36px; 115 | background-color: #FFF; 116 | grid-row-start: 2; 117 | grid-row-end: 5; 118 | overflow: hidden; 119 | grid-column-start: 2; 120 | grid-column-end: 3; 121 | box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; 122 | } 123 | 124 | .div_3 { 125 | width: 85%; 126 | height: 100%; 127 | border-radius: 36px; 128 | background-color: #FFF; 129 | grid-row-start: 2; 130 | grid-row-end: 5; 131 | overflow: hidden; 132 | grid-column-start: 4; 133 | grid-column-end: 5; 134 | box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; 135 | } 136 | 137 | .div_4 { 138 | width: 100%; 139 | height: 100%; 140 | grid-row-start: 3; 141 | grid-row-end: 4; 142 | grid-column-start: 5; 143 | grid-column-end: 6; 144 | display: flex; 145 | flex-direction: column; 146 | align-items: center; 147 | justify-content: center; 148 | } 149 | 150 | .print_button { 151 | background-color: #000; 152 | color: #FFF; 153 | font-size: larger; 154 | width: 86%; 155 | padding-top: 21px; 156 | padding-bottom: 21px; 157 | border-radius: 21px; 158 | border: none; 159 | margin-top: 4.1%; 160 | margin-bottom: 4.1%; 161 | text-align: center; 162 | display: block; 163 | box-sizing: border-box; 164 | } 165 | 166 | #Card1 { 167 | width: 100%; 168 | height: 100%; 169 | overflow: hidden; 170 | object-fit: contain; 171 | } 172 | 173 | #Card1::before { 174 | content: none !important; 175 | } 176 | 177 | #Card2 { 178 | width: 100%; 179 | height: 100%; 180 | overflow: hidden; 181 | object-fit: contain; 182 | } 183 | 184 | #Card2::before { 185 | content: none !important; 186 | } -------------------------------------------------------------------------------- /print.js: -------------------------------------------------------------------------------- 1 | // Snackbar 2 | function snackbar(message) { 3 | var x = document.getElementById("snackbar"); 4 | x.textContent = message; 5 | x.className = "show"; 6 | setTimeout(function () { x.className = x.className.replace("show", ""); }, 3000); 7 | } 8 | 9 | // Check if the DOM is fully loaded 10 | // Function to open file picker 11 | function selectImage(cardId) { 12 | var fileInput = document.getElementById(`fileInput${cardId}`); 13 | if (fileInput) { 14 | fileInput.click(); 15 | } 16 | } 17 | 18 | // Function to display selected image on the image view 19 | function displaySelectedImage(inputId, cardId) { 20 | var input = document.getElementById(inputId); 21 | var card = document.getElementById(cardId); 22 | if (input.files && input.files[0]) { 23 | var reader = new FileReader(); 24 | reader.onload = function (e) { 25 | card.src = e.target.result; 26 | } 27 | reader.readAsDataURL(input.files[0]); 28 | } 29 | } 30 | 31 | function addRotatedAndScaledImageToCanvas(ctx, img, x, y, rotationDegrees, scaledWidth, scaledHeight) { 32 | ctx.save(); // Save the current canvas state 33 | ctx.translate(x + scaledWidth / 2, y + scaledHeight / 2); 34 | ctx.rotate((rotationDegrees * Math.PI) / 180); 35 | ctx.drawImage(img, -scaledWidth / 2, -scaledHeight / 2, scaledWidth, scaledHeight); 36 | ctx.restore(); // Restore the previous canvas state 37 | } 38 | 39 | function createCanvasAndDownload(overlayImageSources) { 40 | const canvas = document.createElement('canvas'); 41 | const ctx = canvas.getContext('2d'); 42 | const backgroundImageSrc = "Print Template/Print Template.jpeg"; 43 | const backgroundImg = new Image(); 44 | backgroundImg.crossOrigin = "Anonymous"; // Enable CORS for the image 45 | backgroundImg.onload = () => { 46 | canvas.width = backgroundImg.width; 47 | canvas.height = backgroundImg.height; 48 | ctx.drawImage(backgroundImg, 0, 0, canvas.width, canvas.height); 49 | let loadedCount = 0; 50 | const loadedImages = []; 51 | const onLoadComplete = () => { 52 | loadedCount++; 53 | if (loadedCount === overlayImageSources.length) { 54 | loadedImages.forEach((img, index) => { 55 | const overlayParams = getOverlayParams(index); // Replace this with your parameters logic 56 | addRotatedAndScaledImageToCanvas(ctx, img, ...overlayParams); 57 | }); 58 | downloadCanvasAsImage(canvas); 59 | } 60 | }; 61 | 62 | overlayImageSources.forEach((overlaySrc, index) => { 63 | const img = new Image(); 64 | img.crossOrigin = "Anonymous"; 65 | img.onload = () => { 66 | loadedImages[index] = img; 67 | onLoadComplete(); 68 | }; 69 | img.src = overlaySrc; 70 | }); 71 | }; 72 | backgroundImg.src = backgroundImageSrc; 73 | } 74 | 75 | 76 | function getOverlayParams(index) { 77 | // Example parameters based on the index 78 | if (index === 0) { 79 | return [280, 10, 270, 265, 395]; // Parameters for the first overlay image 80 | } else if (index === 1) { 81 | return [280, 325, 270, 265, 395]; // Parameters for the second overlay image 82 | } 83 | // Add more conditions or a different approach based on your specific requirements 84 | } 85 | 86 | function downloadCanvasAsImage(canvas) { 87 | const link = document.createElement('a'); 88 | link.download = 'canvas_output.jpg'; 89 | link.href = canvas.toDataURL('image/jpeg'); 90 | link.click(); 91 | } 92 | 93 | document.getElementById("genrator").addEventListener("click", function () { 94 | console.log("index page"); 95 | window.location.href = "index.html"; 96 | }); 97 | 98 | 99 | // Add event listeners to the image views 100 | document.getElementById('Card1').addEventListener('click', function () { 101 | selectImage('Card1'); 102 | }); 103 | 104 | document.getElementById('Card2').addEventListener('click', function () { 105 | selectImage('Card2'); 106 | }); 107 | 108 | 109 | document.getElementById('Print').addEventListener('click', function () { 110 | var card1Src = document.getElementById('Card1').src; 111 | var card2Src = document.getElementById('Card2').src; 112 | const blankImageSrc = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/w8AAwAB/aurfg0AAAAASUVORK5CYII="; // 1x1 white pixel 113 | 114 | // Check if at least one image is selected 115 | if ((card1Src && card1Src !== 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7') || 116 | (card2Src && card2Src !== 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7')) { 117 | 118 | // Use a blank image for any missing card images 119 | card1Src = (card1Src && card1Src !== 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7') ? card1Src : blankImageSrc; 120 | card2Src = (card2Src && card2Src !== 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7') ? card2Src : blankImageSrc; 121 | 122 | snackbar("Generating Print Template"); 123 | const overlayImageSources = [card1Src, card2Src]; 124 | createCanvasAndDownload(overlayImageSources); 125 | } else { 126 | // Neither image is selected 127 | snackbar("At least one image must be selected."); 128 | } 129 | }); 130 | 131 | 132 | 133 | // Function to reset selected images and hide snackbar 134 | // Function to reset selected images and hide snackbar 135 | function resetSelection() { 136 | var card1 = document.getElementById('Card1'); 137 | var card2 = document.getElementById('Card2'); 138 | var fileInput1 = document.getElementById('fileInputCard1'); 139 | var fileInput2 = document.getElementById('fileInputCard2'); 140 | // Reset image sources to clear selected images 141 | card1.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; 142 | card2.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; 143 | // Reset file inputs to allow selecting images again 144 | fileInput1.value = ''; 145 | fileInput2.value = ''; 146 | snackbar("Cleared"); 147 | } 148 | 149 | 150 | document.getElementById('resetButton').addEventListener('click', function () { 151 | resetSelection(); 152 | }); 153 | 154 | const downloadButton = document.getElementById('Print'); 155 | downloadButton.addEventListener('click', createCanvasAndDownload); 156 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | margin: 0; 4 | padding: 0; 5 | width: 100vw; 6 | height: 100vh; 7 | background-color: #FF7315; 8 | display: grid; 9 | overflow: hidden; 10 | grid-template-columns: 4% 56% 36% 4%; 11 | grid-template-rows: 5% 8% 74% 8% 5%; 12 | grid-column-gap: 0px; 13 | grid-row-gap: 0px; 14 | } 15 | 16 | ::-webkit-scrollbar { 17 | width: 0; 18 | background: transparent; 19 | } 20 | 21 | .div_1 { 22 | width: 100%; 23 | height: 100%; 24 | border-radius: 32px; 25 | background-color: #000000; 26 | grid-row-start: 3; 27 | grid-row-end: 3; 28 | grid-column-start: 2; 29 | grid-column-end: 4; 30 | box-shadow: rgba(0, 0, 0, 0.2) 0px 12px 28px 0px, rgba(0, 0, 0, 0.1) 0px 2px 4px 0px, rgba(255, 255, 255, 0.05) 0px 0px 0px 1px inset; 31 | } 32 | 33 | .div_2 { 34 | width: 85%; 35 | height: 100%; 36 | border-radius: 36px; 37 | background-color: #FFF; 38 | grid-row-start: 2; 39 | grid-row-end: 5; 40 | grid-column-start: 3; 41 | grid-column-end: 4; 42 | box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; 43 | display: grid; 44 | overflow: hidden; 45 | grid-template-columns: 100%; 46 | grid-template-rows: 10% 56% 34%; 47 | grid-column-gap: 0px; 48 | grid-row-gap: 0px; 49 | } 50 | 51 | .div_2_1 { 52 | width: 94%; 53 | height: 100%; 54 | grid-row-start: 1; 55 | display: flex; 56 | align-items: flex-end; 57 | justify-content: flex-end; 58 | flex-direction: row; 59 | } 60 | 61 | .div_2_2 { 62 | width: 100%; 63 | height: 100%; 64 | grid-row-start: 2; 65 | display: flex; 66 | align-items: center; 67 | justify-content: center; 68 | flex-direction: column; 69 | } 70 | 71 | .div_2_3 { 72 | width: 100%; 73 | height: 100%; 74 | grid-row-start: 3; 75 | display: flex; 76 | align-items: center; 77 | justify-content: center; 78 | flex-direction: column; 79 | } 80 | 81 | .preview_button { 82 | background-color: #000000; 83 | color: #FFF; 84 | font-size: larger; 85 | width: 86%; 86 | padding-top: 21px; 87 | padding-bottom: 21px; 88 | border-radius: 21px; 89 | border: none; 90 | margin-bottom: 2.5%; 91 | text-align: center; 92 | display: block; 93 | margin: 0 auto; 94 | box-sizing: border-box; 95 | margin-bottom: 2.1%; 96 | } 97 | 98 | .preview_image { 99 | width: 28%; 100 | height: auto; 101 | object-fit: contain; 102 | } 103 | 104 | .form_container { 105 | width: 70%; 106 | height: 100%; 107 | overflow: hidden; 108 | display: flex; 109 | align-items: flex-start; 110 | padding-left: 2.4%; 111 | justify-content: center; 112 | flex-direction: column; 113 | } 114 | 115 | .input_fields { 116 | padding: 2.6%; 117 | margin-bottom: 1.2%; 118 | color: #000000; 119 | border: none; 120 | background-color: #FFF; 121 | border-radius: 12px; 122 | font-size: 18px; 123 | outline: none; 124 | text-overflow: ellipsis; 125 | padding-right: 30px; 126 | } 127 | 128 | .width_62 { 129 | width: 62%; 130 | } 131 | 132 | .width_22 { 133 | width: 22%; 134 | } 135 | 136 | .width_46 { 137 | width: 46%; 138 | } 139 | 140 | .width_32 { 141 | width: 32%; 142 | } 143 | 144 | input::placeholder { 145 | color: #000; 146 | font-size: 18px; 147 | outline: none; 148 | position: relative; 149 | z-index: 1; 150 | } 151 | 152 | 153 | /* Style for the icon */ 154 | .input_fields::after { 155 | content: ''; 156 | background-image: url('/icons/blood.svg'); 157 | background-size: contain; 158 | background-repeat: no-repeat; 159 | position: absolute; 160 | top: 50%; 161 | right: 10px; 162 | transform: translateY(-50%); 163 | width: 20px; 164 | height: 20px; 165 | pointer-events: none; 166 | } 167 | 168 | select#blood_group { 169 | width: 32%; 170 | -webkit-appearance: none; 171 | -moz-appearance: none; 172 | appearance: none; 173 | background-image: none; 174 | background-color: #FFF; 175 | margin-bottom: 0; 176 | } 177 | 178 | .image_Picker_Container { 179 | width: 75%; 180 | padding: 2.6%; 181 | margin-bottom: 1.2%; 182 | border-radius: 12px; 183 | font-size: 18px; 184 | outline: none; 185 | display: flex; 186 | align-items: center; 187 | justify-content: flex-start; 188 | flex-direction: row; 189 | overflow: hidden; 190 | } 191 | 192 | #User_Pick_Button { 193 | background-color: #FFF; 194 | height: max-content; 195 | width: 60%; 196 | margin-bottom: 1.2%; 197 | border-radius: 12px; 198 | font-size: 18px; 199 | outline: none; 200 | border: none; 201 | text-align: left; 202 | } 203 | 204 | .pick_main_container { 205 | width: 80%; 206 | display: flex; 207 | align-items: center; 208 | justify-content: flex-start; 209 | flex-direction: row; 210 | overflow: hidden; 211 | } 212 | 213 | .Pick_Button { 214 | height: 100%; 215 | width: auto; 216 | color: #000000; 217 | border: none; 218 | background-color: #FFF; 219 | border-radius: 12px; 220 | font-size: 18px; 221 | outline: none; 222 | padding-left: 5.5%; 223 | padding-right: 5.5%; 224 | text-align: left; 225 | } 226 | 227 | .Pick_Image { 228 | margin-left: 12.5%; 229 | margin-right: 16.5%; 230 | /* object-fit: contain; 231 | max-width: 50.5%; 232 | max-height: 50.5%; 233 | */ 234 | width: 100%; 235 | border-radius: 2px; 236 | /* Set the width to 100% */ 237 | /* Maintain aspect ratio */ 238 | max-width: 100%; 239 | /* Ensure the image doesn't exceed the container width */ 240 | max-height: 50.5%; 241 | /* Ensure the image doesn't exceed the container height */ 242 | object-fit: contain; 243 | /* Maintain the aspect ratio without stretching the image */ 244 | } 245 | 246 | .pick_sub_Container { 247 | padding-right: 2.5%; 248 | padding-left: 10.5%; 249 | height: 100%; 250 | display: flex; 251 | flex-direction: row; 252 | align-items: center; 253 | justify-content: center; 254 | margin-left: 1.5%; 255 | background-color: #FFF; 256 | border-radius: 12px; 257 | overflow: hidden; 258 | } 259 | 260 | 261 | 262 | /* SnackBar Toast */ 263 | 264 | #snackbar { 265 | visibility: hidden; 266 | min-width: 250px; 267 | max-width: 450px; 268 | margin-left: -125px; 269 | background-color: #000; 270 | color: #FFF; 271 | font-size: 18px; 272 | outline: none; 273 | text-overflow: ellipsis; 274 | text-align: center; 275 | border-radius: 12px; 276 | padding: 16px; 277 | position: fixed; 278 | z-index: 1; 279 | left: 50%; 280 | bottom: 30px; 281 | font-family: 'Roboto', sans-serif; 282 | } 283 | 284 | 285 | #snackbar.show { 286 | visibility: visible; 287 | -webkit-animation: fadein 0.9s, fadeout 0.9s 2.5s; 288 | animation: fadein 0.9s, fadeout 0.5s 2.5s; 289 | } 290 | 291 | /* Animations to fade the snackbar in and out */ 292 | @-webkit-keyframes fadein { 293 | from { 294 | bottom: 0; 295 | opacity: 0; 296 | } 297 | 298 | to { 299 | bottom: 30px; 300 | opacity: 1; 301 | } 302 | } 303 | 304 | @keyframes fadein { 305 | from { 306 | bottom: 0; 307 | opacity: 0; 308 | } 309 | 310 | to { 311 | bottom: 30px; 312 | opacity: 1; 313 | } 314 | } 315 | 316 | @-webkit-keyframes fadeout { 317 | from { 318 | bottom: 30px; 319 | opacity: 1; 320 | } 321 | 322 | to { 323 | bottom: 0; 324 | opacity: 0; 325 | } 326 | } 327 | 328 | @keyframes fadeout { 329 | from { 330 | bottom: 30px; 331 | opacity: 1; 332 | } 333 | 334 | to { 335 | bottom: 0; 336 | opacity: 0; 337 | } 338 | } 339 | 340 | /* SnackBar Toast */ 341 | 342 | 343 | #snackbar.show { 344 | visibility: visible; 345 | -webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s; 346 | animation: fadein 0.5s, fadeout 0.5s 2.5s; 347 | } 348 | 349 | /* Animations to fade the snackbar in and out */ 350 | @-webkit-keyframes fadein { 351 | from { 352 | bottom: 0; 353 | opacity: 0; 354 | } 355 | 356 | to { 357 | bottom: 30px; 358 | opacity: 1; 359 | } 360 | } 361 | 362 | @keyframes fadein { 363 | from { 364 | bottom: 0; 365 | opacity: 0; 366 | } 367 | 368 | to { 369 | bottom: 30px; 370 | opacity: 1; 371 | } 372 | } 373 | 374 | @-webkit-keyframes fadeout { 375 | from { 376 | bottom: 30px; 377 | opacity: 1; 378 | } 379 | 380 | to { 381 | bottom: 0; 382 | opacity: 0; 383 | } 384 | } 385 | 386 | @keyframes fadeout { 387 | from { 388 | bottom: 30px; 389 | opacity: 1; 390 | } 391 | 392 | to { 393 | bottom: 0; 394 | opacity: 0; 395 | } 396 | } 397 | 398 | /* SnackBar Toast */ -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | let frontLabelGenerated = false; // Flag to track front label generation 2 | let backLabelGenerated = false; // Flag to track back label generation 3 | 4 | // allows to toast messages 5 | function snackbar(message) { 6 | var x = document.getElementById("snackbar"); 7 | x.textContent = message; 8 | x.className = "show"; 9 | setTimeout(function () { x.className = x.className.replace("show", ""); }, 3000); 10 | } 11 | 12 | function saveCanvasAsImage(canvas, fileName) { 13 | return Promise.resolve().then(() => { 14 | const dataURL = canvas.toDataURL('image/jpeg'); 15 | const link = document.createElement('a'); 16 | link.href = dataURL; 17 | link.download = fileName; 18 | 19 | let downloadCompleted = false; 20 | link.addEventListener('load', () => { 21 | if (!downloadCompleted && document.body.contains(link)) { 22 | downloadCompleted = true; 23 | document.body.removeChild(link); 24 | } 25 | }); 26 | 27 | link.click(); 28 | 29 | setTimeout(() => { 30 | if (!downloadCompleted && document.body.contains(link)) { 31 | downloadCompleted = true; 32 | document.body.removeChild(link); 33 | } 34 | }, 5000); 35 | }); 36 | } 37 | 38 | 39 | 40 | 41 | // Pick image 42 | function selectImage() { 43 | document.getElementById('fileInput').click(); 44 | } 45 | 46 | // Display image 47 | function displaySelectedImage(event) { 48 | const selectedFile = event.target.files[0]; 49 | const imageElement = document.querySelector('.Pick_Image'); 50 | if (selectedFile && selectedFile.type.startsWith('image/')) { 51 | const reader = new FileReader(); 52 | reader.onload = function (e) { 53 | imageElement.src = e.target.result; 54 | imageElement.style.width = '45px'; // Set a fixed width (change as needed) 55 | imageElement.style.height = '45px'; // Set a fixed height (change as needed) 56 | imageElement.style.objectFit = 'cover'; // Maintain aspect ratio and cover the container 57 | }; 58 | reader.readAsDataURL(selectedFile); 59 | } else { 60 | snackbar('Please select an image file.'); 61 | } 62 | } 63 | 64 | function addTextAndOverlayToFrontImage(name, empCode, overlaySrc) { 65 | console.log("Generating front Image"); 66 | const overlayY = 240; 67 | const overlayWidth = 280; 68 | const overlayHeight = 320; 69 | const frontImg = new Image(); 70 | frontImg.crossOrigin = "Anonymous"; 71 | 72 | return new Promise((resolve, reject) => { 73 | frontImg.onload = () => { 74 | const canvas = document.createElement('canvas'); 75 | const ctx = canvas.getContext('2d'); 76 | canvas.width = frontImg.width; 77 | canvas.height = frontImg.height; 78 | 79 | ctx.drawImage(frontImg, 0, 0); 80 | 81 | const overlayImg = new Image(); 82 | overlayImg.crossOrigin = "Anonymous"; 83 | 84 | overlayImg.onload = () => { 85 | const aspectRatio = overlayImg.width / overlayImg.height; 86 | let overlayWidthActual = overlayWidth; 87 | let overlayHeightActual = overlayWidthActual / aspectRatio; 88 | 89 | if (overlayHeightActual > overlayHeight) { 90 | overlayHeightActual = overlayHeight; 91 | overlayWidthActual = overlayHeightActual * aspectRatio; 92 | } 93 | 94 | const overlayX = (canvas.width - overlayWidthActual) / 2; 95 | const overlayYActual = overlayY + (overlayHeight - overlayHeightActual) / 2; 96 | 97 | ctx.drawImage(overlayImg, overlayX, overlayYActual, overlayWidthActual, overlayHeightActual); 98 | 99 | ctx.font = '35.2px Arial'; 100 | ctx.fillStyle = 'black'; 101 | ctx.fontWeight = 'normal'; 102 | 103 | const nameTextWidth = ctx.measureText(`Name: ${name}`).width; 104 | const empCodeTextWidth = ctx.measureText(`Employee Code: ${empCode}`).width; 105 | const centerX = (canvas.width - Math.max(nameTextWidth, empCodeTextWidth)) / 2; 106 | 107 | ctx.fillText(`Name: ${name}`, centerX, 600); 108 | ctx.fillText(`Employee Code: ${empCode}`, centerX, 640); 109 | 110 | const FrontFileName = `${empCode}_Front_ID.jpg`; 111 | 112 | saveCanvasAsImage(canvas, FrontFileName) 113 | .then(() => { 114 | frontLabelGenerated = true; 115 | console.log("Front label generated successfully"); 116 | resolve(); 117 | }) 118 | .catch(error => { 119 | console.error("Error saving front canvas:", error); 120 | reject(error); 121 | }); 122 | }; 123 | 124 | overlayImg.src = overlaySrc; 125 | }; 126 | 127 | frontImg.src = 'Templates/Front.jpeg'; 128 | }); 129 | } 130 | 131 | function addTextToBackImage(emergencyContact, bloodGroup, empCode) { 132 | console.log("Generating back Image"); 133 | const backImg = new Image(); 134 | backImg.crossOrigin = "Anonymous"; 135 | 136 | return new Promise((resolve, reject) => { 137 | backImg.onload = () => { 138 | const canvas = document.createElement('canvas'); 139 | const ctx = canvas.getContext('2d'); 140 | canvas.width = backImg.width; 141 | canvas.height = backImg.height; 142 | 143 | ctx.drawImage(backImg, 0, 0); 144 | 145 | ctx.font = '35.2px Arial'; 146 | ctx.fillStyle = 'black'; 147 | ctx.fontWeight = 'normal'; 148 | 149 | ctx.fillText(bloodGroup, 360, 90); 150 | ctx.fillText(emergencyContact, 360, 135); 151 | 152 | const backFileName = `${empCode}_Back_ID.jpg`; 153 | saveCanvasAsImage(canvas, backFileName) 154 | .then(() => { 155 | backLabelGenerated = true; 156 | console.log("Back label generated successfully"); 157 | resolve(); 158 | }) 159 | .catch(error => { 160 | console.error("Error saving back canvas:", error); 161 | reject(error); 162 | }); 163 | }; 164 | 165 | backImg.src = 'Templates/back.jpeg'; 166 | }); 167 | } 168 | 169 | 170 | 171 | 172 | function validateFields() { 173 | const nameInput = document.getElementById('name').value.trim(); 174 | const empCodeInput = document.getElementById('emp_code').value.trim(); 175 | const emergencyContactInput = document.getElementById('emergency_contact').value.trim(); 176 | const bloodGroupInput = document.getElementById('blood_group').value; 177 | const selectedImage = document.getElementById('fileInput').files[0]; // Get selected image file 178 | 179 | // Define error messages 180 | const errorMessages = { 181 | name: 'Please Enter Name & Spaces', 182 | empCode: 'Please Enter EMP CODE', 183 | emergencyContact: 'Emergency Contact Should Be Exactly 10 Digits.', 184 | bloodGroup: 'Please Select Blood Group.', 185 | image: 'Please Select An Image', 186 | allFieldsEmpty: 'All fields are Empty. Please Fill In The Details.' 187 | }; 188 | 189 | // Check for errors 190 | const errors = []; 191 | if (nameInput === '') errors.push(errorMessages.name); 192 | if (empCodeInput.length === '') errors.push(errorMessages.empCode); 193 | if (emergencyContactInput.length !== 10) errors.push(errorMessages.emergencyContact); 194 | if (bloodGroupInput === '') errors.push(errorMessages.bloodGroup); 195 | if (!selectedImage) errors.push(errorMessages.image); // Validate if an image is selected 196 | 197 | // Check if all fields are empty 198 | const allFieldsEmpty = [nameInput, empCodeInput, emergencyContactInput, bloodGroupInput].every(field => field === ''); 199 | if (allFieldsEmpty) { 200 | snackbar(errorMessages.allFieldsEmpty); 201 | return false; 202 | } 203 | 204 | // Display errors using snackbar 205 | if (errors.length > 0) { 206 | snackbar(errors.join(' ')); 207 | return false; 208 | } 209 | return true; 210 | } 211 | 212 | // Function to clear all form fields and display "Cleared" message 213 | function clearFields() { 214 | document.getElementById('name').value = ''; // Clear name field 215 | document.getElementById('emp_code').value = ''; // Clear EMP code field 216 | document.getElementById('emergency_contact').value = ''; // Clear emergency contact field 217 | document.getElementById('blood_group').value = ''; // Reset blood group selection to default 218 | document.querySelector('.Pick_Image').src = '/icons/square-fill.svg'; // Reset image source to default 219 | // Display "Cleared" snackbar message 220 | frontLabelGenerated = false; 221 | backLabelGenerated = false; 222 | window.location.reload(); 223 | } 224 | 225 | // Get ImageDimensions 226 | function getImageDimensions(selectedImage) { 227 | return new Promise((resolve, reject) => { 228 | const reader = new FileReader(); 229 | reader.onload = function (e) { 230 | const imgElement = document.createElement('img'); 231 | imgElement.onload = function () { 232 | const dimensions = { width: imgElement.width, height: imgElement.height }; 233 | resolve(dimensions); 234 | }; 235 | imgElement.src = e.target.result; 236 | }; 237 | reader.readAsDataURL(selectedImage); 238 | }); 239 | } 240 | 241 | document.getElementById("Print").addEventListener("click", function () { 242 | window.location.href = "print.html"; 243 | }); 244 | 245 | // Get references to the input fields 246 | const empCodeInput = document.getElementById('emp_code'); 247 | const emergencyContactInput = document.getElementById('emergency_contact'); 248 | 249 | // Allow only numbers for EMP Code input 250 | empCodeInput.addEventListener('input', function () { 251 | this.value = this.value.replace(/\D/g, '').slice(0, 6); // Allow only numbers and limit to 6 characters 252 | }); 253 | 254 | // Allow only numbers for Emergency Contact input and limit to 10 characters 255 | emergencyContactInput.addEventListener('input', function () { 256 | this.value = this.value.replace(/\D/g, '').slice(0, 10); // Allow only numbers and limit to 10 characters 257 | }); 258 | 259 | // Allow only alphabetic characters in the input field and limit to 120 charcters 260 | var inputField = document.getElementById("name"); 261 | // Regex pattern to match only alphabetic characters and space 262 | var pattern = /^[A-Za-z\s]+$/; 263 | inputField.addEventListener("input", function (event) { 264 | var inputValue = event.data || inputField.value; 265 | if (!pattern.test(inputValue)) { 266 | inputField.value = inputField.value.replace(/[^A-Za-z\s]/g, ''); 267 | } 268 | }); 269 | 270 | 271 | 272 | document.getElementById('Back').addEventListener('click', async function () { 273 | // Validate fields before generating the preview 274 | const isValid = validateFields(); 275 | if (isValid) { 276 | // Assuming you have references to the form fields and the selected image 277 | const name = document.getElementById('name').value.trim(); 278 | const empCode = document.getElementById('emp_code').value.trim(); 279 | const emergencyContact = document.getElementById('emergency_contact').value.trim(); 280 | const bloodGroup = document.getElementById('blood_group').value; 281 | const selectedImage = document.getElementById('fileInput').files[0]; 282 | const imagePath = URL.createObjectURL(selectedImage); // Get the image path 283 | try { 284 | addTextToBackImage(emergencyContact, bloodGroup, empCode) 285 | } catch (error) { 286 | console.error("Error obtaining image dimensions:", error); 287 | snackbar("Error obtaining image dimensions"); 288 | // Handle errors while obtaining image dimensions 289 | } 290 | } 291 | }); 292 | 293 | 294 | document.getElementById('Front').addEventListener('click', async function () { 295 | // Validate fields before generating the preview 296 | const isValid = validateFields(); 297 | if (isValid) { 298 | // Assuming you have references to the form fields and the selected image 299 | const name = document.getElementById('name').value.trim(); 300 | const empCode = document.getElementById('emp_code').value.trim(); 301 | const emergencyContact = document.getElementById('emergency_contact').value.trim(); 302 | const bloodGroup = document.getElementById('blood_group').value; 303 | const selectedImage = document.getElementById('fileInput').files[0]; 304 | const imagePath = URL.createObjectURL(selectedImage); // Get the image path 305 | try { 306 | addTextAndOverlayToFrontImage(name, empCode, imagePath); 307 | } catch (error) { 308 | console.error("Error obtaining image dimensions:", error); 309 | snackbar("Error obtaining image dimensions"); 310 | // Handle errors while obtaining image dimensions 311 | } 312 | } 313 | }); 314 | 315 | 316 | // Event listener for the reset button click 317 | document.getElementById('resetButton').addEventListener('click', function () { 318 | clearFields(); // Call the function to clear fields and display message 319 | }); 320 | 321 | 322 | 323 | --------------------------------------------------------------------------------