Jump to content

Mc128k

Members
  • Posts

    19
  • Joined

  • Last visited

  • Days Won

    4

Everything posted by Mc128k

  1. There are multiple reasons for that. You don't need a font, this simplifies the deployment It works on iOS It works on FMS and WebDirect I don't know exactly, but I believe that the font is unable to calculate the checksum It works on containers, so it's more flexible and it can be scaled easily It works on all layouts, it doesn't need a specific layout object, like a custom text field, just a container It's cooler this way
  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
  3. As Lee asked, I'm posting here the functions. Also I updated the docs. /** * ===================================== * BarcodeEAN13_BMP_380px ( number ) * * PURPOSE: * Generate a binary BMP file containing an EAN-13 barcode * * NOTE: * Embed the contents in a container to see it * * RETURNS: * Binary BMP. * * PARAMETERS: * number: The number to encode in EAN-13 * * DEPENDENCIES: * BarcodeEAN13_Raw * * RELEASE: * 2017-06-11 * * VERSION: 1.0 * * AUTHOR: © 2017 Mc128k * ===================================== */ Let ( [ ~pad="000000000000"; ~toEncode=SerialIncrement ( ~pad ; number); ~binary=BarcodeEAN13_Raw( ~toEncode) ] ; Let ( [ _foreground_color = Substitute ( "1111" ; "1" ; "AAAA" ) ; // set to black _background_color = Substitute ( "1111" ; "1" ; "////" ) ; // white _base = "Qk2sBAAAAAAAADYAAAAoAAAAfAEAAAEAAAABABgAAAAAAHYEAAASCwAAEgsAAAAAAAAAAAAA" ; _map = Substitute ( ~binary ; "0" ; _background_color ); _map = Substitute ( _map; "1" ; _foreground_color ); _map = _map & "////" ] ; If(Length(~binary) ≠ 95 ; "error" ; Base64Decode ( _base & _map ; "barcode.bmp" ) ) ) ) /** * ===================================== * BarcodeEAN13_Raw ( input ) * * PURPOSE: * Generates the binary number for the EAN13 barcode * * RETURNS: * A binary number representing the barcode * * PARAMETERS: * input: the number to encode * * RELEASE: * 2017-06-11 * * REFERENCES: * https://en.wikipedia.org/wiki/International_Article_Number * * VERSION: 1.0 * * AUTHOR: © 2015 Mc128k http://www.mc128k.com * ===================================== */ Let([ ~code = input; ~length = Length(Filter( ~code; "1234567890")) ]; If ( ~length ≠ 12 ; "length not 12: " & ~length & input; Let([ ~sum_Odd=Middle(~code; 2; 1) + Middle(~code; 4; 1) + Middle(~code; 6; 1) + Middle(~code; 8; 1) + Middle(~code; 10; 1) + Middle(~code; 12; 1); ~sum_Even=Middle(~code; 1; 1) + Middle(~code; 3; 1) + Middle(~code; 5; 1) + Middle(~code; 7; 1) + Middle(~code; 9; 1) + Middle(~code; 11; 1); ~checksum=Mod(10 - Mod(((3 * ~sum_Odd) + ~sum_Even) ; 10 ) ; 10); ~data=~code & ~checksum; ~EAN_Start="101"; ~EAN_Intermediate="01010"; ~EAN_Stop="101"; ~eval=Middle(~data; 1; 1); ~mask=Case ( ~eval=0 ; "000000" ; ~eval=1 ; "001011" ; ~eval=2 ; "001101" ; ~eval=3 ; "001110" ; ~eval=4 ; "010011" ; ~eval=5 ; "011001" ; ~eval=6 ; "011100" ; ~eval=7 ; "010101" ; ~eval=8 ; "010110" ; ~eval=9 ; "011010" ); ~p1_1= Let([~n = 1 ; ~d=Middle(~data;~n + 1;1)]; Case(~d=0 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0001101" ; "0100111" ) ; ~d=1 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0011001" ; "0110011" ) ; ~d=2 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0010011" ; "0011011" ) ; ~d=3 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0111101" ; "0100001" ) ; ~d=4 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0100011" ; "0011101" ) ; ~d=5 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0110001" ; "0111001" ) ; ~d=6 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0101111" ; "0000101" ) ; ~d=7 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0111011" ; "0010001" ) ; ~d=8 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0110111" ; "0001001" ) ; ~d=9 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0001011" ; "0010111" ) )); ~p1_2= Let([~n = 2 ; ~d=Middle(~data;~n + 1;1)]; Case(~d=0 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0001101" ; "0100111" ) ; ~d=1 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0011001" ; "0110011" ) ; ~d=2 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0010011" ; "0011011" ) ; ~d=3 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0111101" ; "0100001" ) ; ~d=4 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0100011" ; "0011101" ) ; ~d=5 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0110001" ; "0111001" ) ; ~d=6 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0101111" ; "0000101" ) ; ~d=7 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0111011" ; "0010001" ) ; ~d=8 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0110111" ; "0001001" ) ; ~d=9 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0001011" ; "0010111" ) )); ~p1_3= Let([~n = 3 ; ~d=Middle(~data;~n + 1;1)]; Case(~d=0 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0001101" ; "0100111" ) ; ~d=1 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0011001" ; "0110011" ) ; ~d=2 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0010011" ; "0011011" ) ; ~d=3 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0111101" ; "0100001" ) ; ~d=4 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0100011" ; "0011101" ) ; ~d=5 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0110001" ; "0111001" ) ; ~d=6 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0101111" ; "0000101" ) ; ~d=7 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0111011" ; "0010001" ) ; ~d=8 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0110111" ; "0001001" ) ; ~d=9 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0001011" ; "0010111" ) )); ~p1_4= Let([~n = 4 ; ~d=Middle(~data;~n + 1;1)]; Case(~d=0 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0001101" ; "0100111" ) ; ~d=1 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0011001" ; "0110011" ) ; ~d=2 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0010011" ; "0011011" ) ; ~d=3 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0111101" ; "0100001" ) ; ~d=4 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0100011" ; "0011101" ) ; ~d=5 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0110001" ; "0111001" ) ; ~d=6 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0101111" ; "0000101" ) ; ~d=7 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0111011" ; "0010001" ) ; ~d=8 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0110111" ; "0001001" ) ; ~d=9 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0001011" ; "0010111" ) )); ~p1_5= Let([~n = 5 ; ~d=Middle(~data;~n + 1;1)]; Case(~d=0 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0001101" ; "0100111" ) ; ~d=1 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0011001" ; "0110011" ) ; ~d=2 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0010011" ; "0011011" ) ; ~d=3 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0111101" ; "0100001" ) ; ~d=4 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0100011" ; "0011101" ) ; ~d=5 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0110001" ; "0111001" ) ; ~d=6 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0101111" ; "0000101" ) ; ~d=7 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0111011" ; "0010001" ) ; ~d=8 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0110111" ; "0001001" ) ; ~d=9 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0001011" ; "0010111" ) )); ~p1_6= Let([~n = 6 ; ~d=Middle(~data;~n + 1;1)]; Case(~d=0 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0001101" ; "0100111" ) ; ~d=1 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0011001" ; "0110011" ) ; ~d=2 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0010011" ; "0011011" ) ; ~d=3 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0111101" ; "0100001" ) ; ~d=4 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0100011" ; "0011101" ) ; ~d=5 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0110001" ; "0111001" ) ; ~d=6 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0101111" ; "0000101" ) ; ~d=7 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0111011" ; "0010001" ) ; ~d=8 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0110111" ; "0001001" ) ; ~d=9 ; If ( Middle(~mask ; ~n ; 1) = 0 ; "0001011" ; "0010111" ) )); ~p2_1= Let([~n = 1 ; ~d=Middle(~data;~n + 1 + 6 ;1)]; Case(~d=0 ; "1110010" ; ~d=1 ; "1100110" ; ~d=2 ; "1101100" ; ~d=3 ; "1000010" ; ~d=4 ; "1011100" ; ~d=5 ; "1001110" ; ~d=6 ; "1010000" ; ~d=7 ; "1000100" ; ~d=8 ; "1001000" ; ~d=9 ; "1110100" )); ~p2_2= Let([~n = 2 ; ~d=Middle(~data;~n + 1 + 6 ;1)]; Case(~d=0 ; "1110010" ; ~d=1 ; "1100110" ; ~d=2 ; "1101100" ; ~d=3 ; "1000010" ; ~d=4 ; "1011100" ; ~d=5 ; "1001110" ; ~d=6 ; "1010000" ; ~d=7 ; "1000100" ; ~d=8 ; "1001000" ; ~d=9 ; "1110100" )); ~p2_3= Let([~n = 3 ; ~d=Middle(~data;~n + 1 + 6 ;1)]; Case(~d=0 ; "1110010" ; ~d=1 ; "1100110" ; ~d=2 ; "1101100" ; ~d=3 ; "1000010" ; ~d=4 ; "1011100" ; ~d=5 ; "1001110" ; ~d=6 ; "1010000" ; ~d=7 ; "1000100" ; ~d=8 ; "1001000" ; ~d=9 ; "1110100" )); ~p2_4= Let([~n = 4 ; ~d=Middle(~data;~n + 1 + 6 ;1)]; Case(~d=0 ; "1110010" ; ~d=1 ; "1100110" ; ~d=2 ; "1101100" ; ~d=3 ; "1000010" ; ~d=4 ; "1011100" ; ~d=5 ; "1001110" ; ~d=6 ; "1010000" ; ~d=7 ; "1000100" ; ~d=8 ; "1001000" ; ~d=9 ; "1110100" )); ~p2_5= Let([~n = 5 ; ~d=Middle(~data;~n + 1 + 6 ;1)]; Case(~d=0 ; "1110010" ; ~d=1 ; "1100110" ; ~d=2 ; "1101100" ; ~d=3 ; "1000010" ; ~d=4 ; "1011100" ; ~d=5 ; "1001110" ; ~d=6 ; "1010000" ; ~d=7 ; "1000100" ; ~d=8 ; "1001000" ; ~d=9 ; "1110100" )); ~p2_6= Let([~n = 6 ; ~d=Middle(~data;~n + 1 + 6 ;1)]; Case(~d=0 ; "1110010" ; ~d=1 ; "1100110" ; ~d=2 ; "1101100" ; ~d=3 ; "1000010" ; ~d=4 ; "1011100" ; ~d=5 ; "1001110" ; ~d=6 ; "1010000" ; ~d=7 ; "1000100" ; ~d=8 ; "1001000" ; ~d=9 ; "1110100" )); ~part_1=~p1_1 & ~p1_2 & ~p1_3 & ~p1_4 & ~p1_5 & ~p1_6; ~part_2=~p2_1 & ~p2_2 & ~p2_3 & ~p2_4 & ~p2_5 & ~p2_6 ]; ~EAN_Start & ~part_1 & ~EAN_Intermediate & ~part_2 & ~EAN_Stop ) // Let ) // If ~length ) // Let
  4. That confirms my hypothesis.. Thanks
  5. Just what are they for exactly, the docs don't say how they work and if they are exploitable in some way by custom functions.
  6. Kinda figured it out that already, custom functions do not fully exploit the language. What about the square brackets?
  7. I often see that FileMaker native functions use square brackets to define lists, like let ( [ ~var1 = 1 ; ~var2 = 2 ] ~var1 + ~var2 ) Or JSON functions, that actually seem to be "variadic" in the sense that they take a variable number of arguments: JSONSetElement ( "{}" ; [ "id" ; "FB4" ; JSONString ] ; [ "name" ; "Vanilla Cake" ; JSONString ] ; [ "price" ; 17.5 ; JSONNumber ] ; [ "stock" ; 12 ; JSONNumber ] ; [ "category" ; "Cakes" ; JSONString ] ; [ "special" ; true ; JSONBoolean ] ) ] Now, I've been searching for a way to do custom variadic functions, but it seems impossible. And the official documentation doesn't mention the square brackets' real meaning from the language standpoint. What are these "array-like" things exactly? Is there a way to exploit them in custom functions or is it reserved for native functions only? Thanks
  8. If you are too much generic, yeah, it's meaningless. Still there is a distinction. Otherwise all languages would be exactly the same. Would you like to program in Assembly or brainf*ck? Perl? Ruby? C? They are all turing-complete, so they are all the same. That sounds wrong to me. Working with filemaker scripts is like being able to only speak using concrete words. You cannot make abstractions or generalise concepts. The dictionary is poor. Macros are like the mouse/keyboard recording programs, they tell what to do with the UI, and if you see the command palette, that's exactly it. "Go to field".. "Perform find"... "Select all"... "Insert"... these are all actions that an user can do. That is exactly what irritates me, as I learned what can be done with more complex languages, filemaker makes me feel stupid because programming here is like trying to teach algebra to a five years old child. I hope that makes it clearer And about speed.. yeah, that could be sufficing, but it hurts a lot scalability and usability. It really makes a difference to have a fast application.
  9. Except that this isn't actually a "programming language", it's more a scripting system, or like I said a "macro" system. But there's no problem after all, as long as it's possible to build everything with it. Still, it's hard to create maintainable and reusable code. You're right of course, I'm not expecting execution speed for JS either (even if it's way faster in theory compared to other high-level languages), but at least that scripting steps do not take forever to execute. It's like an automation system, where every step uses an incredibly high processing power to be parsed, checked and executed. Excellent for small things, terrible for bigger ones. Again, I agree that some other systems totally fail. And that's the beauty of FileMaker, it makes easy what takes a lot of effort to build. I would prefer creating stuff with it rather than Java. When you deploy with many users (I am working on a medium sized project atm) you encounter sync and versioning issues. Building reusable and modular code becomes hard. About the number of records I'm not referring to millions here (somebody would lose their head if he put FM for a solution this big), but only thousands. Make a script that does an operation on say 2000 records, and run it. It's slow compared to other programming environments. Even PHP can be faster. I don't have a good definition of "professional", I can just feel that compared to other systems in the industry this looks like a toy. Actually this is like MS Access to a higher level. To understand FileMaker we have to go back to Claris and v2.0. See what the "Macintosh UI" innovation really meant back there. No code, intuitive graphical interfaces, drag and drop and so on. Other systems have failed, I think "Double Helix" was somehow similar, but I might be wrong here.
  10. One last thing. If we call them "Macros" instead of "Scripts" it makes more sense. They are a bunch of macros for writing UI operations.
  11. Sorry about the upcoming rant, you are free to ignore it. I've been working for years with filemaker and other languages, despite its easy-to-use interface I think scripts are one of the worst thing of this platform. Correct me if I'm wrong on any of this. For starters, I need a text editor. Or source files I can version with git and edit with sublime. Not a fancy drag-and-drop (now it's better) script editor. This really looks like a toy, and scripts are slow too (execution). Can't I just write functions and parameters with code completion? Nope, I have to mix writing and clicking windows every time. Keyboard shortcuts help here, but not that much. Then, it's not trivial to build some abstractions. Using an object-oriented language is too much maybe, but at least some functions and complex data structures are necessary. Everything comes down to rebuilding the wheel, inventing (or adhering to) standards or creating hacks to make something useful. Decoupling scripts is hard given their nature, parameter passing needs a parser every time, RPC is complicated and resource-intensive. What about error handling? Logging? Exceptions? Data observables? Yes, we can build everything I mentioned, but it's rather complicated, and for a platform like this I begin to think if I'm being stupid not using any other serious framework for building apps. It's perfect for small projects, but it doesn't scale any good. And it becomes expensive too. Scripts ARE turing-complete, but still they are pure madness when it comes to it, basic language constructs that are implemented in nearly every other serious language are missing (for loops, arrays, variable scope, types, tables/dictionaries) and have to be built with other elements. There is no search, no find/replace, no simple import/export. Asynchronous programming is complicated, and sometimes impossible (HTTP requests), it's hard to work with data without entangling everything with a VIEW (yes, I have to be in a layout to build a context). They are called "scripts" for a reason after all. Patterns can be built, but it's hard to make them good. What if I wanted to create an "universal sync system" that didn't rely on the table schema? Is there an API to simply get the table items as... dictionaries? Nope, I have to build a layout with every field and enumerate them! If I add a new field I have to edit the layout too. Cool. I'm researching a way to do it with ExecuteSQL, there is a hidden FileMaker object that seems absent from every document on the official site (or maybe I missed it), this could probably eliminate enumeration problems. What about exchanging data? Well, "serious" languages have libraries (objects or functions) that create an XML DOM and then serialize it, right? Not here, even the most basic plugin implies heavy limitations (like not running on iOS or having to upgrade at every release) and they cost a f..* ton of money. Want to do it with scripts? Possible of course, I just have to implement it from scratch. OR we can use JSON, at least they implemented native functions for it! Hooray! Now, we have our serialized records (and base64 encoded containers, thanks fmp12), I just need to compress it to send it over a slow WAN link.. Oh right, sorry. I'll just send uncompressed code. Still I can encrypt it, right? Nope. No security functions outside of expensive plugins that stop working after the new release. Filemaker encrypts its protocol at least. Shared libraries amonst files? Yeah, have to open the entire file at runtime. Again, RPC sucks. Encapsulation? Decoupling? What's that? This is a script. Localisation and internationalisation? Build it yourself. Also there is some "black magic" with locales, like "the number formats are determined by the system with FMP that saves the file". Background processing? Just use a temporary window placed at +999999 +99999 with dimensions of 1px 1px, do your stuff here and then close it. This is the only way to correctly preserve UI state while doing other operations like editing an item's stock. Seriously? Run the script in the server! And meanwhile rebuild the entire context, wait a couple of seconds and you're done. Do this for every record in a list of 1000 elements. Remotely. This is not a platform for professionals. This is just a prototyping system for databases.
  12. Thanks for the insight! Actually I'm looking to use the web viewer just to "execute decent code" and then get data from it, maybe a base64 encoded image. I read somewhere that it's possible to communicate bidirectionally. Too bad you say that js code for qr is bad. And no server support. I'll try researching... ******* filemaker scripts. They are close to true code, but not enough. [Edit] Wow, I didn't know da-mn was a censored word.
  13. Such a shame this isn't included in FM itself, reminds me how unprofessional this solution is. Anyway I plan to support QR too in the future, and probably I'll post it here when it's done. A good hack I think would be to use a "complex" javascript inside a web viewer to generate the binary, anybody had some experiences with it?
  14. Use this, I created it myself. It's available for free. http://www.mc128k.info/2015/12/codici-a-barre-su-filemaker-con-una-funzione/ It generates a BMP for a container field, I believe paid solutions use the same technique.
  15. Well, excellent work with Barcode creator, I see that Code 128 looks pretty much a hassle to implement. My solution doesn't have specific needs, so I chose the most common just to be compatible with all readers. And just to inform everybody, I am going to post online the functions, when the appropriate website will work, now it looks offline.
  16. The latest solution I developed had to run in OSX, Windows, iPad and WebDirect. Of course I used the same layouts for every device, and each feature was tested on all platforms. It's better for everyone, just use a 1024x768 screen size and it will work beautifully. Navigation should happen in a single window which switches layouts with buttons on the top navigation bar. The iPhone obviously has to be a separate thing, the entire application workflow is often different. Desktop users tend to like big buttons, so design an interface for iPad and it will work even on Surface (*ehm*) tablets which have touch screens. Also it's simpler for an user to have the same interface, and less a hassle for developers to propagate changes.
  17. I never studied how UPC works, this is new stuff for me. So UPC works just like EAN (with checksum and stuff) but with a zero at the beginning in the input number? Do you think using UPC has advantages over EAN? Of course the function can't generate codes, it's meant for existing articles or scalar numbers for a ticketing application I created.
  18. I meant it's not for the generation of UPC codes. I may consider making it in the future, although the code is now public and anybody could follow the basic idea and make the rest.
  19. Hi all I am writing this post because I would like to share a custom function I created for generating EAN-13 barcodes. As almost every other (paid) solution involves plugins, scripts, fonts or other garbage, I decided to create something much cleaner. Everything the file needs is two custom functions, one that calls the other. The first, "GenerateEAN13_Raw" creates the binary string starting from the actual number, and the second, "GenerateEAN13_BMP_380px" takes the same number and generates a BMP file (that can be stored in a container) with the actual rendered barcode (sharp and clear). It took me many hours to create this, so I hope this will be useful for somebody. I just wanted to post everything to FMFunctions but the site is currently down. I know someone should not trust unknown download links, but I'm not attaching viruses here. The proof of concept is hosted on my site here: Download Feel free to use the code as you wish. No, this is not for UPC or other barcodes, just EAN-13. You can take the basic idea and then make yours. Some of the code was inspired by another solution, but in the end I had to recreate even the BMP header from scratch.
×
×
  • Create New...

Important Information

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