diff --git a/README.md b/README.md new file mode 100644 index 0000000..51b864e --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# Barcode generator + +## About +This program generates a [Code 39](https://en.wikipedia.org/wiki/Code_39) barcode for a given string. In other words, it draws the appropriate sequences of bars and spaces into a bmp file. + +Details of the task can be found in `task.pdf` file. + +## How to run +This project is precompiled for Linux. +Open terminal in the folder with files. + +Type `./program width_of_narrow_bar text_to_be_encoded` + +Where: + +`width_of_narrow_bar` - 1, 2 or 3 + +`text_to_be_encoded` - sequence of up to 9 characters (uppercase letters, numbers and [more](https://en.wikipedia.org/wiki/Code_39#/media/File:Free_3_of_9_(Code_39_barcode).svg)) + +A barcode will be generated in the `output.bmp` file. + +## Sample run +``` +./program 2 CODE-X86 +``` + +In `output.bmp` file: + +![example](documentation/example.bmp) + +The correctness of the barcode generated can be verified for example with an Android app: + +![example](documentation/screenshot-barcode-scanner.png) + +## Implementation +The source for the program is located in `main.c` and `functions.asm` files. It is written in C and 32 bit x86 assembly language. The simplified logic of the core functions in pseudocode is presented in form of diagrams below. +The diagrams were created with the MIPS implementation in mind, but are valid in the x86 case as well. + + +![Logic chart](documentation/logic.drawio.svg) \ No newline at end of file diff --git a/documentation/example.bmp b/documentation/example.bmp new file mode 100644 index 0000000..484a066 Binary files /dev/null and b/documentation/example.bmp differ diff --git a/documentation/logic.drawio.svg b/documentation/logic.drawio.svg new file mode 100644 index 0000000..c3327f2 --- /dev/null +++ b/documentation/logic.drawio.svg @@ -0,0 +1,422 @@ + + + + + + + + +
+
+
+ main +
+
+
+
+ + main + +
+
+ + + + +
+
+
+ $s1 - width of  narrowest bar +
+
+
+
+ + $s1 - width of  narrowest bar + +
+
+ + + + +
+
+
+ text - text to encode +
+
+
+
+ + text - text to encode + +
+
+ + + + +
+
+
+ for each character invoke the put_char function +
+
+
+
+ + for each character invoke the put_char func... + +
+
+ + + + +
+
+
+
+
+ $a0 - starting x cordinate +
+
+ $a1 - width of thin bar +
+
+ $a2 - character to put +
+
+
+ For example, when we want to put A: +
+
+ in register $s4 we put sequence: + + `100001001` + +
+
+
+ $s3 - address of sequence of bits +
+
+ $s4 = + + `100001001` + +
+
+ $s5 = + + `100000000` + +
+
+
+ $s6 = $s4 AND $s5 +
+
+ + `100001001` + + AND + + `100000000` + + = + + `100000000` + +
+
+
+ if ($s6 == $s5) $a1 = put_thick_bar($a0, $a1) +
+
+ else $a1 = put_thin_bar($a0, $a1) +
+
+
+ $s5 = + + `010000000` + + (shifted right) +
+
+ if ($s5 = 0) return $a0 + $a1 +
+
+
+ $s6 = $s4 AND $s5 +
+
+ + `100001001` + + AND + + `010000000` + + = + + `000000000` + +
+
+
+ if ($s6 == $s5) $a0 += 2 * $a1 //put thick space +
+
+ else ($s6 == 0) $a0 += $a1  // put thin space +
+
+
+ $s5 = + + `001000000` + + (shifted right) +
+
+
+ go to +
+
+
+
+
+
+ + $a0 - starting x cordinate... + +
+
+ + + + +
+
+
+ put_char ($a0, $a1, $a2) +
+
+
+
+ + put_char ($a0, $a1, $a2... + +
+
+ + + + +
+
+
+ draws bars and spaces for a given character +
+
+
+
+ + draws bars and spaces for a given character + +
+
+ + + + +
+
+
+ Algorithm with exemplary values +
+
+
+
+ + Algorithm with exemplary values + +
+
+ + + + + + +
+
+
+
+
+ + $a0 - starting x + +
+
+ + $a1 = + + + `STARTING_Y` + +
+
+ + $s1 - width of thin bar +
+
+
+
+
+ + put_pixel($a0, $a1) + +
+
+ + $a1++ + +
+
+ + if ($a1 <= 40) go to + +
+
+ + $a0++ + +
+
+ + $s1-- + +
+
+ + if ($s1 == 0) return $a0 + +
+
+ + $a1 = + + + `STARTING_Y` + +
+
+ + go to + +
+
+
+
+
+
+ + $a0 - starting x... + +
+
+ + + + +
+
+
+ put_thin_bar($a0, $s1) +
+
+
+
+ + put_thin_bar($a0, $s1) + +
+
+ + + + + + + + +
+
+
+
+
+ + $a0 - starting x + +
+
+ + $s1 - width of thin bar + +
+
+
+ + $a0 = put_thin_bar($a0, $s1) + +
+
+ + $a0 = put_thin_bar($a0, $s1) + +
+
+ + return $a0 + +
+
+
+
+
+
+ + $a0 - starting x... + +
+
+ + + + +
+
+
+ put_thick_bar($a0, $s1) +
+
+
+
+ + put_thick_bar($a0, $s1) + +
+
+
+ + + + + Viewer does not support full SVG 1.1 + + + +
\ No newline at end of file diff --git a/documentation/screenshot-barcode-scanner.png b/documentation/screenshot-barcode-scanner.png new file mode 100644 index 0000000..f3402dd Binary files /dev/null and b/documentation/screenshot-barcode-scanner.png differ diff --git a/documentation/task.pdf b/documentation/task.pdf new file mode 100644 index 0000000..621b629 Binary files /dev/null and b/documentation/task.pdf differ diff --git a/functions.asm b/functions.asm index f290fe0..d972cd0 100644 --- a/functions.asm +++ b/functions.asm @@ -2,6 +2,7 @@ global _put_pixel, put_pixel global _put_thin_bar, put_thin_bar global _put_thick_bar, put_thick_bar global _put_char, put_char +global _encode39, encode39 section .data ;used by put_char @@ -39,6 +40,9 @@ section .text pop edx %endmacro +; used by encode39 +%define STARTING_X 10 ; starting x coordinate of the bar + ; int put_pixel(char* pixels, int x, int y); ; sets the color of specified pixel to black @@ -153,7 +157,6 @@ put_thick_bar: ; return value: x coordinate of the next character _put_char: put_char: - push ebp mov ebp, esp push ebx @@ -255,4 +258,69 @@ return: pop esi pop ebx pop ebp - ret \ No newline at end of file + ret + + +; int encode39(char* pixels, int width, char* text); +; encodes text using Code 39 barcode +; arguments: +; DWORD[ebp+8]: char* pixels - address of pixel array +; DWORD[ebp+12]: int width - width in pixels of narrowest bar +; DWORD[ebp+16]: char* text - character to put +; return value: 0 (OK) or -1 (error, character unsupported) +_encode39: +encode39: + push ebp + mov ebp, esp + push ebx + + mov edx, STARTING_X + + ; put_char(pixels, x, width, character) + push '*' ; character + push DWORD[ebp+12] ; width + push edx ; x + push DWORD[ebp+8] ; pixels + call put_char + add esp, 16 + mov edx, eax + + mov ebx, DWORD[ebp+16] + +char_loop: + mov cl, BYTE[ebx] + cmp cl, 0 + je ending_char + + ; put_char(pixels, x, width, character) + push ecx ; character + push DWORD[ebp+12] ; width + push edx ; x + push DWORD[ebp+8] ; pixels + call put_char + add esp, 12 + pop ecx + mov edx, eax + + cmp eax, -1 + je exit + + inc ebx + jmp char_loop + +ending_char: + ; put_char(pixels, x, width, character) + push '*' ; character + push DWORD[ebp+12] ; width + push edx ; x + push DWORD[ebp+8] ; pixels + call put_char + add esp, 16 + +set_return_value: + xor eax, eax + +exit: + pop ebx + pop ebp + ret \ No newline at end of file diff --git a/main.c b/main.c index 9aee9f9..086f738 100644 --- a/main.c +++ b/main.c @@ -1,10 +1,13 @@ #include #include +#include extern int put_pixel(char* pixels, int x, int y); extern int put_thin_bar(char* pixels, int x, int width); extern int put_thick_bar(char* pixels, int x, int width); extern int put_char(char* pixels, int x, int width, char character); +extern int encode39(char* pixels, int width, char* text); + char* read_from_file(); char* write_to_file(char* buff); @@ -13,42 +16,40 @@ unsigned int len; int main(int argc, char** argv) { + if(argc != 3) + { + printf("Error: Incorrect number of arguments.\n"); + printf("Correct syntax: ./program width_of_narrow_bar(1, 2 or 3) text_to_be_encoded(max 9 characters).\n "); + return 2; + } + + int width = atoi(argv[1]); + if (width < 1 || width > 3) { + printf("Error: Width must be 1, 2 or 3.\n"); + return 3; + } + + char* text = argv[2]; + if (strlen(text) > 9) { + printf("Error: Length of text to encode must be between 1 and 9 characters.\n"); + return 4; + } + + printf("width: %d, text: %s\n", width, text); + char* buff = read_from_file(); char* pixels = buff + 10; pixels = buff + pixels[0]; // pixels pointer now points to the pixels section of .bmp -// if(ret == -1) { -// printf("Error 1: Text contains characters which cannot be encoded"); -// return 1; -// } -// printf("return value: %d ", ret); - - int ret = 10; - ret = put_char(pixels, ret, 2, '*'); - ret = put_char(pixels, ret, 2, 'B'); - ret = put_char(pixels, ret, 2, 'A'); - ret = put_char(pixels, ret, 2, 'C'); - ret = put_char(pixels, ret, 2, 'A'); - put_char(pixels, ret, 2, '*'); - - -// put_pixel(pixels, 20, 20); -// int ret = put_thick_bar(pixels, 20, 2); -// put_thin_bar(pixels, ret, 2); + int ret = encode39(pixels, width, text); + if(ret == -1) { + printf("Error: Text contains characters which cannot be encoded"); + return 1; + } write_to_file(buff); - -// if(argc != 2) -// { -// printf("Input argument was not specified correctly! \n "); -// return -1; -// } - -// if (result == 0) printf("No shape found.\n"); -// else printf("Shape %i found.\n\n\n", result); - return 0; } @@ -58,10 +59,10 @@ char* read_from_file() { imgFile = fopen("white.bmp", "rb"); if (imgFile == NULL) { - printf("Failed to open file\n"); + printf("Failed to open white.bmp\n"); exit(-1); } - else printf("File opened successfully\n"); + else printf("white.bmp opened successfully\n"); fseek(imgFile, 0, SEEK_END); /* move file pointer to end of file */ len = ftell(imgFile); /* get offset from beginning of the file */ @@ -95,11 +96,6 @@ char* write_to_file(char* buff) { } else printf("File to write to opened successfully\n"); -// int width =*(int * )( & buff[18] ); // width = 600 -// int width = 600; -// int height =*(int * )( & buff[22] ); // height = 50 -// int height = 50; - int size = ((600 * 3 + 3) & ~3) * 50 + 54; fwrite(buff, len, 1, imgFile); fclose(imgFile); diff --git a/output.bmp b/output.bmp index db99d3e..484a066 100644 Binary files a/output.bmp and b/output.bmp differ diff --git a/program b/program index 44d7059..ffe02b7 100755 Binary files a/program and b/program differ