What is the relationship between CGPDFContext and CGPDFDocument? - macos

My understanding of this was that perhaps CGPDFContext is to be used for editing PDF document data and CGPDFDocument is used for storing it, since the documentation doesn't list any ways to alter the content of a CGPDFDocument.
I'm also not quite sure what CGDataConsumer/Provider does. From reading the documentation I got the impression that the consumer/provider abstracts the relationship between the CG object and the CFData it writes to; so I don't have to do that myself. So I figured the following code would create a two page blank PDFdocument:
//Don't know exactly how large a PDF is so I gave it 1 MB for now
self->pdfData = CFDataCreateMutable(kCFAllocatorDefault, 1024);
self->consumerRef = CGDataConsumerCreateWithCFData(self->pdfData);
self.pdfRef = CGPDFContextCreate(self->consumerRef, NULL, NULL);
CGPDFContextBeginPage(self.pdfRef, NULL); //Creates a blank page?
CGPDFContextEndPage(self.pdfRef);
CGPDFContextBeginPage(self.pdfRef, NULL); //Creates a second blank page?
CGPDFContextEndPage(self.pdfRef);
//Copies the data from pdfRef's consumer into docRef's provider?
self.docRef = CGPDFDocumentCreateWithProvider(
CGDataProviderCreateWithCFData(
CFDataCreateCopy(kCFAllocatorDefault, self->pdfData)
));
It didn't work though, and NSLogging the first two pages of docRef returns NULL. I'm rather new at this, the C-Layer stuff in particular. Can someone explain to me the relationship between CGPDFContext, CGPDFDocument, CGDataConsumer & CGDataProvider and how I'd use them to create a blank PDF?

Your basic understanding is correct as far as I can see:
A CGPDFContext is a drawing context that "translates" everything that is drawn onto it to PDF instructions (typically for storage in a PDF file).
A CGPDFDocument is used to open an existing PDF file and get information from it.
When you want to create your own PDF file, you have two ways to do it as described here: https://developer.apple.com/library/mac/documentation/graphicsimaging/reference/CGPDFContext/Reference/reference.html
Use "CGPDFContextCreate" which you pass a data consumer. The data consumer gets the data and can do with it as it pleases (you could create a data consumer that passes the PDF onto the clipboard for example).
Use "CGPDFContextCreateWithURL" which you pass a URL. In that case your data will be written to a PDF file at that URL.
If you want to use these functions, have a look at this page https://developer.apple.com/library/mac/documentation/graphicsimaging/Conceptual/drawingwithquartz2d/dq_pdf/dq_pdf.html#//apple_ref/doc/uid/TP30001066-CH214-TPXREF101 which explains in detail how to create PDF files with a data provider and without (simply to a PDF).
To figure out what is happening I would start by trying to write a simple PDF file to disk before writing one to a data provider and then using that data provider immediately to read it again. Without trying your code however, let me point out that you didn't use "CGPDFContextClose" which is described in the document as closing the PDF document and flushing all information to output. You could actually having a situation where stuff is cached and not written to your data provider yet, simply because you haven't forced that.

Related

Extracting image dimensions in the background with Shrine

I have set up direct uploads to S3 with Shrine. This works great. Among others, I have the following plugins enabled:
Shrine.plugin :backgrounding
Shrine.plugin :store_dimensions
Shrine.plugin :restore_cached_data
Correct me if I'm wrong but image dimensions extraction appears to be done synchronously. If I let the user bulk upload images via Uppy and then persist them all, this seems to be taking a long time.
What I'd like to do is perform image dimensions extraction asynchronously - I don't need the dimensions available for the cached file. If possible, I'd like to do that in the background when the file gets promoted to the store. Is there a way to do it?
The way I got this to work is by making use of :refresh_metadata plugin, instead of :restore_cached_data which I used originally. Thanks to Janko for pointing me in the right direction.
Reading into the source code provided some useful insights. :store_dimensions plugin by itself doesn't extract dimensions - it adds width and height to the metadata hash so that when Shrine's base class requests metadata, they get extracted too.
By using :restore_cached_data, this was being done on every assignment. :restore_cached_data uses :refresh_metadata internally so we can use that knowledge to only call it when the file is promoted to the store.
I have :backgrounding and :store_dimensions set up in the initializer so the final uploader can be simplified to this:
class ImageUploader < Shrine
plugin :refresh_metadata
plugin :processing
process(:store) do |io, context|
io.refresh_metadata!(context)
io
end
end
This way persisting data we get from Uppy is super fast and we let the background job extract dimensions when the file is promoted to the store, so they can be used later.
Finally, should you have questions related to Shrine, I highly recommend its dedicated Google Group. Kudos to Janko for not only creating an amazing piece of software (seriously, go read the source), but also for his dedication to supporting the community.

Create a file with Windows Property Store (metadata) using win32 API

I'd like to create a new stub file "test.mp3" for instance, and add a Window Property to it ( System.Author for instance).
the solution must be usable for several file extension as text, picture, videos, etc...
If I just create a file and use IShellItem2::GetPropertyStore I get a HRESULT fail for invalid Arguments.
Use IShellItem2::GetPropertyStore on a real music file I can read and write Its properties just fine.
Please test your suggestions first.
Property Stores typically access and store data within the file itself. In your case of a mp3 file, it would be attempting to read and write the ID3 tags. Also, Property Stores are not stored in a database and cannot be arbitrarily added to files that don't support it.
You'll most likely need to implement your own property handlers to do what it appears you're trying to accomplish. For types that already have handlers, you'll have to replace the system handlers with your own.
The most likely reason your mp3 test is failing is that you have an empty file with no data and no valid ID3 tags.

