How to make a PDF using bookdown including SVG images - svg

I have some R markdown that includes the following code:
```{r huff51, fig.show='hold', fig.cap='Design decisions connecting research purpose and outcomes [#huff_2009_designingresearchpublication p. 86].', echo=FALSE}
knitr::include_graphics('images/Huff-2009-fig5.1.svg')
```
When using bookdown to produce HTML output everything works as expected.
When using bookdown to produce PDF output I get an error saying ! LaTeX Error: Unknown graphics extension: .svg.
This is understandable as knitr uses Latex's \includegraphics{images/Huff-2009-fig5.1.svg} to include the image. So, it's not a bug per se.
Is there a better way to include the SVG image so I don't need to pre-process it into, say, a PDF or PNG?

An update to Yihui Xie 's answer in '22. The package you want is now rsvg and the code looks like:
show_fig <- function(f)
{if (knitr::is_latex_output())
{
output = xfun::with_ext(f, 'pdf')
rsvg::rsvg_pdf(xfun::with_ext(f,'svg'), file=output)
} else {
output = xfun::with_ext(f, 'svg')
}
knitr::include_graphics(output)
}
Then you can add inline code to your text with
`r show_fig("image_file_name_no_extension")`
knitr v 1.39, rsvg v 2.3.1

You can create a helper function to convert SVG to PDF. For example, if you have the system package rsvg-convert installed, you may use this function to include SVG graphics:
include_svg = function(path) {
if (knitr::is_latex_output()) {
output = xfun::with_ext(path, 'pdf')
# you can compare the timestamp of pdf against svg to avoid conversion if necessary
system2('rsvg-convert', c('-f', 'pdf', '-a', '-o', shQuote(c(output, path))))
} else {
output = path
}
knitr::include_graphics(output)
}
You may also consider R packages like magick (which is based on ImageMagick) to convert SVG to PDF.

For bookdown, I really don't like having PDF files on my websites. So I use this code:
if (knitr::is_html_output()) {
structure("images/01-02.svg", class = c("knit_image_paths", "knit_asis"))
} else {
# do something for PDF, e.g. an actual PDF file if you have one,
# or even use Yihui's code in the other answer
knitr::include_graphics("images/01-02.pdf")
}
It uses the SVG file for websites (i.e., HTML output).
It works perfectly for generating everything: website, gitbook, pdfbook and epub.
To prevent adding this code to every chunk in your bookdown project, add this to index.Rmd:
insert_graphic <- function(path, ...) {
if (knitr::is_html_output() && grepl("[.]svg$", basename(path), ignore.case = TRUE)) {
structure(path, class = c("knit_image_paths", "knit_asis"))
} else {
knitr::include_graphics(path, ...)
}
}

Related

Using 'eachWithindex' groovy instead of For loops to read in json data

