Display base64 image with Deno's Oak package - deno

I've got a base64 encoded image stored in my database, so the start looks like this data:image/png;base64,iVB.. and I return it from the database at my 'image' endpoint.
I could of course just fetch the content using JavaScript and include the base64 string as img source and it would render just fine, but I also want to be able to view the image when I go to the endpoint with my browser. I've tried a combination of different headers but couldn't get it too work.
How do I render a base64 image using Oak?
EDIT:
This is the code I ended up using, for anyone interested!
const getImage = async (
{ params, response }: { params: { id: string }; response: Response },
) => {
// Get the image using the ID from the URL
const image = await imageDatabase.findOne({ _id: ObjectId(params.id) });
// If there is no image found
if (!image) {
response.status = 404;
return;
}
// Return the image to the user
const semicolonIndex = image.base64!.indexOf(';')
const colonIndex = image.base64!.indexOf(':')
const commaIndex = image.base64!.indexOf(',')
const imageSize = image.base64!.slice(colonIndex + 1, semicolonIndex);
const imageData = image.base64!.slice(commaIndex + 1);
response.headers.set('Content-Type', imageSize)
response.body = base64.toUint8Array(imageData)
};

HTTP doesn't support base64 image content. You should decode it and return with content type.
const images: any = {
beam: 'data:image/png;base64,<base64-string>',
google: 'data:image/png;base64,<base64-string>',
}
router.get('/image/:id', ctx => {
if (ctx.params && ctx.params.id && ctx.params.id in images) {
const image: string = images[ctx.params.id]
const colonIdx = image.indexOf(':')
const semicolonIdx = image.indexOf(';')
const commaIdx = image.indexOf(',')
// extract image content type
ctx.response.headers.set('Content-Type', image.slice(colonIdx + 1, semicolonIdx))
// encode base64
ctx.response.body = base64.toUint8Array(image.slice(commaIdx + 1))
}
})
To find full code, see code on github
Or you can run my sample directly
deno run -A https://raw.githubusercontent.com/XDean/StackOverflow/master/src/main/deno/Q66697683.ts

Related

Firebase short URLs not redirecting

I created a Google Sheet that uses a Google Script to generate short URLs via Firebase API.
This is the code in the Google Script
function URLShortener(longURL) {
var body = {
"dynamicLinkInfo": {
"domainUriPrefix": "https://go.example.com",
"link" : longURL
},
"suffix": {
"option": "SHORT"
}
};
var key = 'xxxxxxx'
var url = "https://firebasedynamiclinks.googleapis.com/v1/shortLinks?key=" + key;
var options = {
'method': 'POST',
"contentType": "application/json",
'payload': JSON.stringify(body),
};
var response = UrlFetchApp.fetch(url, options);
var json = response.getContentText();
var data = JSON.parse(json);
var obj = data["shortLink"];
return obj;
Logger.log(obj)
}
The script works and it generates URLs similar to https://go.example.com/Xdka but these link redirect to https://example.com/Xdka instead of the actual URL that is sent, e.g. https://example.com/final_url.
If I try to generate these short links from the Firebase dashboard the same happens.
Did I misunderstand how these short URLs work or am I missing something?

Why don't my query params exist when using useRouter? nextjs

I have a nextjs route that is being hit. Here is the url
localhost:8080/eft-files/133722?enableRegen=true.
In my /pages folder, here is the code I am using to get the query params.
const EftFileViewWrapper = () => {
const {
query: { eftFileId, enableRegen }
} = useRouter();
return (
<EftFileView
eftFileId={eftFileId}
enableRegen={enableRegen}
/>
);
};
When the app routes via a next/link, initially the enableRegen is true, but this file gets hit a second time and enableRegen is then undefined. eftFileId is always populated.
If I do a hard refresh on the page, and don't route to it via a next/link, I always get the right values for all query params.
I have had to use URLSearchParams to make this work, like this:
const EftFileViewWrapper = () => {
const {
query: { eftFileId, enableRegen }
} = useRouter();
let params = isInBrowser && new URLSearchParams(location.search);
return (
<EftFileView
eftFileId={eftFileId}
enableRegen={enableRegen || params.get("enableRegen")}
/>
);
};
I would rather stay in the nextjs ecosystem, but am not sure what to do. Any ideas?
useRouter works only with paths and doesn't parse query params.
I suggest you use window.location in order to obtain the search params and then parse it with URLSearchParams. Of course, check that the window object is presented:
let enableGen = false
if (typeof window !== "undefined") {
const params = new URLSearchParams(window.location.search)
enableGen = params.get("enableRegen")
}

