Trying to use Apache Batik with Lucee on Ubuntu 18. I used batik a long time ago in ColdFusion/Windows but can’t seem to get it going in Lucee. I put the latest batik-all-1.12.jar file in /opt/lucee/tomcat/webapps/ROOT/WEB-INF/lucee/lib/ and restarted Lucee but I don’t see it in the list of jars on Lucee admin page. I can load it manually with Batik = createObject(‘java’,‘org.apache.batik.transcoder.image.PNGTranscoder’,‘/opt/lucee/lib/batik-all-1.12.jar’).init(); but I get Error: cannot load class through its string name, because no definition for the class with the specified name [org.apache.batik.transcoder.TranscoderInput].
I am trying to convert .svg file to png and batik was awesome in the past but I’m not a java programmer and I don’t know what I’m doing… ANY help would be appreciated.
Still same error.
Cause: cannot load class through its string name, because no definition for the class with the specified name [org.apache.batik.transcoder.TranscoderInput] could be found caused by (java.lang.ClassNotFoundException:org.apache.batik.transcoder.TranscoderInput not found by lucee.core [46];java.lang.ClassNotFoundException:org.apache.batik.transcoder.TranscoderInput;)
there were some strange problems with thread context, can’t remember if that was still with ACF or after I switched to Lucee tho… anyway it works with lucee!
<cfcomponent displayName="SVG Converter" output="false">
<cffunction name="Init" access="public" returntype="any" output="false">
<!--- Return This reference. --->
<cfscript>
variables.Javaloader=getJavaLoader();
</cfscript>
<cfreturn this />
</cffunction>
<cffunction name="getJavaLoader" returntype="any" output="false" access="public">
<cflock name="server.JavaLoader" throwontimeout="true" timeout="60">
<cfscript>
if (not StructKeyExists(server,"svgJavaLoader1_11"))
server.svgJavaLoader1_11 = loadJavaLoader();
return server.svgJavaLoader1_11;
</cfscript>
</cflock>
</cffunction>
<cffunction name="loadJavaLoader" returntype="any" output="false" access="private">
<cfscript>
var q_JarFiles="";
var q_FilePaths="";
var local={};
local.paths = [];
</cfscript>
<cfdirectory action="list" directory="#GetDirectoryFromPath(GetCurrentTemplatePath())#\batik-1.11"
name="q_JarFiles" recurse="true" filter="*.jar">
<cfquery name="q_FilePaths" dbtype="query">
SELECT Directory +'\'+ Name AS FilePath
FROM q_JarFiles
</cfquery>
<cfloop query="q_FilePaths">
<cfscript>
ArrayAppend(local.paths,q_filepaths.filepath);
</cfscript>
</cfloop>
<cfscript>
local.poiJavaLoader=createObject("component", "lib.javaloader.JavaLoader").init(loadPaths=local.paths,
loadColdFusionClassPath=true);
</cfscript>
<cfreturn local.poiJavaLoader>
</cffunction>
<CFfunction name="svgToImage" returntype="any" access="public" output="false">
<cfargument name="svg" type="any" required="true">
<cfargument name="height" type="numeric" required="true" default="0">
<cfargument name="width" type="numeric" required="true" default="0">
<cfscript>
var local={};
local.temp_file=GetTempFile(GetTempDirectory(),"svg");
local.src_svg_file=local.temp_file & ".svg";
local.output_png=local.temp_file & ".png";
local.start=getTickCount();
FileWrite(local.src_svg_file,arguments.svg);
</cfscript>
<cfscript>
local._Thread = createObject("java", "java.lang.Thread");
local.currentClassloader = local._Thread.currentThread().getContextClassLoader();
</cfscript>
<cftry>
<!---set the current thread's context class loader as Javaloader's classloader--->
<cfscript>
local.file=variables.javaloader.create("java.io.File").init(local.src_svg_file).toURL().toString();
local.t_input = variables.javaloader.create("org.apache.batik.transcoder.TranscoderInput").init(local.file);
local.ostream = variables.javaloader.create("java.io.FileOutputStream").init(local.output_png);
local.t_output = variables.javaloader.create("org.apache.batik.transcoder.TranscoderOutput").init(local.ostream);
local._Thread.currentThread().setContextClassLoader(variables.javaloader.getURLClassLoader());
local.PNGTranscoder=variables.javaloader.create("org.apache.batik.transcoder.image.PNGTranscoder").init();
if(arguments.height gt 0)
local.PNGTranscoder.addTranscodingHint(local.PNGTranscoder.KEY_HEIGHT, JavaCast("float", arguments.height));
if(arguments.width gt 0)
local.PNGTranscoder.addTranscodingHint(local.PNGTranscoder.KEY_WIDTH, JavaCast("float", arguments.width));
local.PNGTranscoder.addTranscodingHint(local.PNGTranscoder.KEY_MAX_HEIGHT, JavaCast("float", 1200));
local.PNGTranscoder.addTranscodingHint(local.PNGTranscoder.KEY_MAX_WIDTH, JavaCast("float", 2024));
local.PNGTranscoder.transcode(local.t_input, local.t_output);
// set the classloader back to the original one
local._Thread.currentThread().setContextClassLoader(local.currentClassloader);
</cfscript>
<cfcatch type="Any" >
<!---// set the classloader back to the original one--->
<cfscript>
local._Thread.currentThread().setContextClassLoader(local.currentClassloader);
cleanUpFiles('#local.temp_file#|#local.src_svg_file#|#local.output_png#');
local.ostream.flush();
local.ostream.close();
</cfscript>
<cfrethrow>
</cfcatch>
</cftry>
<cfscript>
local.ostream.flush();
local.ostream.close();
local.time=(getTickCount()-local.start)/1000;
local.png=ImageRead(local.output_png);
</cfscript>
<cflog file="#application.applicationname#" type="information"
text="SVG file produced in #local.time#s, #decimalFormat(FileInfo(local.output_png).size/1024)#Kb from SVG size #decimalformat(len(arguments.svg)/1024)#Kb">
<cfif not IsImage(local.png)>
<cfthrow message="No SVG file Produced">
</cfif>
<cfscript>
cleanUpFiles('#local.temp_file#|#local.src_svg_file#|#local.output_png#');
</cfscript>
<cfreturn local.png>
</CFfunction>
<CFfunction name="cleanUpFiles" returntype="void" access="public" output="false">
<cfargument name="files" type="string" required="true">
<cfscript>
var local={};
</cfscript>
<cfloop list="#arguments.files#" index="local.f" delimiters="|">
<cfif FileExists(local.f)>
<cffile action="delete" file="#local.f#">
</cfif>
</cfloop>
</CFfunction>
</CFcomponent>
Question, inside \batik-1.11 what jar file do you use? In my original download from Apache there are a ton but I only put “batik-all-1.12.jar”. Should I put all jar files in /WEB-INF/lucee/lib/ ? Should I create a folder for them?
I just have the whole distribution extracted in a folder under my own code base, I try and avoid putting anything in the lucee/lib folders… with 1.11 it was 62 files
it makes installing a code base on a server much easier, just checkout the repo… no messing around with other deployment steps required
I usually use JavaLoader too when working with java libraries as it’s more flexible, but you should be able to use CreateObject() directly with the complete batik distro in a folder within your code base as Zac suggests. Just add the path to the distro folder as the third argument:
Batik = CreateObject( "java", "org.apache.batik.transcoder.image.PNGTranscoder", "batik/" ).init();
context: [where object type is “java”] classpath used to load the defined class. This can be a single absolute path, or an array of absolute paths, where paths are jar files or directories containing class files.
So when you say the complete distro I don’t think I understand. Do I unzip the entire download from Apache “batik-bin-1.12.zip” to my directory or just the jar files? Sorry, I really don’t know much about Java.
I would unzip everything to your folder. Lucee will ignore anything it doesn’t need. Just make sure your third argument has the correct folder path to the root of the distro (i.e. the folder containing batik-rasterizer-1.12.jar etc)