I'm having trouble with converting an existing FOR loop to use the 'eachWithIndex' groovy function.
I'm not sure how to go about doing this successfully, examples I've seen are quite straightforward on tutorials but I'm not sure how to make them work with groovy json files.
The current solution uses a For loop which reads in data from 3 different groovy files
Add_Page1_data = data.get("json_Page1")
Add_Page2_data = data.get("json_Page2")
Add_Page3_data = data.get("json_Page3")
for (int i=0; i< Add_Page1_data.size(); i++) {
execute(w, Add_Page1_data[i],
Add_Page2_data[i],
Add_Page3_data[i])
}
I then use the following code to populate data inside windows by accessing the page objects of the file before :
def execute(w, data1) {
def page1 = new PO_Add_Page1(wrapper: w)
page1.typeInSomeText(data1.sometext)
}
PageObject file looks like this:
class PO_Add_Page1 {
def typeInSomeText(val) {
wrapper.findWithLabel("Some Text . .").rightEditable().type(val)
}
Json file used contains multiple records like this:
{
"json_Page1": [
{
"sometext": "text1"
},
{
"sometext": "text2"
},
The json is fed in as the "data" which maps to elements on the page using the page object groovy file.
I wanted to be able to repeat the same functionality in a more groovy idiomatic way.
Any help would be much appreciated.

How to implement output cache for a content part (such as a widget)?

I have a widget with list of last news, how to cache only widget output?
OutputCache module caches whole page and for anonymous users, but in fact I need to cache only one shape output.
What solution can be here?
It's not a good idea to cache the Shape object itself, but you can capture the HTML output from a Shape and cache that.
Every Orchard Shape has a corresponding object called the Metadata. This object contains, among other things, some event handlers that can run when the Shape is displaying or after it has been displayed. By using these event handlers, it is possible to cache the output of the Shape on the first call to a driver. Then for future calls to the driver, we can display the cached copy of the output instead of running through the expensive parts of the driver or template rendering.
Example:
using System.Web;
using DemoModule.Models;
using Orchard.Caching;
using Orchard.ContentManagement.Drivers;
using Orchard.DisplayManagement.Shapes;
namespace DemoModule.Drivers {
public class MyWidgetPartDriver : ContentPartDriver<MyWidgetPart> {
private readonly ICacheManager _cacheManager;
private readonly ISignals _signals;
public MyWidgetPartDriver(
ICacheManager cacheManager,
ISignals signals
) {
_cacheManager = cacheManager;
_signals = signals;
}
public class CachedOutput {
public IHtmlString Output { get; set; }
}
protected override DriverResult Display(MyWidgetPart part, string displayType, dynamic shapeHelper) {
return ContentShape("Parts_MyWidget", () => {
// The cache key. Build it using whatever is needed to differentiate the output.
var cacheKey = /* e.g. */ string.Format("MyWidget-{0}", part.Id);
// Standard Orchard cache manager. Notice we get this object by reference,
// so we can write to its field to save our cached HTML output.
var cachedOutput = _cacheManager.Get(cacheKey, ctx => {
// Use whatever signals are needed to invalidate the cache.
_signals.When(/* e.g. */ "ExpireCache");
return new CachedOutput();
});
dynamic shape;
if (cachedOutput.Output == null) {
// Output has not yet been cached, so we are going to build the shape normally
// and then cache the output.
/*
... Do normal (potentially expensive) things (call DBs, call services, etc.)
to prep shape ...
*/
// Create shape object.
shape = shapeHelper.Parts_MyWidget(/*...*/);
// Hook up an event handler such that after rendering the (potentially expensive)
// shape template, we capture the output to the cached output object.
((ShapeMetadata) shape.Metadata).OnDisplayed(displayed => cachedOutput.Output = displayed.ChildContent);
} else {
// Found cached output, so simply output it instead of building
// the shape normally.
// This is a dummy shape, the name doesn't matter.
shape = shapeHelper.CachedShape();
// Hook up an event handler to fill the output of this shape with the cached output.
((ShapeMetadata)shape.Metadata).OnDisplaying(displaying => displaying.ChildContent = cachedOutput.Output);
// Replacing the ChildContent of the displaying context will cause the display manager
// to simply use that HTML output and skip template rendering.
}
return shape;
});
}
}
}
EDIT:
Note that this only caches the HTML that is generated from your shape output. Things like Script.Require(), Capture(), and other side effects that you perform in your shape templates will not be played back. This actually bit me because I tried to cache a template that required its own stylesheet, but the stylesheets would only be brought in the first time.
Orchard supplies a service called the CacheManager, which is awesome and cool and makes caching super easy. It is mentioned in the docs, but it isn't a particularly helpful description of how to use it (http://docs.orchardproject.net/Documentation/Caching). Best place to see examples would be in the Orchard core code and third party modules such as Favicon and the twitter widgets (all of them one would hope).
Luckily other nice people have gone to the effort of searching orchards code for you and writing nice little blog posts about it. The developer of the LatestTwitter widget wrote a neat post: http://blog.maartenballiauw.be/post/2011/01/21/Writing-an-Orchard-widget-LatestTwitter.aspx . So did Richard of NogginBox: http://www.nogginbox.co.uk/blog/orchard-caching-by-time . And of course Bertrand has a helpful post on the subject as well: http://weblogs.asp.net/bleroy/archive/2011/02/16/caching-items-in-orchard.aspx

Can groovy heredocs be internationalized?

Have some multiline strings that are presented to the user and stored as Heredocs. So rather than a 'normal' (Java) property file, a groovy-based one (see here) to be consumed by ConfigSlurper was used and works great. Sorry if this is a dumb question, but can that be easily internationalized? If so, can you outline how that is accomplished?
My solution: In your ConfigSlurper you should store keys to the internalized strings. Inject messageSourceand localResolver in your controller/service, get key from your ConfigSlurper and find localized string in your i18n messages.property file. Example (not sure that code is correct, but it's the main idea):
def config = new ConfigSlurper().parse(new File('src/Config.groovy').toURL())
//localized string1 value
def msg = messageSource.getMessage(config.data1.string1, null, localeResolver.defaultLocale)
As far as I know the ConfigSlurper does not have special support for i18n.
You may achieve it by using the leveraging its support for environments by creating an environment closure per locale. For example:
environments {
english {
sample {
hello = "hello"
}
}
spanish {
sample {
hello = "hola"
}
}
}
When creating the ConfigSlurper you will need to pass the desired language:
def config = new ConfigSlurper("spanish")

groovy parse local html file

I am working on a groovy script that will get all the local html files and parse certain tags in them. I tried using something like html clean and it just is not working. I tried to read each line but that only works when the stuff I need is on 1 line. I have this script up on github, https://github.com/jrock2004/johns-octopress-scripts/blob/master/convertCompiledPosts/convertPosts.groovy. Thanks for any input
Edit: So I am getting closer. I have this code now
def parser = new org.cyberneko.html.parsers.SAXParser()
new XmlParser( parser ).parse( curFile+ "/index.html" ).with { page ->
page.'**'.DIV.grep { it.'#class'?.contains 'entry-content' }.each {
println it
println "--------------------------------"
}
}
And what it prints is
DIV[attributes={class=entry-content}; value=[P[attributes={}; value=[As an automation developer, I have learned how to write code in Java. When I am having an issue, one of the nice things that you can do is debug your code, line by line. For the longest I had wished that something like this existed in PHP. I have come to find out that you can actually debug code, like I do in Java. This is such a helpful task because I do not have to waste time using var_dump and such on variables or results. In your apache/php server you need to install and or enable something called, A[attributes={href=http://xdebug.org/}; value=[Xdebug]], . I will work on a tutorial on how to use xdebug while writing code in Sublime Text 2. So keep an eye out on my blog and or, A[attributes={href=http://www.youtube.com/jrock20041}; value=[YouTube]], channel for this tutorial.]]]]
So basically what I want is I wall the text including the html elements in the div with the class entry-content. If you want to see the page it can be found here -- http://jcwebconcepts.net/blog/2013/02/02/xdebug/
Thanks for your help
It does work... Save the HTML for this page to a file, then you can parse it.
The following code prints the name of the author of every comment on the page:
#Grab('net.sourceforge.nekohtml:nekohtml:1.9.16')
def parser = new org.cyberneko.html.parsers.SAXParser()
new XmlParser( parser ).parse( file ).with { page ->
page.'**'.A.grep { it.'#class'?.contains 'comment-user' }.each {
println it.text()
}
}
When file is set to be a File pointing to the saved HTML (or a String containing the URL of this question), it prints:
tim_yates
jrock2004
tim_yates
Edit:
To print the contents of a given node, you could do (using the example from your edited question):
#Grab('net.sourceforge.nekohtml:nekohtml:1.9.16')
import groovy.xml.*
def parser = new org.cyberneko.html.parsers.SAXParser()
new XmlParser( parser ).parse( 'http://jcwebconcepts.net/blog/2013/02/02/xdebug/' ).with { page ->
page.'**'.DIV.grep { it.'#class'?.contains 'entry-content' }.each { it ->
println XmlUtil.serialize( it )
}
}

Check a file already exists in Save As Dialog box - c++, opencascade

I want to create a .stl file for a particular shape where each face of that shape has a different patch name like face1,face 2 etc. I have done this by overriding the StlAPI_Writer and RWStl classes in opencascade. I have used file.Append method instead of file.Build method to do so.
But I have a problem when I save the .stl file in an already existing file, it appends data to the existing one which is incorrect. I want to delete the existing data in the file and append new data face by face for a given shape.
Please help me on this.
You can use this simple function:
#include <sys/stat.h>
#include <string>
using namespace std;
bool FileExists(string strFilename) {
struct stat stFileInfo;
bool blnReturn;
int intStat;
// Attempt to get the file attributes
intStat = stat(strFilename.c_str(),&stFileInfo);
if(intStat == 0) {
// We were able to get the file attributes
// so the file obviously exists.
blnReturn = true;
} else {
// We were not able to get the file attributes.
// This may mean that we don't have permission to
// access the folder which contains this file. If you
// need to do that level of checking, lookup the
// return values of stat which will give you
// more details on why stat failed.
blnReturn = false;
}
return(blnReturn);
}
I assume you use the SaveFileDialogue class. In this case you can handle the return result of the dialogue like this:
if ( saveFileDialog.ShowDialog() == ::DialogResult::OK ) {
if ( FileExist(saveFileDialog.FileName) ) {
// erase the file
}
// write the code using the Append function
}
This should work, however a easier variant must be accessible if you use something else than Append (something like Write or maybe even Append but with a parameter that specifies to rewrite the file)
HTH, JP

Resources