With XML Publisher 5.6.2 you now have the ability to execute pre processing on your data prior to applying a barcode font to the data in the output document. For example you may need to calculate checksum values or start and end bits for the data before formatting them.
In lieu of Oracle not having the barcode fonts available I have worked with the popular IDAutomation fonts, they provide the necessary java code support for their fonts.
Information on their fornts can be found here: http://www.idautomation.com/fonts/
Information on their java source code here: http://www.idautomation.com/fonts/tools/sourcecode/FontIDAutomation.txt
The solution requires that you register a barcode encoding class with XML Publisher that can then be instantiated at runtime to carry out the formatting in the template. This is covered in <<link to class description and sample and setup>>
In the template there are two new commands that need to be used to enable the formatting feature.
<?register-barcode-vendor:java_class_name;barcode_vendor_id?>
This command registers the barcode encoding class. It requires a java class name, this will carry out the encoding and a barcode vendor ID as defined by the class. This command needs to appear before the commands to encode the data in the template. For example:
<?register-barcode-vendor:弛racle.apps.xdo.template.rtf.util.barcoder.BarcodeUtil?;'XMLPBarVendor'?>
So the class is defined as 双racle.apps.xdo.template.rtf.util.barcoder.BarcodeUtil? and the vendor id as 'XMLPBarVendor'
For the data to be encoded the following command is required:
<?format-barcode:data;barcode_type;barcode_vendor_id?>
This accepts:
? data ? the element in the XML to be encoded
? barcode_type ? this is the method in the encoding class used to format the data e.g. Code128a
? barcode_vendor_id ? this is the ID as defined in the register-barcode-vendor field.
At runtime the barcode_type method will be called to format the data value and the barcode font will then be applied to the data in the final output. So in the template create the field and highlight it with you chosen bardcode (make sure the font is available at runtime) and you're done .. for the template anyway. Now you'll need to write the class to carry out the encoding ... dont panic we have an example you can copy.
Advanced Barcode Font Formatting Implementation
For the advanced formatting to work in the template a java class is required that will have the appropriate methods to format the data at runtime. Many font vendors offer the code with their fonts to carry out the formatting, these need to be incorporated as methods into a class that is available to the XML Publisher formatting libraries at runtime. There are some specific interfaces that need to be provided in the class for the library to call the correct method for encoding.
This class has to have the following 3 methods implemented:
/**
* Return a unique ID for this bacode encoder
* @return the id as a string
*/
public String getVendorID();
/**
* Return true if this encoder support a specific type of barcode
* @param type the type of the barcode
* @return true if supported
*/
public boolean isSupported(String type);
/**
* Encode a barcode string by given a specific type
* @param data the original data for the barcode
* @param type the type of the barcode
* @return the formatted data
*/
public String encode(String data, String type);
The class should located in the classpath for the middle tier JVM in which XML Publisher is running.
Note: For EBS users the class needs to be in the classpath for the middle tier and any concurrent tiers that are present.
If in the <?register-barcode-vendor:...?> command, the barcode_vendor_id is not provided. XML Publisher will call the getVendorID() and use the result of the method as ID for the vendor.
An example class that supports the code128 a, b and c encodings follows. You'll need to compile the class and to do that you'll need the XMLP java libraries in the classpath to compile. Once you have that you can simply copy the following code and add your encoding methods.
--------------------------------------------------------------------------------
package oracle.apps.xdo.template.rtf.util.barcoder;
import java.util.Hashtable;
import java.lang.reflect.Method;
import oracle.apps.xdo.template.rtf.util.XDOBarcodeEncoder;
import oracle.apps.xdo.common.log.Logger;
// This class name will be used in the register vendor field in the template.
public class BarcodeUtil implements XDOBarcodeEncoder
// The class implements the XDOBarcodeEncoder interface
{
// This is the barcode vendor id that is used in the register vendor field and format-barcode fields
public static final String BARCODE_VENDOR_ID = "XMLPBarVendor";
// The hastable is used to store references to the encoding methods
public static final Hashtable ENCODERS = new Hashtable(10);
// The BarcodeUtil class needs to be instantiated
public static final BarcodeUtil mUtility = new BarcodeUtil();
// This is the main code that is executed in the class, it is loading the methods for the encoding into the hashtable. In this case we are loading the three code128 encoding methods we have created.
static {
try {
Class[] clazz = new Class[] { "".getClass() };
ENCODERS.put("code128a",mUtility.getClass().getMethod("code128a", clazz));
ENCODERS.put("code128b",mUtility.getClass().getMethod("code128b", clazz));
ENCODERS.put("code128c",mUtility.getClass().getMethod("code128c", clazz));
} catch (Exception e) {
// This is using the XML Publisher logging class to push errors to the XMLP log file.
Logger.log(e,5);
}
}
// The getVendorID method is called from the template layer at runtime to ensure the correct encoding method are used
public final String getVendorID()
{
return BARCODE_VENDOR_ID;
}
//The isSupported method is called to ensure that the encoding method called from the template is actually present in this class. If not then XMLP will report this in the log.
public final boolean isSupported(String s)
{
if(s != null)
return ENCODERS.containsKey(s.trim().toLowerCase());
else
return false;
}
// The encode method is called to then call the appropriate encoding method, in this example the code128a/b/c methods.
public final String encode(String s, String s1)
{
if(s != null && s1 != null)
{
try
{
Method method = (Method)ENCODERS.get(s1.trim().toLowerCase());
if(method != null)
return (String)method.invoke(this, new Object[] {
s
});
else
return s;
}
catch(Exception exception)
{
Logger.log(exception,5);
}
return s;
} else
{
return s;
}
}
/** This is the complete method for Code128a */
public static final String code128a( String DataToEncode )
{
char C128_Start = (char)203;
char C128_Stop = (char)206;
String Printable_string = "";
char CurrentChar;
int CurrentValue=0;
int weightedTotal=0;
int CheckDigitValue=0;
char C128_CheckDigit='w';
DataToEncode = DataToEncode.trim();
weightedTotal = ((int)C128_Start) - 100;
for( int i = 1; i <= DataToEncode.length(); i++ )
{
//get the value of each character
CurrentChar = DataToEncode.charAt(i-1);
if( ((int)CurrentChar) < 135 )
CurrentValue = ((int)CurrentChar) - 32;
if( ((int)CurrentChar) > 134 )
CurrentValue = ((int)CurrentChar) - 100;
CurrentValue = CurrentValue * i;
weightedTotal = weightedTotal + CurrentValue;
}
//divide the WeightedTotal by 103 and get the remainder,
//this is the CheckDigitValue
CheckDigitValue = weightedTotal % 103;
if( (CheckDigitValue < 95) && (CheckDigitValue > 0) )
C128_CheckDigit = (char)(CheckDigitValue + 32);
if( CheckDigitValue > 94 )
C128_CheckDigit = (char)(CheckDigitValue + 100);
if( CheckDigitValue == 0 ){
C128_CheckDigit = (char)194;
}
Printable_string = C128_Start + DataToEncode + C128_CheckDigit + C128_Stop + " ";
return Printable_string;
}
/** This is the complete method for Code128b ***/
public static final String code128b( String DataToEncode )
{
char C128_Start = (char)204;
char C128_Stop = (char)206;
String Printable_string = "";
char CurrentChar;
int CurrentValue=0;
int weightedTotal=0;
int CheckDigitValue=0;
char C128_CheckDigit='w';
DataToEncode = DataToEncode.trim();
weightedTotal = ((int)C128_Start) - 100;
for( int i = 1; i <= DataToEncode.length(); i++ )
{
//get the value of each character
CurrentChar = DataToEncode.charAt(i-1);
if( ((int)CurrentChar) < 135 )
CurrentValue = ((int)CurrentChar) - 32;
if( ((int)CurrentChar) > 134 )
CurrentValue = ((int)CurrentChar) - 100;
CurrentValue = CurrentValue * i;
weightedTotal = weightedTotal + CurrentValue;
}
//divide the WeightedTotal by 103 and get the remainder,
//this is the CheckDigitValue
CheckDigitValue = weightedTotal % 103;
if( (CheckDigitValue < 95) && (CheckDigitValue > 0) )
C128_CheckDigit = (char)(CheckDigitValue + 32);
if( CheckDigitValue > 94 )
C128_CheckDigit = (char)(CheckDigitValue + 100);
if( CheckDigitValue == 0 ){
C128_CheckDigit = (char)194;
}
Printable_string = C128_Start + DataToEncode + C128_CheckDigit + C128_Stop + " ";
return Printable_string;
}
/** This is the complete method for Code128c **/
public static final String code128c( String s )
{
char C128_Start = (char)205;
char C128_Stop = (char)206;
String Printable_string = "";
String DataToPrint = "";
String OnlyCorrectData = "";
int i=1;
int CurrentChar=0;
int CurrentValue=0;
int weightedTotal=0;
int CheckDigitValue=0;
char C128_CheckDigit='w';
DataToPrint = "";
s = s.trim();
for(i = 1; i <= s.length(); i++ )
{
//Add only numbers to OnlyCorrectData string
CurrentChar = (int)s.charAt(i-1);
if((CurrentChar < 58) && (CurrentChar > 47))
{
OnlyCorrectData = OnlyCorrectData + (char)s.charAt(i-1);
}
}
s = OnlyCorrectData;
//Check for an even number of digits, add 0 if not even
if( (s.length() % 2) == 1 )
{
s = "0" + s;
}
//<<<< Calculate Modulo 103 Check Digit and generate DataToPrint >>>>
//Set WeightedTotal to the Code 128 value of the start character
weightedTotal = ((int)C128_Start) - 100;
int WeightValue = 1;
for( i = 1; i <= s.length(); i += 2 )
{
//Get the value of each number pair (ex: 5 and 6 = 5*10+6 =56)
//And assign the ASCII values to DataToPrint
CurrentChar = ((((int)s.charAt(i-1))-48)*10) + (((int)s.charAt(i))-48);
if((CurrentChar < 95) && (CurrentChar > 0))
DataToPrint = DataToPrint + (char)(CurrentChar + 32);
if( CurrentChar > 94 )
DataToPrint = DataToPrint + (char)(CurrentChar + 100);
if( CurrentChar == 0)
DataToPrint = DataToPrint + (char)194;
//multiply by the weighting character
//add the values together to get the weighted total
weightedTotal = weightedTotal + (CurrentChar * WeightValue);
WeightValue = WeightValue + 1;
}
//divide the WeightedTotal by 103 and get the remainder,
//this is the CheckDigitValue
CheckDigitValue = weightedTotal % 103;
if((CheckDigitValue < 95) && (CheckDigitValue > 0))
C128_CheckDigit = (char)(CheckDigitValue + 32);
if( CheckDigitValue > 94 )
C128_CheckDigit = (char)(CheckDigitValue + 100);
if( CheckDigitValue == 0 ){
C128_CheckDigit = (char)194;
}
Printable_string = C128_Start + DataToPrint + C128_CheckDigit + C128_Stop + " ";
Logger.log(Printable_string,5);
return Printable_string;
}
}
--------------------------------------------------------------------------------
Once the class is created and placed in the correct class path your template creators can start using it to format the data for barcodes. You will need to communicate to them the following:
1. The class name and path. In this example: oracle.apps.xdo.template.rtf.util.barcoder.BarcodeUtil
2. The barcode vendor id you created. In this example 噌MLPBarVendor?
3. The available encoding methods, in this example, code128a, code128b and code128c
They can then use this information to sucessfully encode their data for barcode output.
I can see in the java code,
char C128_Start = (char)204;
Why here the start code is 204, not 104?
We are looking to use IDAutomation's Code 128 Barcode in the Oracle Apps with the PO Output for Communication report. We are wondering what to expect for the required number of font licenses: 1 per server, 1 per potential user, etc...
Obviously we will work with the vendor on the number of licenses, but I was hoping you might be able to shed some insight on this. I'm not sure how well the vendor understands Oracle applications and I'd like to be prepped for the potential automatic response of "1 font license per Oracle user" that I may receive.
Best regards,
Suzanne
Is it possible to have vertical barcode in BIP? We are using horizontal barcodes but have a requirement to display few barcodes vertically. I do not see any feature/documentation regarding this. Can you suggest if it is possible?
Regards,
Pratul
Need on the Java Encoder part.
I copied the encoding code and compiled the code into java Class as requested
javac -g -Xlinit BarcodeUtil.java
I getting
BarcodeUtil.java:32: warning: [unchecked] unchecked call to put(K,V) as a member
of the raw type java.util.Hashtable
ENCODERS.put("code128a",mUtility.getClass().getMethod("code128a", clazz));
Any help with this
Thanks for your info in the blog.
Can we encode application identifiers using the approach you have mentioned in this blog?
If not, please suggest a menthod to encode data string containing application identifiers.
Thank You
Do you know of anyone successfully using the PDF417 barcode feature of Adobe Acrobat Pro 9 Extended. I loaded the PDF template with this barcode. Unfortunately, the barcode value is not updated by the query results. The associated fields used to calculate the barcode are updated, but not the barcode calculated value itself.
I can go ahead with the IDAutomation/PDF417 encoder class solution, but Adobe would be much easier as I'm starting with Adobe templates. My understanding is that the IDAutomation/PDF417 class will require RTF (or similar) templates and I cannot use PDF templates.
Thanks for the great articles on barcoding in XML publisher -- they are highly useful.
Sincerely,
James Wilson
bayshorecomputing@yahoo.com
Hi All, I am not able generate PDF417 font barcode for my client.. Can anyone send me a live snapshot for the same
anoop.jain88@gmail.com
Thanks in advance
Anoop Jain
Hi
Tim,
if you have step by step instruction to install code128 for XML Publisher, can you please with us.
Thanks
Surendra
Surendra
I believe its covered in the user docs.
Tim
I am new to XML Publisher font installation, we bought the software code 128 after that I don't know how to install class file. I never write a class file.
Please help me with this issue.
Surendra
You'll need some java experience, not much thou. I suggest you get something like jdeveloper installed and open up the java class you have and check to see whats its doing. Its going to be very similar to the one above.
Check the docs and see what the requirements are from BIPs side and then create a wrapper class to call the font vendors encoding functions as needed. Its all out there, you just need to put it together.
Tim
Hi surendra
I am also trying to use code128b font in XML publisher, if you are able to get the steps then can you please share with am also new to java thing
Thanks,
Param
Surendra
Check out the other barcode posts.
https://blogs.oracle.com/xmlpublisher/entry/barcoding_102
Best way to test is to first not apply the font in the RTF template ie leave it as a readable font. That way you can test if your data is being encoded correctly.
Make sure BIP is in debug mode so you can see any error messages.
Tim
Hi Tim,
I have tried it without applying font ,it seems data is being encoded properly. But barcode does not show in final output
Thanks,
Param
So your java is working, thats good!
Im guessing your font is not mapped onto the server correctly. The font needs to be mapped for the PDF output because we embed a sub set into the PDF document.
The UI is pretty straightforward to do the mapping. The font file itself needs to be copied into the server fonts directory.
Check the docs for font mapping. You did not say what version you are running so I can not provide exact links:
Jump off page is
http://www.oracle.com/technetwork/middleware/bi-foundation/documentation/bi-pub-096318.html
Tim
Hi Tim,
I am not sure what's wrong here , I followed the steps mentioned here.
I copied this packaged and created a java file name BarcodeUtil.java and compiled it , but i placed it on our custom folder in JAVA TOP,
Then i added following two tags in my rtf template
<?register-barcode-vendor: arrow.oracle.apps.xxvas.wip.jobtraveler.BarcodeUtil;XMLPBarVendor?>
and field as
<?format-barcode:SAMPLE;code128b;XMLPBarVendor?>
where SAMPLE is test fiel from XML file, which has value as " Sample Test", now whenever I run report it simply gives me out
put as "Sample Test", No barcodes. IT seems that it is not even calling the class. PLease help
Thanks,
Param
Hey Tim,
Do you have some stuff for .NET barcodes?
I have followed the steps you mention I can get a scanable barcode but it will not encode the space character I used the Code128 font from http://www.idautomation.com/fonts/ which you describe above as well as others. However, none of them will encode the space. Is there an additional step I am missing to do?
Hi Tim,
I have followed the steps you mention I can get a scanable barcode but it will not encode the space character I used the Code128 font which you describe above as well as others. However, none of them will encode the space. Is there an additional step I am missing to do?
Thanks
Joe
Tim,
I am running into the same issue as Param above. We are on 11.5.10.2 and BI Publisher template is 10.1.3.4.1 Build 130.
I posted this on the Oracle-Community forums at this link:
https://community.oracle.com/message/12574802
Here are some details on what I did on the Application tier:
1. Created a BarcodeUtil.java class under $JAVA_TOP/oracle/apps/xdo/template/rtf/util/barcoder (using your code)
2. The IDAutomation software is installed under $JAVA_TOP - so I see the DataMatrixEncoder.class under $JAVA_TOP/com/idautomation/fontencoder/datamatrix directory
3. I used a small test file DMatrixTest.java to run at command line (see below); It works fine and encodes the static text passed in the script (Data Matrix Test):
4. I created a BI Publisher concurrent report which takes one parameter and displays the datamatrix encoding for that passed parameter
5a. Created a new BI Publisher template in MS Word with just two fields. The first one is a text form field and has a help text of <?register-barcode-vendor: 'oracle.apps.xdo.template.rtf.util.barcoder.BarcodeUtil' ; 'XMLPBarVendor' ?>
5b. The second text form field has a help text of <?format-barcode: PARAM_TEXT1; 'datamatrix' ; 'XMLPBarVendor’?>; I even tried without the form field and just typed the text to see if that makes a difference
6. When I submit the concurrent request, I do not see the encoding..I just see the value I passed (PARAM_TEXT1); So the encoding is not happening
7. I enabled BI Publisher Logging and the xdo.log nor any of the log files have any reference to the BarcodeUtil class nor the ID automation classes.
And I am stuck here, not sure how to proceed from here. What could I be missing?
Thanks,
Venkat
// DMatrixTest.java
import java.io.*;
import com.idautomation.fontencoder.datamatrix.*;
class DMatrixTest
{
public static void main ( String [] args )
{
//Here is the data we will encode
String dataToEncode = "Data Matrix Test";
//NOTE: "DataMatrixEncoder" is the class of the encoder
DataMatrixEncoder dme=new DataMatrixEncoder();
System.out.println("\n"+ "This is an example of the Data Matrix Java Font Encoder."+"\n");
//This is an example of formatting data to the font...
System.out.println( dme.fontEncode(dataToEncode) );
System.out.println("\n"+ "The above code will create a Data Matrix symbol when");
System.out.println("displayed or printed with the Data Matrix font."+"\n"+"\n");
}
}
Tim,
Not sure the first one got posted. So, submitting this again.
I am running into the same issue as Param above. We are on 11.5.10.2 and BI Publisher template is 10.1.3.4.1 Build 130.
I posted this on the Oracle-Community forums at this link:
https://community.oracle.com/message/12574802
Here are some details on what I did on the Application tier:
1. Created a BarcodeUtil.java class under $JAVA_TOP/oracle/apps/xdo/template/rtf/util/barcoder (using your code)
2. The IDAutomation software is installed under $JAVA_TOP - so I see the DataMatrixEncoder.class under $JAVA_TOP/com/idautomation/fontencoder/datamatrix directory
3. I used a small test file DMatrixTest.java to run at command line (see below); It works fine and encodes the static text passed in the script (Data Matrix Test):
4. I created a BI Publisher concurrent report which takes one parameter and displays the datamatrix encoding for that passed parameter
5a. Created a new BI Publisher template in MS Word with just two fields. The first one is a text form field and has a help text of <?register-barcode-vendor: 'oracle.apps.xdo.template.rtf.util.barcoder.BarcodeUtil' ; 'XMLPBarVendor' ?>
5b. The second text form field has a help text of <?format-barcode: PARAM_TEXT1; 'datamatrix' ; 'XMLPBarVendor’?>; I even tried without the form field and just typed the text to see if that makes a difference
6. When I submit the concurrent request, I do not see the encoding..I just see the value I passed (PARAM_TEXT1); So the encoding is not happening
7. I enabled BI Publisher Logging and the xdo.log nor any of the log files have any reference to the BarcodeUtil class nor the ID automation classes.
And I am stuck here, not sure how to proceed from here. What could I be missing?
Thanks,
Venkat
// DMatrixTest.java
import java.io.*;
import com.idautomation.fontencoder.datamatrix.*;
class DMatrixTest
{
public static void main ( String [] args )
{
//Here is the data we will encode
String dataToEncode = "Data Matrix Test";
//NOTE: "DataMatrixEncoder" is the class of the encoder
DataMatrixEncoder dme=new DataMatrixEncoder();
System.out.println("\n"+ "This is an example of the Data Matrix Java Font Encoder."+"\n");
//This is an example of formatting data to the font...
System.out.println( dme.fontEncode(dataToEncode) );
System.out.println("\n"+ "The above code will create a Data Matrix symbol when");
System.out.println("displayed or printed with the Data Matrix font."+"\n"+"\n");
}
}