Jump to content
Mc128k

Custom function for generating Code-128 Type B

Recommended Posts

Mc128k    2

Hey all, this time I created two functions that generate a BMP file with a code-128 barcode. It's more complicated, despite being shorter than the previous (EAN13), and it also has to generate a variable-length BMP file. There are some hacks, like the generation of a little-endian number for the BMP header, but overall it seems stable.

I tried uploading it to Brian Dunning's website but it didn't give me the link. I'll post it here, and if there are problems, please PM me.

 

/**
 * =====================================
 * BarcodeCode128B_BMP_380px ( string )
 *
 * PURPOSE:
 *		Generate a binary BMP file containing a Code-128 Type B barcode
 *
 * NOTE:
 *		Embed the contents in a container to see it. Valid for UP TO 20 CHARACTERS
 *
 * RETURNS:
 *		Binary BMP.
 *
 * PARAMETERS:
 *		string: The string to encode in Code-128
 *
 * DEPENDENCIES:
 * 		BarcodeCode128B_Raw
 *
 * RELEASE:
 * 		2017-06-15
 *
 * VERSION:	1.0
 * 
 * AUTHOR: 	© 2017 Mc128k - http://www.mc128k.com
 * =====================================
 */

Let ( [
	~binary=BarcodeCode128B_Raw(string);
	~size=Length(~binary) * 4 // size increased by (4 pixels wide) * (11 chars) * n = 44
	] ; 

	Let ( [
			_foreground_color = Substitute ( "1111" ; "1" ; "AAAA" ) ;  // set to black
			_background_color = Substitute ( "1111" ; "1" ; "////" ) ; // white
			_base =Base64Encode ( HexDecode ( 
				// BMP header
				"42 4D " &

				// File size (fake)
				"10 27 00 00 00 00 00 00 36 00 00 00 28 00 00 00 " &

				// Image size (bad solution but effective, creating little-endian values with functions is hard)
				// MAXIMUM 20 CHARACTERS
				Case ( 
					~size=220 ; "DC 00 00 00"; 
					~size=264 ; "08 01 00 00"; 
					~size=308 ; "34 01 00 00"; 
					~size=352 ; "60 01 00 00"; 
					~size=396 ; "8C 01 00 00"; 
					~size=440 ; "B8 01 00 00"; 
					~size=484 ; "E4 01 00 00"; 
					~size=528 ; "10 02 00 00"; 
					~size=572 ; "3C 02 00 00"; 
					~size=616 ; "68 02 00 00"; 
					~size=660 ; "94 02 00 00"; 
								
					~size=704 ; "C0 02 00 00"; 
					~size=748 ; "EC 02 00 00"; 
					~size=792 ; "18 03 00 00"; 
					~size=836 ; "44 03 00 00"; 
					~size=880 ; "70 03 00 00"; 
					~size=924 ; "9C 03 00 00"; 
					~size=968 ; "C8 03 00 00"; 
					~size=1012 ; "F4 03 00 00"; 
					~size=1056 ; "20 04 00 00"; 
					~size=1100 ; "4C 04 00 00"; 
					~size=1144 ; "78 04 00 00"; 
				) & " " &

				// Other BMP stuff
				"01 00 00 00 01 00 18 00 00 00 00 00 76 04 00 00 12 0B 00 00 12 0B 00 00 00 00 00 00 00 00 00 00"
				
				; "barcode.bmp" )) // Base64, Hex
				;
			_map = Substitute ( ~binary ; "0" ; _background_color );
			_map = Substitute ( _map; "1" ; _foreground_color );
			_map = _map & "////"
		] ; 
			If ( ~size > 1144  ; "error" ; Base64Decode ( _base & _map ; "barcode.bmp" ) )
		)
)
/**
 * =====================================
 * BarcodeCode128B_Raw ( input )
 *
 * PURPOSE:
 *		Generates the binary number for the Code-128 Type B barcode
 *
 * RETURNS:
 *		A binary number representing the barcode
 *
 * PARAMETERS:
 *		input: the string to encode
 *
 * DEPENDENCIES:
 * 		ForEach, Repeat
 *
 * RELEASE:
 * 		2017-06-15
 *
 * REFERENCES:
 *		https://en.wikipedia.org/wiki/Code_128
 *
 * VERSION:	1.0
 * 
 * AUTHOR: 	© 2017 Mc128k - http://www.mc128k.com
 * =====================================
 */

