1

I have a Firebird DB table, which contains fields with image data (as blob sybtype -5). I need to get this data and convert it to an image file. Code example below creates a file (but size is very large, and while trying to open it - it is said, that file is not right BMP file). What am I missing here?

result[0].OBJ_IMAGE1((err, name, eventEmitter) => {
    if(err) throw err;

    let chunks = [];
    eventEmitter.on('data', chunk => {
        chunks.push(chunk);                
    });
    eventEmitter.once('end', () => {
        let buffer = Buffer.concat(chunks);         

        fs.writeFile('test.png',  buffer, err => {
            if(err) throw err;
            console.log('image file written');
        });            
    });
});

enter image description here

enter image description here

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Yurii
  • 171
  • 2
  • 17
  • Your saving it as a PNG, but you mention it is a BMP. What is the actual file type? Can you open the file if you save the blob to a file from your favourite query tool? Also, which Firebird Node.js driver are you using? – Mark Rotteveel Feb 11 '22 at 15:59
  • As an aside, negative blob sub-types have no special meaning in Firebird, it just means it is a user-defined blob-type (which might have special meaning for the application reading or writing the data). – Mark Rotteveel Feb 11 '22 at 16:01
  • Actual type of image, inserted in firebird db, using application, is a .bmp file. I've tried to save as .bmp, .jpeg, .png. But Windows keeps telling that the file is a wrong pixel picture bmp (while trying to open using Paint). – Yurii Feb 11 '22 at 19:26
  • @MarkRotteveel I'm using IBExpert as a DB viewer. I can see data as hex, but as a picture it is not loading (image I added in question) – Yurii Feb 11 '22 at 19:31
  • I'm using 'node-firebird' – Yurii Feb 11 '22 at 20:00
  • 15 0F 00 .. seems not a valid/known image file signature, some signs found here https://www.garykessler.net/library/file_sigs.html – Marcodor Feb 11 '22 at 20:45
  • Maybe there should be used some CAST while getting data from SELECT query? Now I just get value from table as it is. – Yurii Feb 12 '22 at 07:06
  • Before you can even verify how you can open the file, you really need to know what data was stored and how it needs to be processed. Maybe it is a raw image, maybe it is some proprietary encoding or encryption by the authors of the software that inserted the image. At first glance, your code to save the file looks correct (though I would use a stream to write, instead of storing it in memory before writing it out), but I'm not that familiar with Node.js. – Mark Rotteveel Feb 12 '22 at 09:20
  • @MarkRotteveel thanks for the advice. As for stored data - for test purpose I can store an image by myself from that software, and in the program interface image is displaying, all works fine. But I cannot find a way to correctly retrieve image from db programmatically. Maybe there really some encryption is used for storing image in DB, I don't know... – Yurii Feb 12 '22 at 10:08
  • `I can store an image by myself from that software, and in the program interface image is displaying` then you have to determine what language and libraries the said program was written with, and also if what you try to do is legal (would not be considered trying to break into the program). While Russian laws declares your rights to "adapt" software for the sake of compatibility, there is no specific criteria how this is different from cracking, and then it is about having a better paid lawyer. http://ipcmagazine.ru/asp/software-modification-regulation-issues – Arioch 'The Feb 14 '22 at 20:39
  • @Arioch'The thanks for the respond, but I don't care what russian laws declared, thankfully I'm not from russia – Yurii Feb 16 '22 at 07:21
  • the software was written in delphi – Yurii Feb 16 '22 at 07:21
  • I looked through Delphi XE2 sources, and while i found some places where extra data is prefixed to the binary stream, it never was 5 bytes. Can you get any idea about the sources of that saving function? If not, the only thing you left is chop off byte by byte and then try to recognize file format (or any of more efficient string multi-search algos). Or just assume there would always be 5 bytes then JPEG and try your luck. Your screenshot shows Windows set for Russian language though. Maybe you did so to get free IBExpert. I saw it and assumed you operate under Russian laws, mistaken. – Arioch 'The Feb 17 '22 at 09:49

1 Answers1

1

I have tested your code, and it will correctly write out the blob to a file. Your problem is therefore - as also discussed in the comments - one of not knowing what the actual image file type is, so you're storing it with the wrong file extension. You need to know the file type (or encoding, or encryption) used by the application storing the image data to be able to select the right file extension, image viewer to display the data and/or additional transformations required to get a viewable file.

Looking at the example data and the File Signatures link Marcodor provided, it is possible that the stored data is type "Standard JPEG file with Exif metadata" (FF D8 FF E1 xx xx 45 78 69 66 00), but the file is prefixed with 5 bytes of application specific data (maybe some sort of type identifier, or a file length, or something like that). Based on that, try using SUBSTRING(OBJ_IMAGE1 FROM 6) and see if saving as jpg allows you to open the file (NOTE: This doesn't necessarily mean all files stored in these blobs are JPEGs!).

As an aside, it is more efficient to store the image using:

result[0].OBJ_IMAGE1((err, name, e) => {
    if (err) throw err;
    var imgStream = fs.createWriteStream('filename.ext')
    e.pipe(imgStream);
});

Using pipe will write the chunks directly to a file as they are received, instead of accumulating the entire file into memory before writing it out.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • These 5 bytes most likely are from a header added by Delphi TDBImage that was supposed to contain image type and other internal info but didn't get much support since introduction. – user13964273 Feb 12 '22 at 13:37
  • When I try to use ```SUBSTRING(OBJ_IMAGE1 FROM 6)``` - an error ocurres ```Error: invalid BLOB ID``` – Yurii Feb 12 '22 at 15:01
  • I tried to compare hex data of the same picture. This is actual buffer, which was seen durring ```fs.readFileSync()```: ``` – Yurii Feb 12 '22 at 15:39
  • `FF D8 FF E0 xx xx 4A 46 49 46 00` is also JPEG according to that File Signatures page. – Mark Rotteveel Feb 13 '22 at 06:49
  • that `яяШя` in his screenshot is a typical JFIF (JPEG with tags) header when seen in Russian Windows codepage. The prefix $0f15 might be a sream length saved as int32, with decimal value 3861. Or something else. I believe few months ago we already saw a very similar question, which was bound to some specific language/library. The data in the blob was not the picture file, but a picture object of that library/language, with some tagged data before and/or after the stream. The topic starter has to show the piece code of the program that writes to the database, to learn language and library – Arioch 'The Feb 14 '22 at 20:15