I'm using pdfKit and FlowRouter on my meteor App. I would like to generate a pdf file without saving it an the server. In the docs there is an example for that:
Router.route('/getPDF', function() {
var doc = new PDFDocument({size: 'A4', margin: 50});
doc.fontSize(12);
doc.text('PDFKit is simple', 10, 30, {align: 'center', width: 200});
this.response.writeHead(200, {
'Content-type': 'application/pdf',
'Content-Disposition': "attachment; filename=test.pdf"
});
this.response.end( doc.outputSync() );
}, {where: 'server'});
But this is for Iron Router usage. As I'm using FlowRouter, I don't know how to display/download the pdf directly to the user without saving the file on the server.
Use the server side router from meteorhacks picker. Then something along the lines of
Picker.route('/generate/getPdf', function(params, req, res, next) {
var doc = new PDFDocument({size: 'A4', margin: 50});
doc.fontSize(12);
doc.text('PDFKit is simple', 10, 30, {align: 'center', width: 200});
res.writeHead(200, {
'Content-Type': 'application/pdf',
'Content-Disposition': 'attachment; filename=test.pdf'
});
res.end(doc.outputSync());
});
UPDATE: now that outputSync is deprecated, use:
Picker.route('/generate/getPdf', function(params, req, res, next) {
var doc = new PDFDocument({size: 'A4', margin: 50});
doc.fontSize(12);
doc.text('PDFKit is simple', 10, 30, {align: 'center', width: 200});
res.writeHead(200, {
'Content-Type': 'application/pdf',
'Content-Disposition': 'attachment; filename=test.pdf'
});
doc.pipe(res);
doc.end();
});
Here's how to do it now that outputSync() has been removed:
Picker.route('/generate/getPdf', function(params, req, res, next) {
var doc = new PDFDocument({size: 'A4', margin: 50});
doc.fontSize(12);
doc.text('PDFKit is simple', 10, 30, {align: 'center', width: 200});
res.writeHead(200, {
'Content-Type': 'application/pdf',
'Content-Disposition': 'attachment; filename=test.pdf'
});
doc.pipe(res);
doc.end(res);
});
Related
I've seen very similar questions but I still can't see what's wrong with my code.
I've deployed a Firebase function that I call from my client when pressing a specific button.
// Generate Payment URL
exports.paymentRequest = functions.https.onCall(async (data, context) => {
const clientAccessToken = data.clientAccessToken;
const recipientIban = data.recipientIban;
const recipientName = data.recipientName;
const paymentDescription = data.paymentDescription;
const paymentReference = data.paymentReference;
const productPrice = parseInt(data.productPrice);
const jsonData = {
"destinations": [
{
"accountNumber": recipientIban,
"type": "iban"
}
],
"amount": productPrice,
"currency": "EUR",
"market": "FR",
"recipientName": recipientName,
"sourceMessage": paymentDescription,
"remittanceInformation": {
"type": "UNSTRUCTURED",
"value": paymentReference
},
"paymentScheme": "SEPA_INSTANT_CREDIT_TRANSFER"
};
axios({
method: "post",
url: "https://api.endpoint.com/payment",
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
Authorization: `Bearer ${clientAccessToken}`,},
data: jsonData,
})
.then(response => {
//handle success
console.log(response.data);
return response.data;
})
.catch(response => {
//handle error
console.log(response);
});
})
And here is my flutter code:
onPressed: () async {
HttpsCallable callable = FirebaseFunctions.instance
.httpsCallable('PaymentRequest');
final resp = await callable.call(
<String, dynamic>{
'clientAccessToken': 'myToken',
'recipientIban': ibanController.text,
'recipientName': nameController.text,
'paymentDescription': descriptionController.text,
'paymentReference': referenceController.text,
'productPrice': productPriceController.text
},
);
print("result: ${resp.data}");
}
I do receive a 200 and the full expected API Response body in the Firebase Console (meaning that the console.log(response.data); in my function works), but I always receive a "result: null" in de Flutter console, so it seems like the response.data isn't returned.
I tried adding a return right before axios in my function but it doesn't change anything.
What am I missing?
Thanks
You returning data in axios.then() method. If you made an async function why you not use await but .then() ?
Try like this:
exports.paymentRequest = functions.https.onCall(async (data, context) => {
const clientAccessToken = data.clientAccessToken;
const recipientIban = data.recipientIban;
const recipientName = data.recipientName;
const paymentDescription = data.paymentDescription;
const paymentReference = data.paymentReference;
const productPrice = parseInt(data.productPrice);
const jsonData = {
"destinations": [
{
"accountNumber": recipientIban,
"type": "iban"
}
],
"amount": productPrice,
"currency": "EUR",
"market": "FR",
"recipientName": recipientName,
"sourceMessage": paymentDescription,
"remittanceInformation": {
"type": "UNSTRUCTURED",
"value": paymentReference
},
"paymentScheme": "SEPA_INSTANT_CREDIT_TRANSFER"
};
const response = await axios({
method: "post",
url: "https://api.endpoint.com/payment",
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
Authorization: `Bearer ${clientAccessToken}`,
},
data: jsonData,
})
console.log(response.data)
return response.data
})
I want to upload a batch of 64 images to Custom Vision using the JavaScript SDK.
const files: ImageFileCreateEntry[] = []
while (i < 64) {
const data = fs.readFileSync(`${sampleDataRoot}/${tag.name}/${file}`)
const fileEntry: ImageFileCreateEntry = { name: file, contents: data }
files.push(fileEntry);
i++
}
const batch: ImageFileCreateBatch = { images: files, tagIds: [tag.id] }
fileUploadPromises.push(client.createImagesFromFiles(projectId, batch))
But I'm getting the following error:
RestError: No valid image files
at new RestError (/home/pomatti/projects/personal/azure-customvision-benchmark/node_modules/#azure/ms-rest-js/lib/restError.ts:18:5)
at /home/pomatti/projects/personal/azure-customvision-benchmark/node_modules/#azure/ms-rest-js/lib/policies/deserializationPolicy.ts:117:27
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async Promise.all (index 5) {
code: 'BadRequestImageBatch',
statusCode: 400,
request: WebResource {
streamResponseBody: false,
url: 'https://eastus.api.cognitive.microsoft.com/customvision/v3.3/training/projects/ff4967f9-f772-4473-89a5-41356c471454/images/files',
method: 'POST',
headers: HttpHeaders { _headersMap: [Object] },
body: '{"images":[],"tagIds":["8a2e95b5-2050-403d-95e7-45b08e358d7d"]}',
query: undefined,
formData: undefined,
withCredentials: false,
abortSignal: undefined,
timeout: 0,
onUploadProgress: undefined,
onDownloadProgress: undefined,
proxySettings: undefined,
keepAlive: undefined,
operationSpec: {
httpMethod: 'POST',
path: 'projects/{projectId}/images/files',
urlParameters: [Array],
requestBody: [Object],
responses: [Object],
serializer: [Serializer]
}
},
response: {
body: '{"code":"BadRequestImageBatch","message":"No valid image files"}',
headers: HttpHeaders { _headersMap: [Object] },
status: 400
},
body: { code: 'BadRequestImageBatch', message: 'No valid image files' }
}
I figured out that my implementation was completely messed up.
This is how I solved it for now:
const client = getTrainingClient();
const tags = await client.getTags(projectId);
let fileUploadPromises = [];
tags.forEach(tag => {
const imageFiles = fs.readdirSync(`${sampleDataRoot}/${tag.name}`);
const files: ImageFileCreateEntry[] = []
const chunk = imageFiles.slice(0, 64)
chunk.forEach(file => {
const data = fs.readFileSync(`${sampleDataRoot}/${tag.name}/${file}`)
const fileEntry: ImageFileCreateEntry = { name: file, contents: data }
files.push(fileEntry);
})
const batch: ImageFileCreateBatch = { images: files, tagIds: [tag.id] }
fileUploadPromises.push(client.createImagesFromFiles(projectId, batch))
})
(I've got say it in advance, sorry for my bad english) below is my typescript code in which is working perfectly. The takephoto method opens the device gallary and let the user choose one of pictures stored in the device and the uploadFile method tranfers the data image to the restfull api that I'm developing in asp.net core :
export class SelecionarAvatarPage {
imgrc:any ='assets/imgs/blank-profile-picture-973460_640-300x300.png';
imgurl: any =' ';
imgname: string;
constructor(public navCtrl: NavController, private transfer: FileTransfer, public loadingCtrl: LoadingController, private camera: Camera, public navParams: NavParams, private platform: Platform, public toastCtrl: ToastController) {
}
ionViewDidLoad() {
console.log('ionViewDidLoad SelecionarAvatarPage');
}
takePhoto(sourceType:number) {
const options: CameraOptions = {
quality: 50,
destinationType: this.camera.DestinationType.DATA_URL,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.PICTURE,
correctOrientation: true,
sourceType:sourceType,
}
this.camera.getPicture(options).then((imageData) => {
this.imgname = imageData;
let base64Image = 'data:image/jpeg;base64,' + imageData;
this.imgrc = base64Image;
this.imgurl = imageData;
}, (err) => {
// Handle error
});
}
presentToast(msg) {
let toast = this.toastCtrl.create({
message: msg,
duration: 3000,
position: 'bottom'
});
toast.onDidDismiss(() => {
console.log('Dismissed toast');
});
toast.present();
}
uploadFile() {
let loader = this.loadingCtrl.create({
content: "Uploading..."
});
loader.present();
const fileTransfer: FileTransferObject = this.transfer.create();
loader.dismiss();
let options: FileUploadOptions = {
fileKey: 'ionicfile',
fileName: 'ionicfile',
chunkedMode: false,
mimeType: "image/jpeg",
headers: {}
}
fileTransfer.upload(this.imgurl, 'http://192.168.0.000:5000/api/image', options)
.then((data) => {
console.log(data);
this.presentToast("Imagem foi enviada");
}, (err) => {
console.log(err);
loader.dismiss();
});
}
I want to know how I could upload image sent from an ionic app by File Transfer plugin in ASP.NET Core
Code for Upload: `
postFile(imageData,id) {
this.commonService.showLoader("Uploading........");
let currentName = imageData.substr(imageData.lastIndexOf('/') + 1);
let correctPath = imageData.substr(0, imageData.lastIndexOf('/') + 1);
let base64Image = imageData;
this.filePath.resolveNativePath(imageData)
.then(filePath =>base64Image)
.catch(err => console.log(err));
console.log(base64Image);
const fileTransfer = this.transfer.create();
let imageName = base64Image;
var options: FileUploadOptions = {
fileKey: "file",
fileName: imageName.substr(imageName.lastIndexOf('/') + 1),
mimeType: "image/png/jpeg",
chunkedMode: false,
params:{'Id': id},
headers: { 'Authorization':'Bearer '+ sessionStorage.getItem("token") }
}
return new Promise((resolve, reject) => {
fileTransfer.upload(imageName,encodeURI( this.MainURL + "/UploadMedia"), options)
.then((data) => {
console.log(data);
resolve(200);
}, (err) => {
this.commonService.hideLoader();
reject(500);
})
})
}
Code for Getting Image :private OpenCamera(): void {
const options: CameraOptions = {
quality: 50,
destinationType: this.camera.DestinationType.FILE_URI,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.PICTURE,
correctOrientation: true,
sourceType: this.camera.PictureSourceType.CAMERA,
saveToPhotoAlbum: true
}
this.camera.getPicture(options).then((imageData) => {
// let base64Image = 'data:image/jpeg;base64,' + imageData;
let s = imageData;
this.AddIssueObj.file.push(s);
this.uploadcount = this.AddIssueObj.file.length;
}, (err) => {
// Handle error
});
}
Use destinationType: this.camera.DestinationType.DATA_URI, Becasue URL wont help you to send data to server but URI does. Plugins u need to use.import { FileUploadOptions } from '#ionic-native/file-transfer';
import { File } from '#ionic-native/file';`
I got it, I solved this problem by replacing the destination type to this.camera.DestinationType.FILE_URI instead of this.camera.DestinationType.DATA_URL
const options: CameraOptions = {
quality: 50,
destinationType: this.camera.DestinationType.FILE_URI,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.PICTURE,
correctOrientation: true,
sourceType:sourceType,
}
i am actually working on a mobile app in ionic v3 with angular5
The goal is to be able to take a picture or choose from existing ones and then upload it to the server. The first part is done, but i am struggling with the upload.
The api needs multipart/form-data which must consist of two requests. First with text part and second is the image.
Is there any solution for this?
This is what I have done for similar requirement
takePhoto() {
this.camera.getPicture({
quality: 100,
destinationType: this.camera.DestinationType.FILE_URI,
sourceType: this.camera.PictureSourceType.CAMERA,
encodingType: this.camera.EncodingType.PNG,
saveToPhotoAlbum: true
}).then(imageData => {
this.myPhoto = imageData;
this.uploadPhoto(imageData);
}, error => {
this.functions.showAlert("Error", JSON.stringify(error));
});
}
selectPhoto(): void {
this.camera.getPicture({
sourceType: this.camera.PictureSourceType.PHOTOLIBRARY,
destinationType: this.camera.DestinationType.FILE_URI,
quality: 100,
encodingType: this.camera.EncodingType.PNG,
}).then(imageData => {
this.myPhoto = imageData;
this.uploadPhoto(imageData);
}, error => {
this.functions.showAlert("Error", JSON.stringify(error));
});
}
private uploadPhoto(imageFileUri: any): void {
this.file.resolveLocalFilesystemUrl(imageFileUri)
.then(entry => (<FileEntry>entry).file(file => this.readFile(file)))
.catch(err => console.log(err));
}
private readFile(file: any) {
const reader = new FileReader();
reader.onloadend = () => {
const formData = new FormData();
const imgBlob = new Blob([reader.result], { type: file.type });
formData.append('evaluationID', this.currentEvaluation.evaluationId);
formData.append('standardID', this.currentEvaluation.id);
formData.append('score', this.currentEvaluation.score);
formData.append('comment', this.currentEvaluation.comment);
formData.append('file', imgBlob, file.name);
this.saveStandard(formData);
};
reader.readAsArrayBuffer(file);
}
And here is code for provider
saveStandard(receivedStandardInfo:any){
return new Promise((resolve, reject) => {
this.http.post(apiSaveStandard,receivedStandardInfo)
.subscribe(res => {
resolve(res);
}, (err) => {
console.log(err);
reject(err);
});
}).catch(error => { console.log('caught', error.message); });
}
Here is the code I am working with:
const initialState = {
_requestStatus: null,
data: {
domains: {},
},
};
const transformCustomDomainsData = (state, json) => {
const { response } = json;
return {
domains: {
...state.data.domains,
...response.map(resp => ({
id: resp.id,
domain: resp.domain,
context: resp.context,
})),
},
};
};
I am trying to come up with code that will translate the initial fetch reducer response into a hash tree.
Something like this:
const initialState = {
byHash: {
'1': {id: '1', content: {title: 'item 1'}},
'2': {id: '2', content: {title: 'item 2'}},
'3': {id: '3', content: {title: 'item 3'}}
}
}
Where the key in the byHash is the id of each item in the array and the value is each object in the json response from the server.
Figured it out...
const transformCustomDomainsData = (state, json) => {
const { response } = json;
return {
domains: {
...state.data.domains,
...response.reduce((obj, resp) => {
obj[resp.id] = resp;
return obj;
}, {}),
},
};
};