Let ( [
	~code=Filter ( input ; "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~" );

/**
 * Behold, all 108 symbols of Code-128. Use GetValue() to pick the desired one.
 *
 * Bar weights are specified by the number of black or white consecutive bars
 * For example a weight of "212222" means that the code will be "11011001100"
 * where the first "2" means that there will be two "1" bits, and the next
 * "1" will tell that there will be one "0" bit
 * 
 * Type B, keep +1 as it allows C-style array numbers, 32 shifts the ASCII value to the array position
 */

$code128_sym="212222¶222122¶222221¶121223¶121322¶131222¶122213¶122312¶132212¶221213¶221312¶231212¶112232¶122132¶122231¶113222¶123122¶123221¶223211¶221132¶221231¶213212¶223112¶312131¶311222¶321122¶321221¶312212¶322112¶322211¶212123¶212321¶232121¶111323¶131123¶131321¶112313¶132113¶132311¶211313¶231113¶231311¶112133¶112331¶132131¶113123¶113321¶133121¶313121¶211331¶231131¶213113¶213311¶213131¶311123¶311321¶331121¶312113¶312311¶332111¶314111¶221411¶431111¶111224¶111422¶121124¶121421¶141122¶141221¶112214¶112412¶122114¶122411¶142112¶142211¶241211¶221114¶413111¶241112¶134111¶111242¶121142¶121241¶114212¶124112¶124211¶411212¶421112¶421211¶212141¶214121¶412121¶111143¶111341¶131141¶114113¶114311¶411113¶411311¶113141¶114131¶311141¶411131¶211412¶211214¶211232¶2331112¶"

];

/**
 * Zones:
 * 
 * Quiet zone
 * Start symbol
 * Encoded data
 * Check symbol
 * Stop symbol & final bar
 * Quiet zone
 */ 

// Quiet zone (10x)
"0000000000" &

// Start symbol
Substitute ( ForEach ( StringToList ( GetValue ( $code128_sym ; 104 +1) ) ; "If ( Mod ( $~i ; 2 ) = 1 ; Repeat ( \"1\" ; ~n ) ; Repeat ( \"0\" ; ~n ) ) " ) ; "¶" ; Null ) &

// Encoded data - Substitute string with symbols, symbols with binary. Evaluation hell incoming
Evaluate (Substitute ( 
	ForEach ( 
		// substitute rows with calculations that return binary code. Should look like this:
		// Substitute ( ForEach ( StringToList ( "311321" ) ; "If ( Mod ( $~i ; 2 ) = 1 ; Repeat ( \"1\" ; ~n ) ; Repeat ( \"0\" ; ~n ) ) " ) ; "¶" ; Null )
		ForEach ( StringToList ( ~code ) ; "GetValue ( $code128_sym ; code ( ~n ) +1 -32 )" ); // "abc" -> 121124¶121421¶141122
		"
			\"Substitute ( ForEach ( StringToList ( \\\"\" 
			& ~n & 
			\"\\\" ) ; \\\"If ( Mod ( $~i ; 2 ) = 1 ; Repeat ( \\\\\\\"1\\\\\\\" ; ~n ) ; Repeat ( \\\\\\\"0\\\\\\\" ; ~n ) ) \\\" ) ; \\\"\\\¶\\\" ; Null )\"
		"
	)
; "¶" ; " & ")) &

// Checksum
Let ( 
	~checksum = Evaluate( "Mod(104+" & Substitute ( ForEach ( StringToList ( ~code ) ; "(Code ( ~n ) - 32) * $~i" ) ; "¶" ; "+") & "; 103)");
	Substitute ( ForEach ( StringToList ( GetValue ( $code128_sym ; ~checksum +1) ) ; "If ( Mod ( $~i ; 2 ) = 1 ; Repeat ( \"1\" ; ~n ) ; Repeat ( \"0\" ; ~n ) ) " ) ; "¶" ; Null )
) &

// Stop symbol
Substitute ( ForEach ( StringToList ( GetValue ( $code128_sym ; 106 +1) ) ; "If ( Mod ( $~i ; 2 ) = 1 ; Repeat ( \"1\" ; ~n ) ; Repeat ( \"0\" ; ~n ) ) " ) ; "¶" ; Null ) &

// Quiet zone (10x)
"0000000000"

 ) // End Let
