diff --git a/project/build.properties b/project/build.properties index 27e88aa..b7dd3cb 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.13 +sbt.version=1.0.2 diff --git a/project/plugins.sbt b/project/plugins.sbt index 31ea0e8..107e847 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,5 +1,5 @@ -addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "1.1") +addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "2.0") -addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") +addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.0") -addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.3") +addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.6") diff --git a/src/main/scala/io/github/cloudify/scala.spdf/Image.scala b/src/main/scala/io/github/cloudify/scala.spdf/Image.scala new file mode 100644 index 0000000..ab9635c --- /dev/null +++ b/src/main/scala/io/github/cloudify/scala.spdf/Image.scala @@ -0,0 +1,65 @@ +package io.github.cloudify.scala.spdf + +import scala.sys.process._ +import java.io.File + +class Image(executablePath: String, config: ImageConfig) { + validateExecutable_!(executablePath) + + /** + * Runs the conversion tool to convert sourceDocument HTML into + * destinationDocument image. + */ + def run[A, B](sourceDocument: A, destinationDocument: B)(implicit sourceDocumentLike: SourceDocumentLike[A], destinationDocumentLike: DestinationDocumentLike[B]): Int = { + val commandLine = toCommandLine(sourceDocument, destinationDocument) + val process = Process(commandLine) + def source = sourceDocumentLike.sourceFrom(sourceDocument) _ + def sink = destinationDocumentLike.sinkTo(destinationDocument) _ + + (sink compose source)(process).! + } + + /** + * Generates the command line needed to execute `wkhtmltoimage` + */ + private def toCommandLine[A: SourceDocumentLike, B: DestinationDocumentLike](source: A, destination: B): Seq[String] = + Seq(executablePath) ++ + ImageConfig.toParameters(config) ++ + Seq( + "--quiet", + implicitly[SourceDocumentLike[A]].commandParameter(source), + implicitly[DestinationDocumentLike[B]].commandParameter(destination) + ) + + /** + * Check whether the executable is actually executable, if it isn't + * a NoExecutableException is thrown. + */ + private def validateExecutable_!(executablePath: String): Unit = { + val executableFile = new File(executablePath) + if(!executableFile.canExecute) throw new NoExecutableException(executableFile.getAbsolutePath) + } + +} + +object Image { + + /** + * Creates a new instance of Image with default configuration + * @return + */ + def apply(config: ImageConfig): Image = { + val executablePath: String = ImageConfig.findExecutable.getOrElse { + throw new NoExecutableException(System.getenv("PATH")) + } + + apply(executablePath, config) + } + + /** + * Creates a new instance of Image with the passed configuration + */ + def apply(executablePath: String, config: ImageConfig): Image = + new Image(executablePath, config) + +} diff --git a/src/main/scala/io/github/cloudify/scala.spdf/ImageConfig.scala b/src/main/scala/io/github/cloudify/scala.spdf/ImageConfig.scala new file mode 100644 index 0000000..bd32069 --- /dev/null +++ b/src/main/scala/io/github/cloudify/scala.spdf/ImageConfig.scala @@ -0,0 +1,187 @@ +package io.github.cloudify.scala.spdf + +import scala.sys.process._ + +/** + * Holds the configuration parameters of Pdf Kit + */ +trait ImageConfig { + + /** + * Options for `wkhtmltoimage` command + * See `wkhtmltoimage --extended-help` for a description of each option + */ + + val allow = Parameter[Iterable[String]]("allow") + + val bypassProxy = Parameter[Iterable[String]]("bypass-proxy-for") + + val cacheDir = Parameter[String]("cache-dir") + + val checkboxCheckedSvg = Parameter[String]("checkbox-checked-svg") + + val checkboxSvg = Parameter[String]("checkbox-svg") + + val cookie = Parameter[Iterable[String]]("cookie") + + val cookieJar = Parameter[String]("cookieJar") + + val cropH = Parameter[Int]("crop-h") + + val cropW = Parameter[Int]("crop-w") + + val cropX = Parameter[Int]("crop-x") + + val cropY = Parameter[Int]("crop-y") + + val customHeader = Parameter[Iterable[String]]("custom-header") + + val customHeaderPropagation = Parameter[Boolean]("custom-header-propagation") + + val noCustomHeaderPropagation = Parameter[Boolean]("no-custom-header-propagation") + + val debugJavascript = Parameter[Boolean]("debug-javascript") + + val noDebugJavascript = Parameter[Boolean]("no-debug-javascript") + + val encoding = Parameter[String]("encoding") + + val format = Parameter[String]("format") + + val height = Parameter[Int]("height") + + val images = Parameter[Boolean]("images") + + val noImages = Parameter[Boolean]("no-images") + + val disableJavascript = Parameter[Boolean]("disable-javascript") + + val enableJavascript = Parameter[Boolean]("enable-javascript") + + val javascriptDelay = Parameter[Int]("javascript-delay") + + val loadErrorHandling = Parameter[String]("load-error-handling") + + val loadMediaErrorHandling = Parameter[String]("load-media-error-handling") + + val disableLocalFileAccess = Parameter[Boolean]("disable-local-file-access") + + val enableLocalFileAccess = Parameter[Boolean]("enable-local-file-access") + + val minimumFontSize = Parameter[Int]("minimum-font-size") + + val password = Parameter[String]("password") + + val disablePlugins = Parameter[Boolean]("disable-plugins") + + val enablePlugins = Parameter[Boolean]("enable-plugins") + + val post = Parameter[Iterable[String]]("post") + + val postFile = Parameter[String]("post-file") + + val proxy = Parameter[String]("proxy") + + val quality = Parameter[Int]("quality") + + val quiet = Parameter[Boolean]("quiet") + + val radioButtonCheckedSvg = Parameter[String]("radiobuttion-checked-svg") + + val radioButtonSvg = Parameter[String]("radiobuttion-svg") + + val runScript = Parameter[String]("run-script") + + val stopSlowScripts = Parameter[Boolean]("stop-slow-scripts") + + val noStopSlowScripts = Parameter[Boolean]("no-stop-slow-scripts") + + val userStyleSheet = Parameter[String]("user-style-sheet") + + val username = Parameter[String]("username") + + val width = Parameter[Int]("width") + + val windowStatus = Parameter[String]("window-status") + + val zoom = Parameter[Float]("zoom") + +} + +object ImageConfig { + + /** + * An instance of the default configuration + */ + object default extends ImageConfig + + /** + * Generates a sequence of command line parameters from a `PdfKitConfig` + */ + def toParameters(config: ImageConfig): Seq[String] = { + import config._ + Seq( + allow.toParameter, + bypassProxy.toParameter, + cacheDir.toParameter, + checkboxCheckedSvg.toParameter, + checkboxSvg.toParameter, + cookie.toParameter, + cookieJar.toParameter, + cropH.toParameter, + cropW.toParameter, + cropX.toParameter, + cropY.toParameter, + customHeader.toParameter, + customHeaderPropagation.toParameter, + noCustomHeaderPropagation.toParameter, + debugJavascript.toParameter, + noDebugJavascript.toParameter, + encoding.toParameter, + format.toParameter, + height.toParameter, + images.toParameter, + noImages.toParameter, + disableJavascript.toParameter, + enableJavascript.toParameter, + javascriptDelay.toParameter, + loadErrorHandling.toParameter, + loadMediaErrorHandling.toParameter, + disableLocalFileAccess.toParameter, + enableLocalFileAccess.toParameter, + minimumFontSize.toParameter, + password.toParameter, + disablePlugins.toParameter, + enablePlugins.toParameter, + post.toParameter, + postFile.toParameter, + proxy.toParameter, + quality.toParameter, + quiet.toParameter, + radioButtonCheckedSvg.toParameter, + radioButtonSvg.toParameter, + runScript.toParameter, + stopSlowScripts.toParameter, + noStopSlowScripts.toParameter, + userStyleSheet.toParameter, + username.toParameter, + width.toParameter, + windowStatus.toParameter, + zoom.toParameter + ).flatten + } + + /** + * Attempts to find the `wkhtmltoimage` executable in the system path. + * @return + */ + def findExecutable: Option[String] = try { + val os = System.getProperty("os.name").toLowerCase + val cmd = if(os.contains("windows")) "where wkhtmltoimage" else "which wkhtmltoimage" + + Option(cmd.!!.trim).filter(_.nonEmpty) + } catch { + case _: RuntimeException => None + } + +} diff --git a/src/main/scala/io/github/cloudify/scala.spdf/ParamShow.scala b/src/main/scala/io/github/cloudify/scala.spdf/ParamShow.scala index 1109695..7d496e1 100644 --- a/src/main/scala/io/github/cloudify/scala.spdf/ParamShow.scala +++ b/src/main/scala/io/github/cloudify/scala.spdf/ParamShow.scala @@ -1,5 +1,8 @@ package io.github.cloudify.scala.spdf +import java.text.{DecimalFormat, DecimalFormatSymbols} +import java.util.{Formatter, Locale} + /** * Renders a parameter of type T to a sequence of strings that will be * appended to the command line. @@ -39,8 +42,11 @@ object ParamShow { } implicit object FloatParamShow extends ParamShow[Float] { + val dformat: DecimalFormatSymbols = DecimalFormatSymbols.getInstance() + dformat.setDecimalSeparator('.') + override def show(name: String, value: Float): Iterable[String] = - formatParam(name, Some("%.2f".format(value))) + formatParam(name, Some(new DecimalFormat("0.00", dformat).format(value))) } implicit object PageOrientationParamShow extends ParamShow[PageOrientation] { diff --git a/src/main/scala/io/github/cloudify/scala.spdf/PdfConfig.scala b/src/main/scala/io/github/cloudify/scala.spdf/PdfConfig.scala index 3912655..f4faf89 100644 --- a/src/main/scala/io/github/cloudify/scala.spdf/PdfConfig.scala +++ b/src/main/scala/io/github/cloudify/scala.spdf/PdfConfig.scala @@ -13,151 +13,271 @@ trait PdfConfig { * See `wkhtmltopdf --extended-help` for a description of each option */ + val collate = Parameter[Boolean]("collate") + + val noCollate = Parameter[Boolean]("no-collate") + + val cookieJar = Parameter[String]("cookie-jar") + + val copies = Parameter[Int]("copies") + + val dpi = Parameter[Int]("dpi") + + val grayScale = Parameter[Boolean]("grayscale") + + val lowQuality = Parameter[Boolean]("lowquality") + + val marginBottom = Parameter[String]("margin-bottom") + + val marginLeft = Parameter[String]("margin-left") + + val marginRight = Parameter[String]("margin-right") + + val marginTop = Parameter[String]("margin-top") + + val orientation = Parameter[PageOrientation]("orientation") + + val pageHeight = Parameter[String]("page-height") + + val pageWidth = Parameter[String]("page-width") + + val title = Parameter[String]("title") + val allow = Parameter[Iterable[String]]("allow") - val defaultHeader = Parameter[Boolean]("default-header") + val background = Parameter[Boolean]("background") - val disableExternalLinks = Parameter[Boolean]("disable-external-links") + val noBackground = Parameter[Boolean]("no-background") - val disableInternalLinks = Parameter[Boolean]("disable-internal-links") + val bypassProxyFor = Parameter[Iterable[String]]("bypass-proxy-for") - val disableJavascript = Parameter[Boolean]("disable-javascript") + val cacheDir = Parameter[String]("cache-dir") - @deprecated("Use noPdfCompression instead", "1.3.1") - val disablePdfCompression = Parameter[Boolean]("disable-pdf-compression") + val checkboxCheckedSvg = Parameter[String]("checkbox-checked-svg") - val noPdfCompression = Parameter[Boolean]("no-pdf-compression") + val checkboxSvg = Parameter[String]("checkbox-svg") - val disableSmartShrinking = Parameter[Boolean]("disable-smart-shrinking") + val cookie = Parameter[Iterable[String]]("cookie") - val javascriptDelay = Parameter[Int]("javascript-delay") + val customHeader = Parameter[Iterable[String]]("custom-header") - val enableForms = Parameter[Boolean]("enable-forms") + val customHeaderPropagation = Parameter[Boolean]("custom-header-propagation") - val encoding = Parameter[String]("encoding", "UTF-8") + val noCustomHeaderPropagation = Parameter[Boolean]("no-custom-header-propagation") - val grayScale = Parameter[Boolean]("grayscale") + val debugJavascript = Parameter[Boolean]("debug-javascript") - val lowQuality = Parameter[Boolean]("lowquality") + val noDebugJavascript = Parameter[Boolean]("no-debug-javascript") - val marginBottom = Parameter[String]("margin-bottom") + val encoding = Parameter[String]("encoding") - val marginLeft = Parameter[String]("margin-left") + val images = Parameter[Boolean]("images") - val marginRight = Parameter[String]("margin-right") + val noImages = Parameter[Boolean]("no-images") - val marginTop = Parameter[String]("margin-top") + val disableJavascript = Parameter[Boolean]("disable-javascript") + + val enableJavascript = Parameter[Boolean]("enable-javascript") + + val javascriptDelay = Parameter[Int]("javascript-delay") + + val loadErrorHandling = Parameter[String]("load-error-handling") + + val loadMediaErrorHandling = Parameter[String]("load-media-error-handling") + + val disableLocalFileAccess = Parameter[Boolean]("disable-local-file-access") + + val enableLocalFileAccess = Parameter[Boolean]("enable-local-file-access") val minimumFontSize = Parameter[Int]("minimum-font-size") - val background = Parameter[Option[Boolean]]("background") + val pageOffset = Parameter[Int]("page-offset") - val orientation = Parameter[PageOrientation]("orientation") + val password = Parameter[String]("password") - val pageHeight = Parameter[String]("page-height") + val disablePlugins = Parameter[Boolean]("disable-plugins") - val pageOffset = Parameter[String]("page-offset") + val enablePlugins = Parameter[Boolean]("enable-plugins") - val pageSize = Parameter[String]("page-size") + val post = Parameter[Iterable[String]]("post") - val pageWidth = Parameter[String]("page-width") + val postFile = Parameter[String]("post-file") - val title = Parameter[String]("title") + val proxy = Parameter[String]("proxy") - val tableOfContent = Parameter[Boolean]("toc") + val radioButtonCheckedSvg = Parameter[String]("radiobuttion-checked-svg") + + val radioButtonSvg = Parameter[String]("radiobuttion-svg") + + val runScript = Parameter[String]("run-script") + + val stopSlowScripts = Parameter[Boolean]("stop-slow-scripts") + + val noStopSlowScripts = Parameter[Boolean]("no-stop-slow-scripts") + + val userStyleSheet = Parameter[String]("user-style-sheet") + + val username = Parameter[String]("username") + + val windowStatus = Parameter[String]("window-status") val zoom = Parameter[Float]("zoom") + // Only deprecated options from here on + @deprecated("No longer in use", "1.4.1") + val defaultHeader = Parameter[Boolean]("default-header") + + @deprecated("No longer in use", "1.4.1") + val disableExternalLinks = Parameter[Boolean]("disable-external-links") + + @deprecated("No longer in use", "1.4.1") + val disableInternalLinks = Parameter[Boolean]("disable-internal-links") + + @deprecated("Use noPdfCompression instead", "1.3.1") + val disablePdfCompression = Parameter[Boolean]("disable-pdf-compression") + + @deprecated("No longer in use", "1.4.1") + val noPdfCompression = Parameter[Boolean]("no-pdf-compression") + + @deprecated("No longer in use", "1.4.1") + val disableSmartShrinking = Parameter[Boolean]("disable-smart-shrinking") + + @deprecated("No longer in use", "1.4.1") + val enableForms = Parameter[Boolean]("enable-forms") + + @deprecated("No longer in use", "1.4.1") + val pageSize = Parameter[String]("page-size") + + @deprecated("No longer in use", "1.4.1") + val tableOfContent = Parameter[Boolean]("toc") + + @deprecated("No longer in use", "1.4.1") val footerCenter = Parameter[String]("footer-center") + @deprecated("No longer in use", "1.4.1") val footerFontName = Parameter[String]("footer-font-name") + @deprecated("No longer in use", "1.4.1") val footerFontSize = Parameter[String]("footer-font-size") + @deprecated("No longer in use", "1.4.1") val footerHtml = Parameter[String]("footer-html") + @deprecated("No longer in use", "1.4.1") val footerLeft = Parameter[String]("footer-left") + @deprecated("No longer in use", "1.4.1") val footerLine = Parameter[Boolean]("footer-line") + @deprecated("No longer in use", "1.4.1") val footerRight = Parameter[String]("footer-right") + @deprecated("No longer in use", "1.4.1") val footerSpacing = Parameter[Float]("footer-spacing") + @deprecated("No longer in use", "1.4.1") val headerCenter = Parameter[String]("header-center") + @deprecated("No longer in use", "1.4.1") val headerFontName = Parameter[String]("header-font-name") + @deprecated("No longer in use", "1.4.1") val headerFontSize = Parameter[String]("header-font-size") + @deprecated("No longer in use", "1.4.1") val headerHtml = Parameter[String]("header-html") + @deprecated("No longer in use", "1.4.1") val headerLeft = Parameter[String]("header-left") + @deprecated("No longer in use", "1.4.1") val headerLine = Parameter[Option[Boolean]]("header-line") + @deprecated("No longer in use", "1.4.1") val headerRight = Parameter[String]("header-right") + @deprecated("No longer in use", "1.4.1") val headerSpacing = Parameter[Float]("header-spacing") + @deprecated("No longer in use", "1.4.1") val tableOfContentDepth = Parameter[Int]("toc-depth") + @deprecated("No longer in use", "1.4.1") val tableOfContentDisableBackLinks = Parameter[Boolean]("toc-disable-back-links") + @deprecated("No longer in use", "1.4.1") val tableOfContentDisableLinks = Parameter[Boolean]("toc-disable-links") + @deprecated("No longer in use", "1.4.1") val tableOfContentFontName = Parameter[String]("toc-font-name") + @deprecated("No longer in use", "1.4.1") val tableOfContentHeaderFontName = Parameter[String]("toc-header-font-name") + @deprecated("No longer in use", "1.4.1") val tableOfContentHeaderFontSize = Parameter[Int]("toc-header-font-size") + @deprecated("No longer in use", "1.4.1") val tableOfContentHeaderText = Parameter[String]("toc-header-text") + @deprecated("No longer in use", "1.4.1") val tableOfContentLevel1FontSize = Parameter[Int]("toc-l1-font-size") + @deprecated("No longer in use", "1.4.1") val tableOfContentLevel1Indentation = Parameter[Int]("toc-l1-indentation") + @deprecated("No longer in use", "1.4.1") val tableOfContentLevel2FontSize = Parameter[Int]("toc-l2-font-size") + @deprecated("No longer in use", "1.4.1") val tableOfContentLevel2Indentation = Parameter[Int]("toc-l2-indentation") + @deprecated("No longer in use", "1.4.1") val tableOfContentLevel3FontSize = Parameter[Int]("toc-l3-font-size") + @deprecated("No longer in use", "1.4.1") val tableOfContentLevel3Indentation = Parameter[Int]("toc-l3-indentation") + @deprecated("No longer in use", "1.4.1") val tableOfContentLevel4FontSize = Parameter[Int]("toc-l4-font-size") + @deprecated("No longer in use", "1.4.1") val tableOfContentLevel4Indentation = Parameter[Int]("toc-l4-indentation") + @deprecated("No longer in use", "1.4.1") val tableOfContentLevel5FontSize = Parameter[Int]("toc-l5-font-size") + @deprecated("No longer in use", "1.4.1") val tableOfContentLevel5Indentation = Parameter[Int]("toc-l5-indentation") + @deprecated("No longer in use", "1.4.1") val tableOfContentLevel6FontSize = Parameter[Int]("toc-l6-font-size") + @deprecated("No longer in use", "1.4.1") val tableOfContentLevel6Indentation = Parameter[Int]("toc-l6-indentation") + @deprecated("No longer in use", "1.4.1") val tableOfContentLevel7FontSize = Parameter[Int]("toc-l7-font-size") + @deprecated("No longer in use", "1.4.1") val tableOfContentLevel7Indentation = Parameter[Int]("toc-l7-indentation") + @deprecated("No longer in use", "1.4.1") val tableOfContentNoDots = Parameter[Boolean]("toc-no-dots") + @deprecated("No longer in use", "1.4.1") val outline = Parameter[Option[Boolean]]("outline") + @deprecated("No longer in use", "1.4.1") val outlineDepth = Parameter[Int]("outline-depth") + @deprecated("No longer in use", "1.4.1") val printMediaType = Parameter[Option[Boolean]]("print-media-type") - val userStyleSheet = Parameter[String]("user-style-sheet") - - val username = Parameter[String]("username") - - val password = Parameter[String]("password") - + @deprecated("No longer in use", "1.4.1") val viewportSize = Parameter[String]("viewport-size") + @deprecated("No longer in use", "1.4.1") val useXServer = Parameter[Boolean]("use-xserver") } @@ -176,75 +296,58 @@ object PdfConfig { Seq( allow.toParameter, background.toParameter, - defaultHeader.toParameter, - disableExternalLinks.toParameter, - disableInternalLinks.toParameter, + bypassProxyFor.toParameter, + cacheDir.toParameter, + checkboxCheckedSvg.toParameter, + checkboxSvg.toParameter, + collate.toParameter, + cookie.toParameter, + cookieJar.toParameter, + copies.toParameter, + customHeader.toParameter, + customHeaderPropagation.toParameter, + debugJavascript.toParameter, disableJavascript.toParameter, - noPdfCompression.toParameter, - disableSmartShrinking.toParameter, - javascriptDelay.toParameter, - enableForms.toParameter, + disableLocalFileAccess.toParameter, + disablePlugins.toParameter, + dpi.toParameter, + enableJavascript.toParameter, + enableLocalFileAccess.toParameter, + enablePlugins.toParameter, encoding.toParameter, - footerCenter.toParameter, - footerFontName.toParameter, - footerFontSize.toParameter, - footerHtml.toParameter, - footerLeft.toParameter, - footerLine.toParameter, - footerRight.toParameter, - footerSpacing.toParameter, grayScale.toParameter, - headerCenter.toParameter, - headerFontName.toParameter, - headerFontSize.toParameter, - headerHtml.toParameter, - headerLeft.toParameter, - headerLine.toParameter, - headerRight.toParameter, - headerSpacing.toParameter, + images.toParameter, + javascriptDelay.toParameter, + loadErrorHandling.toParameter, + loadMediaErrorHandling.toParameter, lowQuality.toParameter, marginBottom.toParameter, marginLeft.toParameter, marginRight.toParameter, marginTop.toParameter, minimumFontSize.toParameter, + noBackground.toParameter, + noCollate.toParameter, + noCustomHeaderPropagation.toParameter, + noDebugJavascript.toParameter, + noImages.toParameter, + noStopSlowScripts.toParameter, orientation.toParameter, - outline.toParameter, - outlineDepth.toParameter, pageHeight.toParameter, pageOffset.toParameter, - pageSize.toParameter, pageWidth.toParameter, password.toParameter, - printMediaType.toParameter, - tableOfContent.toParameter, - tableOfContentDepth.toParameter, - tableOfContentDisableBackLinks.toParameter, - tableOfContentDisableLinks.toParameter, - tableOfContentFontName.toParameter, - tableOfContentHeaderFontName.toParameter, - tableOfContentHeaderFontSize.toParameter, - tableOfContentHeaderText.toParameter, - tableOfContentLevel1FontSize.toParameter, - tableOfContentLevel1Indentation.toParameter, - tableOfContentLevel2FontSize.toParameter, - tableOfContentLevel2Indentation.toParameter, - tableOfContentLevel3FontSize.toParameter, - tableOfContentLevel3Indentation.toParameter, - tableOfContentLevel4FontSize.toParameter, - tableOfContentLevel4Indentation.toParameter, - tableOfContentLevel5FontSize.toParameter, - tableOfContentLevel5Indentation.toParameter, - tableOfContentLevel6FontSize.toParameter, - tableOfContentLevel6Indentation.toParameter, - tableOfContentLevel7FontSize.toParameter, - tableOfContentLevel7Indentation.toParameter, - tableOfContentNoDots.toParameter, + post.toParameter, + postFile.toParameter, + proxy.toParameter, + radioButtonCheckedSvg.toParameter, + radioButtonSvg.toParameter, + runScript.toParameter, + stopSlowScripts.toParameter, title.toParameter, userStyleSheet.toParameter, username.toParameter, - useXServer.toParameter, - viewportSize.toParameter, + windowStatus.toParameter, zoom.toParameter ).flatten } diff --git a/src/test/scala/io/github/cloudify/scala/spdf/ImageSpec.scala b/src/test/scala/io/github/cloudify/scala/spdf/ImageSpec.scala new file mode 100644 index 0000000..9b170c2 --- /dev/null +++ b/src/test/scala/io/github/cloudify/scala/spdf/ImageSpec.scala @@ -0,0 +1,51 @@ +package io.github.cloudify.scala.spdf + +import java.io.File +import scala.sys.process._ +import org.scalatest.Matchers +import org.scalatest.WordSpec + +class ImageSpec extends WordSpec with Matchers { + + "An Image" should { + + "require the executionPath config" in { + val file = new File("notexecutable") + val filePath = file.getAbsolutePath + + assertThrows[NoExecutableException] { + new Image(filePath, ImageConfig.default) + } + + assertThrows[NoExecutableException] { + Image(filePath, ImageConfig.default) + } + + } + + PdfConfig.findExecutable match { + case Some(_) => + "generate an image file from an HTML string" in { + + val page = + """ + |