How to serve static profile images in node

This is really more of a "using what method" than a "how-to" question. I am creating a site in NodeJS with Express. So, each user has the ability to upload a profile picture, and my concern is how to route requests for these images. A couple of questions I have are:
Can I use express.static() to serve a default file if a valid one isn't specified? If not, am I going to have to specify a GET route for /img/profileand handle the FS querying there?
How can I find the correct image if multiple file extensions are allowed? (I originally just removed the file extension and they appeared in img tags anyway, is that okay?)
I am currently naming all pictures after their user's name. Looking ahead into the future (for apps I may have to scale), what are normal naming conventions for static user content? Are most stored with a UUID referencing the content in the database?
What else should I take into consideration that I may not have accounted for yet?
First question:
At present, I'd recommend storing your images in a predictable location that can be inferred from some combination of columns or fields in your database entries. One of those fields or columns would be a filename (accounts for different extensions). Then, if they haven't uploaded an image, you just lay down in your view code a reference to the generic "has not set an image" file.
express.static obviously can server static files, but it currently doesn't have a way to serve some other file if the one you wanted isn't there. Because this sounded like fun, I made some modifications to static to support what you request and submitted a couple of pull requests (the feature touched 2 different modules):
In send: https://github.com/visionmedia/send/pull/33
In connect: https://github.com/senchalabs/connect/pull/999
I don't know if those will get included in the project, but if you want to see my forks that have these changes, they are here:
https://github.com/bigohstudios/send
https://github.com/bigohstudios/connect
If this went through, you would mount a static at the root of your profile image files:
app.use(static('<profile image files root>', { fallback: 'anon.jpg'}))
Second question
I generally store the extension in my DB, then when I load the image, I have the correct extension to put into the src attribute on the img tag.
Third question
If you can guarantee unique names, then using those would work. I prefer using the DB id or a UUID as you suggest. It's less intuitive when scanning all the image uploads, but I rarely find myself doing that. I'm usually hunting for a specific image, and I can look up the identifier for that as needed.
Fourth question
You may end up storing the static content outside your app server (e.g. on S3). If that happens, then of course static won't help you.

Birt Reports - Don't generate an empty report

I have several Birt Reports that I am trying to set up to run on a cron job that will email pdfs of the reports every morning. Everything is working fine as far as the generation and emailing goes; the only issue I am stuck with is this: if there is nothing to report, a pdf with just the report title is generated and emailed (a blank report, basically). I'd like to stop this report from being generated at all, so i can skip the emailing, if the pdf file does not exist.
I have been all over Google for two days now, and the closest I can find is this: http://www.eclipse.org/forums/index.php/t/458779/ in which someone was trying to solve a similar problem and received a push in the right direction, but not a complete solution.
It appears as if this can be done during the beforerender script... but how?
I know I need to:
set a persistent global variable in the oncreate if there is indeed data to report.
get the persistent global variable in the beforerender script.
send the magic don't generate report command.
I'm doing all of generating and emailing from a php script, not Java, so I can't send commands like IEngineTask.cancel() (or can I???)
Yes, I know I can make a row in the report that says "No data to report", but that's not what my users want.
And yes, I could query the database outside of the report to determine if there is valid data to report or not, but i'd prefer not to.
And maybe I could even open and read the pdf, programmatically to see if there is anything there, but that sounds like more of a hassle than it's worth...
So, how do I do this?
Thanks.
My answer is a little bit late, but I'm doing it like this in a framework that is working for hundreds of reports, probably it could be simplified for a single report:
Note that all the code is written from memory (not copied from our framework), so maybe it contains some errors.
Add an external Javascript file myframework.js to your report.
In this file, define an object myframework like this:
if (myframework == undefined) {
myframework = {
dataFound: false,
afterReport: function() {
// Write it to the appContext.
// Using Java, you could read it after the
// runAndRenderTask is done.
reportContext.getAppContext().put("dataFound", this.dataFound);
// But since you probably cannot the context
// (don't like coding Java?), the report has to
// tell it to he world some other way...
var txt = "dataFound=" + (dataFound? "true": "false");
var fw = new java.io.FileWriter("c:\\reportcontext.out");
fw.write(txt);
fw.close();
}
};
}
Add the JS file to your report's resources.
In your report, at a place where you decide that the report has found something (e.g. typically in a data set's onFetch event), tell the framework so by calling
myframework.dataFound = true;
In the reports's afterFactory or afterRender event, call
myframework.afterReport();
Then your report should create an output file c:\reportcontext.out which contains the information you need.

How to add components in to an existing GUI created by guide?

I just created a GUI using guide in MATLAB for a small project I'm working on. I have amongst other things two text fields for from and to dates. Now I'd like to get rid of them and use a Java date select tool. Of course this is not possible using guide so I need to add them manually.
I've managed to get them to show up by putting this code into my Opening_Fcn,
uicomponent(handles, 'style','com.jidesoft.combobox.DateChooserPanel','tag','til2');
using UICOMPONENT.
But even though it shows up I can't access the date select's attributes, for example
get(handles.til2)
returns
??? Reference to non-existent field 'til2'.
How can I fix this?
Unless you edit the saved GUI figure, the basic handles structure will not include your new component by default.
One way to access you component is to store the handle via guidata, by adding the following to your opening function:
handles.til2 = uicomponent(handles, 'style','com.jidesoft.combobox.DateChooserPanel','tag','til2');
guidata(hObject,handles)
Functions that need to access the handle need the line
handles = guidata(hObject)
to return the full handles structure that includes the filed til2

Resources