/**
 * =====================================
 * Repeat ( text ; times )
 *
 * PURPOSE:
 *		Just repeat a string many times
 *
 * RETURNS:
 *		A string
 *
 * PARAMETERS:
 *		text: The text to be repeated
 *		times: How many times to repeat it
 *
 * RELEASE:
 * 		2017-06-11
 *
 * VERSION:	1.0
 * 
 * AUTHOR: 	© 2017 Mc128k
 * =====================================
 */

If (times > 0 ;
text & If ( times > 1 ;  Repeat ( text ; times - 1) ; "") ; "" )
/**
 * =====================================
 * ForEach ( valueList ; expression )
 *
 * PURPOSE:
 *		ForEach repeatedly applies a calculation to each value in a ¶-delimited
 *		list. For each value in valueList, evaluates expression, substituting
 *		the value for each "~n" in expression. Expressions may also reference
 *		the value index (line number) being evaluated with "$~i". This is
 *		analogous to Map functionality in functional programming languages.
 *
 * NOTE:
 *		This is the recursive version of this function. It is slower, but
 *		capable of processing larger lists.
 *
 * RETURNS:
 *		A ¶-delimited list of the results of evaluating expression on valueList.
 *
 * EXAMPLE:
 *		ForEach (
 *			List ( "1 One" ; "2 Two" ; "3 Three"  );
 *			"Left ( ~n ; 1 ) + $~i"
 *		)	// = "2¶4¶6"
 *
 * PARAMETERS:
 *		valueList: A ¶-delimited list of inputs to expression
 *		expression: A calculation to evaluate
 *
 * DEPENDENCIES: none
 *
 * RELEASE:	2012-01-06
 *
 * REFERENCES:
 *		http://en.wikipedia.org/wiki/Map_(higher-order_function)
 * =====================================
 */

Case (
	/* Step 0, initialize routine */
	not $~map.step;
		Let ( [
			$~map.valueCount = ValueCount ( valueList );
			$~map.step = 1
		];
			ForEach ( valueList ; expression )
		);

	/* Step 1, evaluate expression */
	$~map.step = 1;
		Let ( [
			$~i = $~i + 1;
			~value =
				Evaluate (
					"Let ( ~n = "
					& Quote ( GetValue ( valueList ; $~i ) )
					& " ; "
					& expression
					& " )"
				);
			$~map.resultList =
				If ( $~i > 1 ; $~map.resultList & ¶ )
				& ~value;
			$~map.step =
				If ( $~i < $~map.valueCount;
					$~map.step;
					/* Else */ $~map.step + 1
				)
		];
			ForEach ( valueList ; expression )
		);

	/* Step 2, clean-up and return result */
	$~map.step = 2;
		Let ( [
			~resultList = $~map.resultList;

			// Purge variables
			$~i = "";
			$~map.resultList = "";
			$~map.step = "";
			$~map.valueCount = ""
		];
			~resultList
		)
)
/**
 * =====================================
 * Null
 *
 * PURPOSE:
 *		Mark in a readable way an empty string (for parameters and stuff)
 *
 * RETURNS:
 *		""
 *
 * EXAMPLE:
 *		If ( PatternCount ( Table::fieldName ; Tab & Tab ) ≥ 1;
 * 			"Awesome use of indentation!";
 * 			Null
 * 		);
 *
 * RELEASE:
 * 		2017-06-11
 *
 * REFERENCES:
 *		http://filemakerstandards.org/pages/viewpage.action?pageId=557129
 *
 * VERSION:	1.0
 * 
 * AUTHOR: 	© 2017 Mc128k
 * =====================================
 */

""

 

Code128B.fmp12

Share this post


Link to post
Share on other sites
Mc128k    2

