I have successfully imported the nodes by importing it from a json file. However, it doesn't work because I try to modify(transform,remove) the nodes I brought. What should I do?
Here is code. Thank you!
function setFile() {
const files = document.querySelector('.selectFile').files;
if (files.length <= 0) {
return false;
}
const fr = new FileReader();
fr.onload = function(e) {
const result = JSON.parse(e.target.result);
const formatted = JSON.stringify(result, null, 2);
console.log(formatted)
layer.destroyChildren();
stage = Konva.Node.create(formatted, 'container');
stage.draw()
}
fr.readAsText(files.item(0))
}
Codepen
I think you missed adding layer to the stage
Related
I've got a huge PDF file with more than 100 pages and I want to separate them to single PDF files (containing only one page each). Problem is, that PoDoFo does not copy just the page, but the whole document because of the references (and so each of the 100 PDF files have same size as the 100-page PDF). A relevant mailing list post can be found, unfortunately there is no solution provided.
In source code of function InsertPages there is explanation:
This function works a bit different than one might expect.
Rather than copying one page at a time - we copy the ENTIRE document
and then delete the pages we aren't interested in.
We do this because
1) SIGNIFICANTLY simplifies the process
2) Guarantees that shared objects aren't copied multiple times
3) offers MUCH faster performance for the common cases
HOWEVER: because PoDoFo doesn't currently do any sort of "object
garbage collection" during a Write() - we will end up with larger
documents, since the data from unused pages will also be in there.
I have tried few methods to copy only relevant objects, but each of them failed.
Copy all pages and remove irrelevant ones
Use XObject wrapping: FillXObjectFromDocumentPage and FillXObjectFromExistingPage
Copy object by object
Use RenumberObjects with bDoGarbageCollection = true
but none of them worked out. Does anybody have an idea or working solution for this problem?
The only solution is to use another PDF library. Or wait for garbage collection to be implemented.
The problem is stated in the quote you mentioned:
> during a Write() - we will end up with larger documents, since the
> data from unused pages will also be in there.
This means podofo always puts the entire PDF content in your file, no matter what. The whole PDF is there, you just don't see parts of it.
Dennis from the podofo support sent me an working example of optimized version of InsertPages function which is actually fixing page references and decreases document size significantly!
void PdfMemDocument::InsertPages2(const PdfMemDocument & rDoc, std::vector<int> pageNumbers)
{
std::unordered_set<PdfObject*> totalSet;
std::vector<pdf_objnum> oldObjNumPages;
std::unordered_map<pdf_objnum, pdf_objnum> oldObjNumToNewObjNum;
std::vector<PdfObject*> newPageObjects;
// Collect all dependencies from all pages that are to be copied
for (int i = 0; i < pageNumbers.size(); ++i) {
PdfPage* page = rDoc.GetPage(pageNumbers[i]);
if (page) {
oldObjNumPages.push_back(page->GetObject()->Reference().ObjectNumber());
std::unordered_set<PdfObject*> *set = page->GetPageDependencies();
totalSet.insert(set->begin(), set->end());
delete set;
}
}
// Create a new page object for every copied page from the old document
// Copy all objects the pages depend on to the new document
for (auto it = totalSet.begin(); it != totalSet.end(); ++it) {
unsigned int length = static_cast<unsigned int>(GetObjects().GetSize() + GetObjects().GetFreeObjects().size());
PdfReference ref(static_cast<unsigned int>(length+1), 0);
PdfObject* pObj = new PdfObject(ref, *(*it));
pObj->SetOwner(&(GetObjects()));
if ((*it)->HasStream()) {
PdfStream *stream = (*it)->GetStream();
pdf_long length;
char* buf;
stream->GetCopy(&buf, &length);
PdfMemoryInputStream inputStream(buf, length);
pObj->GetStream()->SetRawData(&inputStream, length);
free(buf);
}
oldObjNumToNewObjNum.insert(std::pair<pdf_objnum, pdf_objnum>((*it)->Reference().ObjectNumber(), length+1));
GetObjects().push_back(pObj);
newPageObjects.push_back(pObj);
}
// In all copied objects, fix the object numbers so they are valid in the new document
for (auto it = newPageObjects.begin(); it != newPageObjects.end(); ++it) {
FixPageReferences(GetObjects(), *it, oldObjNumToNewObjNum);
}
// Insert the copied pages into the pages tree
for (auto it = oldObjNumPages.begin(); it != oldObjNumPages.end(); ++it) {
PdfObject* pageObject = GetObjects().GetObject(PdfReference(oldObjNumToNewObjNum[(*it)], 0));
PdfPage *page = new PdfPage(pageObject, std::deque<PdfObject*>());
GetPagesTree()->InsertPage(GetPageCount() - 1, page);
}
}
std::unordered_set<PdfObject *>* PdfPage::GetPageDependencies() const
{
std::unordered_set<PdfObject *> *set = new std::unordered_set<PdfObject *>();
const PdfObject* pageObj = GetObject();
if (pageObj) {
PdfVecObjects* objects = pageObj->GetOwner();
if (objects) {
set->insert((PdfObject*)pageObj);
objects->GetObjectDependencies2(pageObj, *set);
}
}
return set;
}
// Optimized version of PdfVecObjects::GetObjectDependencies
void PdfVecObjects::GetObjectDependencies2(const PdfObject* pObj, std::unordered_set<PdfObject*> &refMap) const
{
// Check objects referenced from this object
if (pObj->IsReference())
{
PdfObject* referencedObject = GetObject(pObj->GetReference());
if (referencedObject != NULL && refMap.count(referencedObject) < 1) {
(refMap).insert((PdfObject *)referencedObject); // Insert referenced object
GetObjectDependencies2((const PdfObject*)referencedObject, refMap);
}
}
else {
// Recursion
if (pObj->IsArray())
{
PdfArray::const_iterator itArray = pObj->GetArray().begin();
while (itArray != pObj->GetArray().end())
{
GetObjectDependencies2(&(*itArray), refMap);
++itArray;
}
}
else if (pObj->IsDictionary())
{
TCIKeyMap itKeys = pObj->GetDictionary().GetKeys().begin();
while (itKeys != pObj->GetDictionary().GetKeys().end())
{
if ((*itKeys).first != PdfName("Parent")) {
GetObjectDependencies2((*itKeys).second, refMap);
}
++itKeys;
}
}
}
}
void FixPageReferences(PdfVecObjects& objects, PdfObject* pObject, std::unordered_map<pdf_objnum, pdf_objnum>& oldNumToNewNum) {
if( !pObject)
{
PODOFO_RAISE_ERROR( ePdfError_InvalidHandle );
}
if( pObject->IsDictionary() )
{
TKeyMap::iterator it = pObject->GetDictionary().GetKeys().begin();
while( it != pObject->GetDictionary().GetKeys().end() )
{
if ((*it).first != PdfName("Parent")) {
FixPageReferences(objects, (*it).second, oldNumToNewNum);
}
++it;
}
}
else if( pObject->IsArray() )
{
PdfArray::iterator it = pObject->GetArray().begin();
while( it != pObject->GetArray().end() )
{
FixPageReferences(objects, &(*it), oldNumToNewNum),
++it;
}
}
else if( pObject->IsReference() )
{
//PdfObject* referencedObj = objects.GetObject(pObject->GetReference());
pdf_objnum oldnum = pObject->GetReference().ObjectNumber();
pdf_objnum newnum = oldNumToNewNum[oldnum];
if (!newnum) throw new std::exception("No new object number for old object number");
*pObject = PdfReference(newnum, 0);
}
}
I'm having some trouble with the following method and I need some help trying to figure out what I am doing wrong.
I want to return a reference to a Value in a document. I am passing the Document from outside the function so that when I read a json file into it I don't "lose it".
const rapidjson::Value& CTestManager::GetOperations(rapidjson::Document& document)
{
const Value Null(kObjectType);
if (m_Tests.empty())
return Null;
if (m_current > m_Tests.size() - 1)
return Null;
Test& the_test = m_Tests[m_current];
CMyFile fp(the_test.file.c_str()); // non-Windows use "r"
if (!fp.is_open())
return Null;
u32 operations_count = 0;
CFileBuffer json(fp);
FileReadStream is(fp.native_handle(), json, json.size());
if (document.ParseInsitu<kParseCommentsFlag>(json).HasParseError())
{
(...)
}
else
{
if (!document.IsObject())
{
(...)
}
else
{
auto tests = document.FindMember("td_tests");
if (tests != document.MemberEnd())
{
for (SizeType i = 0; i < tests->value.Size(); i++)
{
const Value& test = tests->value[i];
if (test["id"].GetInt() == the_test.id)
{
auto it = test.FindMember("operations");
if (it != test.MemberEnd())
{
//return it->value; is this legitimate?
return test["operations"];
}
return Null;
}
}
}
}
}
return Null;
}
Which I am calling like this:
Document document;
auto operations = TestManager().GetOperations(document);
When I inspect the value of test["operations"] inside the function I can see everything I would expect (debug code removed from the abode code).
When I inspect the returned value outside the function I can see that it's an array (which I expect). the member count int the array is correct as well, but when print it out, I only see garbage instead.
When I "print" the Value to a string inside the methods, I get what I expect (i.e. a well formated json), but when I do it outside all keys show up as "IIIIIIII" and values that aren't strings show up correctly.
rapidjson::StringBuffer strbuf2;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer2(strbuf2);
ops->Accept(writer2);
As this didn't work I decided to change the method to receive a Value as a parameter and do a deep copy into it like this
u32 CTestManager::GetOperationsEx(rapidjson::Document& document, rapidjson::Value& operations)
{
(...)
if (document.ParseInsitu<kParseCommentsFlag>(json).HasParseError())
{
(...)
}
else
{
if (!document.IsObject())
{
(...)
}
else
{
auto tests = document.FindMember("tests");
if (tests != document.MemberEnd())
{
for (SizeType i = 0; i < tests->value.Size(); i++)
{
const Value& test = tests->value[i];
if (test["id"].GetInt() == the_test.id)
{
const Value& opv = test["operations"];
Document::AllocatorType& allocator = document.GetAllocator();
operations.CopyFrom(opv, allocator); //would Swap work?
return operations.Size();
}
}
}
}
}
return 0;
}
Which I'm calling like this:
Document document;
Value operations(kObjectType);
u32 count = TestManager().GetOperationsEx(document, operations);
But... I get same thing!!!!
I know that it's going to be something silly but I can't put my hands on it!
Any ideas?
The problem in this case lies with the use of ParseInSitu. When any of the GetOperations exist the CFileBuffer loses scope and is cleaned up. Because the json is being parsed in-situ when the buffer to the file goes, so goes the data.
I have a very basic question. Is it possible to convert a string into a closure? I tried evaluate() but it didn't work.
evaluate( "myFunction = function(val){ return dollarFormat( val ); }" );
What I have in mind is to save custom functions in the database as string and then run it as needed.
Thank you!
Edit: Just to clarify: I want to be able to save "function(val){ return dollarFormat( val ); }" as a string in database and be able to convert it into a functioning closure.
I would go with user2943775 answer:
<cfscript>
FileWrite("/ram/UDFs.cfm", "<cfset myFunction = function(val){ return dollarFormat( val ); }>")
include template="/ram/UDFs.cfm";
writedump(myFunction(10));
</cfscript>
And in your Application.cfc
component {
this.mappings["/ram"] = "ram://";
...
}
I came across a similar solution, though I was unable to use the in-memory filesystem due to security restrictions. In my Application.cfc, I added the following mapping:
this.mappings = {
"/models" = "#APP_ROOT_PATH#cfcs/models",
"/utils" = "#APP_ROOT_PATH#cfcs/utils",
"/modules" = "#APP_ROOT_PATH#_modules",
"/components" = "#APP_ROOT_PATH#cfcs",
"/udfs" = "#APP_ROOT_PATH#includes/udfs" // path for global (and temporary) UDFs
};
The UDF I created is as follows:
/**
* Takes a string representation of a function and returns it as a Closure
* #output false
* #return Closure
*/
private any function toClosure (required string closure) {
local.id = replace(createUUID(), "-", "", "all");
local.udfpath = "/udfs/udf#id#.cfm";
local.script = "<cfscript>local.fn#id# = #closure#;</cfscript>";
try {
fileWrite(expandPath(udfPath), script);
include udfpath;
} catch (any e) {
} finally {
try {
fileDelete(expandPath(udfPath));
} catch (any e) {}
}
if (!structkeyExists(local, "fn#id#") || !isClosure(local["fn#id#"])) {
throw (message="Unable to compile closure");
}
// return the closure
return local["fn#id#"];
}
And the result:
myFn = toClosure("function (num) { return num + 1; }");
myFn(1); // returns 2
We can pass an integer as a Configuration property as below:
Configuration conf = new Configuration();
conf.set("size", 4);
Is there a way to send an array of integers as a property value?
conf.set("list.of.nums", {2, 4, 6, 8}); // one way is to pass them as a String but it doesn't look good
You can serialize the array object into a file and then move the file to HDFS.Then you can add the hdfs file path to Distributed cache using following.
DistributedCache.addCacheFile(new URI(dfsMetaPath + "#"
+ Constants.OBJSYMLINK0), conf);
DistributedCache.createSymlink(conf);
Serialization can be done as follows:-
public static <T> void serializeMetadata(T voObj,
String filePath) throws IOException,NullPointerException {
if(null==voObj){
throw new NullPointerException("NULL object found");
}
ObjectOutputStream oout = null;
FileOutputStream fsout = null;
try {
fsout = new FileOutputStream(filePath);
oout = new ObjectOutputStream(fsout);
oout.writeObject(voObj);
oout.close();
} finally {
if (null != fsout) {
fsout.close();
}
if (null != oout) {
oout.close();
}
}
}
You can use the filepath passed as arguments to the above method.Using this filepath you can move the file to HDFS filepath. Use the HDFS filepath to create the symlink.
To retireve in mapper you can use the following inside setup to get the object back.
File hdfsfilepath = new File(Constants.OBJSYMLINK0);
Integer[] youarray = MetadataSerDeUtils.deserializeMetadata(youarray ,
hdfsfilepath.getAbsolutePath());
For deserialization you can use following code:-
public static <T> T deserializeMetadata(T voObj,
String filePath) throws IOException,NullPointerException, ClassNotFoundException {
FileInputStream fsin = null;
ObjectInputStream oin = null;
try {
fsin = new FileInputStream(filePath);
oin = new ObjectInputStream(fsin);
voObj = (T) oin.readObject();
return voObj;
} finally {
if (null != fsin) {
fsin.close();
}
if (null != oin) {
oin.close();
}
}
}
I use this code to getData from javascript:
const QVariant myvar = this->page()->mainFrame()->
evaluateJavaScript("measureDistance("+QString::fromStdString(prev->marker_id)+","+QString::fromStdString(stop->marker_id+");"));
bool ok;
const int myint = myvar.toInt(&ok);
if (!ok)
qWarning() << "Error getting int from JS";
qDebug() << myint;
getMapTimeDistance(location, QString::fromStdString(prev->getName()), stop, 10);
And in javascript the last line is:
function measureDistance(m1, m2) {
var wp = new Array();
var lstart = new google.maps.LatLng(markers[m1].position);
var lend = new google.maps.LatLng(markers[m2].position);
var request = {
origin : lstart,
destination : lend,
waypoints : [],
optimizeWaypoints: true,
travelMode : google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status== google.maps.DirectionsStatus.OK) {
response.routes[0].legs[0].duration.text;
} else {
document.getElementById('locationD').value = "drawRouteBad";
}
});
}
Do you know why this code won't work for me? I've tried different combinations of types, but nothing helped. Probably I don't know what type is javasscripts value. Maybe I should pass it to the qt in different way?
response.routes[0].legs[0].duration.value; is coming from the Google Maps API v3 Directions Service (per your last question. That service is asynchronous, you can't return anything from the call to it, you have to use any data you need inside the callback function (when it has been returned from the server and is available).