AngularFire2 db.collection Adds key 2 Times

I followed this guide to create a upload-component for Angular5 with AngularFire2.
At the end of the Video he showed a code snippet that allows adding a url path to any other database url.
this.snapshot = this.task.snapshotChanges().pipe(
tap(snap => {
console.log(snap);
if (snap.bytesTransferred === snap.totalBytes) {
// Update firestore on completion
this.db.collection('photos').add({ path, size: snap.totalBytes }).then();
}
})
);
This creates a url entry to photos, but it does it 2 times. Any idea how this can be? Each upload he creates 2 random keys with exactly same content inside.
Try something like this. Add to collection in downloadURL()
import { AngularFireStorage } from 'angularfire2/storage';
constructor(private storage: AngularFireStorage)
uploadFile(file){
const filePath = 'images/' + this.docRef + '/';
const task = this.storage.upload(filePath, file);
task.percentageChanges().subscribe(per => {
console.log(per);
});
task.downloadURL().subscribe(url => {
console.log(url);
this.db.collection('photos').add('required data')
}
}

How to pipe requests into clean-css in nodejs?

I'm trying to pipe request output into clean-css to minify and then provide it as a response. The example app in question is built on restify.
Sample Objective Code :
var url = "http://www.example.com/css/style.css";
request.get(url).pipe(minify()).pipe(res);
How can I define the minify() function to accept stream and return one. I've tried dozens of packages, none worked.
Help would be much appreciated!
You can create a Transform stream. It gets the CSS code from the stream created by request.get, does the minification magic and returns the minified CSS.
Here's a working example:
const restify = require('restify');
const request = require('request');
const { Transform } = require('stream');
const CleanCSS = require('clean-css');
const server = restify.createServer();
const cleanCss = new CleanCSS();
const url = 'http://www.example.com/css/style.css';
function createMinifyTransform() {
return new Transform({
transform(chunk, encoding, callback) {
const output = cleanCss.minify(chunk.toString());
this.push(output.styles);
callback();
}
});
}
function respond(req, res) {
request
.get(url)
.pipe(createMinifyTransform())
.pipe(res);
}
server.get('/', respond);
server.listen(8080, () => console.log('%s listening at %s', server.name, server.url));

Downloading Blob from Docusign Envelopes API

Using Meteor HTTP I'm able to get a response from docusign and convert to a base64 buffer.
try {
const response = HTTP.get(`${baseUrl}/envelopes/${envelopeId}/documents/1`, {
headers: {
"Authorization": `bearer ${token}`,
"Content-Type": "application/json",
},
});
const buffer = new Buffer(response.content).toString('base64');
return buffer
} catch(e) {
console.log(e);
throw new Meteor.Error(e.reason);
}
Then on the client I'm using FileSaver.js to saveAs a blob created from an ArrayBuffer via this function
function _base64ToArrayBuffer(base64) {
const binary_string = window.atob(base64);
const len = binary_string.length;
const bytes = new Uint8Array( len );
for (let i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes.buffer;
}
// template helper
'click [data-action="download"]'(e, tmpl){
const doc = this;
return Meteor.call('downloadPDF', doc, (err, pdf)=>{
if(err) {
return notify({
message: err,
timeout: 3000,
})
}
const pdfBuffer = pdf && _base64ToArrayBuffer(pdf);
console.log(pdfBuffer);
return saveAs(new Blob([pdfBuffer], {type: 'application/pdf'}), `docusign_pdf.pdf`);
});
},
The PDF is downloading with the correct size and page length, but all the pages are blank. Should I be encoding the buffer differently? Is there something else I'm missing?
When uploading documents into DocuSign you can either send the raw document bytes as part of a multipart/form-data request or you can send the document as a base64 encoded file in the document node in your request body.
However once the envelope is complete the DocuSign platform converts the doc into a PDF (if it wasn't one already) and provides that raw file. As such, you shouldn't have to base64 decode the doc so I would try removing that part of your code.

Resources