Trevor
Trevor

Reputation: 2467

nodejs serve blob(base64) as image

I know there's two other similar questions, but mine just isn't working and I'm not sure why.

I'm trying to serve a blob image saved in base64 on a nodejs server.

It's just not serving and I have no clue why. If I comment out the "writeHead" part it shows the base64 like it should. I've tried it with data:image/jpeg and without. I've also tried converting it to a buffer. Just can't seem to figure it out.

The base64 image is less than 200 kb and is saved in a mediumblob

Can anyone see what I'm doing wrong

app.get("/f/:id", async function(req, res) {
  r = await Files.get(req);
  if(r.err.code){
    console.log("error",r);
  }
  var file = r.res.file;

  res.writeHead(200, {
    'Content-Type': 'image/png',
    'Content-Length': file.length
  });
  res.end(file);
});

Here's what it looks like in the browser Here's what it looks like in the browser Here's what it looks like without writeHead enabled Here's what it looks like without writeHead enabled

Note: the "viewPortSize" id element at the bottom is an extension.

Edit #1: Also on Firefox it says "the image cannot be displayed because of errors" This must mean I've encoded it into base64 incorrectly right?

Edit #3: Actually it is saved correctly because if I remove headers and display it as html with an img and src it shows the image properly..now I really don't know what the issue is.

firefox error

Edit #2:Here's the app.js setup

// ==============================================
// Base setup
// ==============================================

process.env.TZ = "Etc/GMT"

const express     = require('express');
const session     = require('express-session');
const app         = express();
const port        = 3075;
const bodyParser  = require('body-parser');

app.use(bodyParser.urlencoded({limit: '50mb', extended: true }));
app.use(bodyParser.json({limit: '50mb'}));

app.use(require('express-useragent').express());
app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true,
  cookie: { secure: true }
}))

// Cors
app.use(async function(req, res, next) {

  let allowOrigins = [
    // removed for SO
  ];

  if(Config.Env === Environments.Local){
    res.header("Access-Control-Allow-Origin", "*");
    req.session.language = req.query.lg;
  }else{
    res.header("Access-Control-Allow-Origin", Config.FrontEnd.Url);
    var origin = req.get('origin');
    for (let i = 0; i < allowOrigins.length; i++) {
      const allowOrigin = allowOrigins[i];
      if(origin.match(allowOrigin)){
        res.header("Access-Control-Allow-Origin", origin);
      }
    }

    var subdomain = origin.split('.')[0];
    for (let j = 0; j < availableLanguages.length; j++) {
      const lang = availableLanguages[j];
      if(lang.code === subdomain){
        req.session.language = lang.code;
        break;
      }    
    }
  }

  // if(Config.Env !== Environments.Local){
    if(req.session.language !== undefined && req.session.language !== "en"){
      Config.FrontEnd.Url = Config.FrontEnd.Url.replace("://", "://"+req.session.language+".");
    }
  // }


  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, auth-id, auth-token, x-csrf-token, _csrf");
  res.header('Access-Control-Allow-Methods', 'PATCH, POST, GET, DELETE, OPTIONS');
  next();
});

Edit #4: If I send it like this(with the data part on it) , the image shows like it should. However the headers are not of an image. (if I change to image it goes back to the black screen)

app.get("/f/:id", async function(req, res) {
  r = await Files.get(req);
  if(r.err.code){
    console.log("error",r);
  }
  var file = r.res.file;

  res.end(
    '<html>'+
      '<head></head>'+
      '<body>'+
          '<img src="'+file+'">'+
      '</body>'+
    '</html>'
  );
});

Upvotes: 1

Views: 5535

Answers (1)

Matt
Matt

Reputation: 74889

If the database stores a data:image/png;base64,xxxx string then it would need to be converted back to the binary data to be part of a response with a content type of image/png (like a regular image file).

const img_base64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='

const server = require('http').createServer((req,res)=>{
  console.log('got req', req.url)

  // Extract image data
  const m = /^data:(.+?);base64,(.+)$/.exec(img_base64)
  if (!m) throw new Error(`Not a base64 image [${img_base64}]`)
  const [ _, content_type, file_base64 ] = m
  const file = Buffer.from(file_base64,'base64')

  res.writeHead(200, {
    'Content-Type': content_type,
    'Content-Length': file.length
  });
  res.end(file);
})

server.listen(3132, ()=> console.log('hi', server.address()))

Upvotes: 9

Related Questions