Hello

+ """.stripMargin + + val file = File.createTempFile("scala.spdf", "pdf") + + val image = Image(ImageConfig.default) + + image.run(page, file) + + Seq("file", file.getAbsolutePath).!! should include("PDF document") + } + + case None => + "Skipping test, missing wkhtmltopdf binary" in { true should equal(true) } + } + + + } + +} diff --git a/src/test/scala/io/github/cloudify/scala/spdf/ParamShowSpec.scala b/src/test/scala/io/github/cloudify/scala/spdf/ParamShowSpec.scala index e0e209e..002350e 100644 --- a/src/test/scala/io/github/cloudify/scala/spdf/ParamShowSpec.scala +++ b/src/test/scala/io/github/cloudify/scala/spdf/ParamShowSpec.scala @@ -1,6 +1,6 @@ package io.github.cloudify.scala.spdf -import io.github.cloudify.scala.spdf.ParamShow.{BooleanParamShow, StringParamShow, IterableParamShow} +import io.github.cloudify.scala.spdf.ParamShow.{BooleanParamShow, FloatParamShow, IterableParamShow, StringParamShow} import org.scalatest.WordSpec import org.scalatest.Matchers @@ -34,4 +34,12 @@ class ParamShowSpec extends WordSpec with Matchers { } + "FloatParamShow" should { + + "represent a properly formatted float parameter" in { + FloatParamShow.show("zoom", 0.2f) should equal(Seq("--zoom", "0.20")) + } + + } + }