There are multiple reasons for that.

  1. You don't need a font, this simplifies the deployment
  2. It works on iOS
  3. It works on FMS and WebDirect
  4. I don't know exactly, but I believe that the font is unable to calculate the checksum
  5. It works on containers, so it's more flexible and it can be scaled easily
  6. It works on all layouts, it doesn't need a specific layout object, like a custom text field, just a container
  7. It's cooler this way ;)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Similar Content

    • By kmccann84
      Hello, 
      I am extremely new to Filemaker. I've been trying to learn it but time always dictates. I am trying to create what I believe is a simple database. What I am trying to do is to have a very basic system to track parts usage by our mechanics by either barcode or part number. Basically the mechanic would come up to the computer. Enter a unit #, worker order #, date,  part #(either by manual entry or upc.) and qty.  Then I would like to be able to print a report in the morning that will display Unit #, work order #, date, part # and qty. I can then take this information and enter it into our system. The problem I have is our system doesn't allow bar coding. Also some of our parts don't have barcodes such as tires and brass fittings so I need a manual part entry. I can't have the report show a upc number. So I need to have a way for the database to take the upc and switch to show the part # it is related to. I can get the system to work fine and show the repor that I want. The only problem I have is I can't get it to switch the upc to the part #. I was wondering if some one could take a look at what I have done and inform me on what I could do. I am not looking for someone to do it for me. Just give me some guiding information. I wanted to say thank you in advance for any information you can supply.
      Inventory 2.fmp12
    • By 34South
       
      I developed a solution which utilises the barcode reader function. This worked perfectly in FMGo 14 on an iPhone 6 Plus. I upgraded to FMGo 15 but at the same time made a few programming changes, although not to the script containing the 'Insert from Device function'. On activating the script, the camera would activate and the barcode would be read successfully but, on a later occasion, the camera would activate, but not trigger on the same barcode as before and the camera would remain in scan mode unless cancelled. Thinking this was due to the changes I made, I spent hours trying to overcome the problem. Eventually, I deleted FMGo 15 and downloaded it again. It worked. However, the problem resurfaced. When it does, quitting the app restores the functionality. The 'Insert from Device' step I have scripted writes to a global field which I have placed off the layout. Again, sometimes it works, other times not, even when activated from the same layout using the same script. Could this be a bug in FMGo 15? Also, sometimes when clicking on an image in a container field, instead of going to the app extensions, FMGo 15 quits. Relaunching, on the same layout and photo, it works as expected. Again a bug?
    • By Budi Hananto Seto
      i have a script to find and add barcode if not available, but, the problem is, it is not automatically add new barcode, if the find result is not available, any suggestion about this script?
      i want to to find barcode through iphone camera, if not available, it will automatically add the new barcode. thank you
       
       
      script.tiff
    • By dav1089
      Hello,
      I am gonna describe a scenario where total automation needed using only barcode scan, please bear with me:
      I am creating operator timesheet layout for product lifecycle in list-view.
      Each operator has a list of unique barcodes(printed sheet) for each production function.
      Every activity(function) of print production is assigned code (barcode) that represents function type as well as operator name: For eg. if John is working on new plates function for Press he'd scan barcode 301-1 but if Marc is working on the same function , he'd scan 301-2 , Now '301' represents new plates function and number after hyphen(-) represents operator. In John's case 1 and Marc 2.
      So, on the interface(list view of functions) , when an operator scans barcode of function it will set time-in field value and name of operator in their fields based on calculation from code.
      I don't want STOP button for each function to set value of time-out (because it requires user interaction), rather, I want it automated.
      I am looking for some sort of script trigger that runs on every new code scan and search for last record with similar operator name and set time-out value as current time in that record and set the same value as time-in for new function record. 
      Thank you
       
    • By Kurt Hansen
      We have for many years (of forgotten and unknown reasons) put a zero in front of all 12-digit bar codes so that all bar codes in our FileMaker database appears as a 13-digit code.
      Our products in the database are from suppliers from all parts of the world and some are using EAN, while others use UPC.
      I need to separate them, so they will reflect the original barcodes (UPC (12) / EAN (13)). We have approximately 33,500 items in the database.
      How do I do it?
×

Important Information

By using this site, you agree to our Terms of Use.