├── 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 | Print
29 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ID-Card-Generator
2 | ## 🔍 Overview:
3 | 
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 | 
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 |
41 |
42 |
43 |
45 |
46 |
47 |
48 |
49 |
50 | FRONT
51 | BACK
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 |
--------------------------------------------------------------------------------