Could not download PDF from base 64 data from web service . Why?

Friends,
I got a web service output as base 64 encoded data for PDF. I response i get the value , but no pdf output…

My Web service provider method is

getOwnershipCertificate(lb,bid,reason)
  {
    var obj = {wspassword: 'Ikm#itmi$$i0n', wsname: 'getOwnershipCertPDF', lb: lb, bid: bid, reason: reason  };
    var myData = JSON.stringify(obj);
    if(this.data)
    {
      return Promise.resolve(this.data);
    } else {
      return new Promise 
      (
        (resolve,reject) => 
                    {
                      this.http.post('http://ccc.jhj.gov.in/mobservice/index.php/sanchaya/',myData,{ headers: new HttpHeaders()
                      , responseType: 'json'})
                      //.map(res => res)
                      .subscribe
                                 (res => {
                                    resolve(res);
                                   },
                                   err => {console.log("oops some error on taking ownership certificate PDF base 64 encoded string");reject(err);}
                                 );
                    }
      );
    }
  }

My Controller functions are

getOwnershipCertificate(lb, bid, reason) {
    this.certificateProvider.getOwnershipCertificate(lb, bid, reason)
    .then(data => {
        let downloadPDF: any = data[0].ownershippdf;
        //let base64pdf = 'data:application/pdf;base64,' + downloadPDF;
        let base64pdf = downloadPDF;
        console.log("log is"+base64pdf);
        let blobPdf = this.b64toBlob(base64pdf, 'application/pdf',512);
 
        this.file.writeFile(this.file.externalRootDirectory, 'Ownership.pdf', blobPdf, { replace: true })
     .then(res => {
           console.log('wres', res);
         this.fileOpener.open(res.toInternalURL(), 'application/pdf').then((ores) => {
               console.log('ores', ores)
         }).catch(err => {
             console.log('open error');
         });
     }).catch(err => {
         console.log('save error');
     });
    }).catch(err => {
        console.error('ownership get error',err);
    });
 }

and

b64toBlob(b64Data, contentType, sliceSize) {
    contentType = contentType || '';
    sliceSize = sliceSize || 512;
 
    let byteCharacters = atob(b64Data);
    let byteArrays = [];
 
    for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
        let slice = byteCharacters.slice(offset, offset + sliceSize);
 
        let byteNumbers = new Array(slice.length);
 
        for (let i = 0; i < slice.length; i++) {
            byteNumbers[i] = slice.charCodeAt(i);
        }
 
        let byteArray = new Uint8Array(byteNumbers);
 
        byteArrays.push(byteArray);
    }
 
    var blob = new Blob(byteArrays, {type: contentType});
    return blob;
 }

My sample base 64 output is : Sample pdf base 64 value

I did not any error and got the base 64 encoded data as output. Please advise how to download pdf and open it default…

Thanks

Anes

@anespa your code looks very good, for a first step. Now you need to handle errors like with return(). :wink:

Dear Francois
Do you please advise what modification I need to do in current code to download pdf ( open pdf) ? Please suggest code edit help with some working code snippet on current code

Thanks

Anes

@anespa hello, with a super quick look, i’d say this is what makes your code fails:

let blobPdf = this.b64toBlob(base64pdf, ‘application/pdf’,512);

… you need to have a better function for base64toPDF, it looks buggy.

Regards,

Dear Francois,

I feel you are right. Do you please suggest a good function for making blobPDF ?

any body please reply

Anes

@anespa ur code looks perfect. but the problem here is converstion of base64 to blob.
let blobPdf = this.b64toBlob(base64pdf, ‘application/pdf’,512);

Use FetchAPI to convert the base64 to blob response. I hope this will solve ur problem.

let base64pdf = downloadPDF
 fetch('data:application/pdf;base64,' + base64pdf,{
         method: "GET"          
    }).then(res => res.blob()).then(blobPdf => {
      this.file.writeFile(this.file.externalRootDirectory, 'Ownership.pdf', blobPdf, { replace: true })
     .then(res => {
           console.log('wres', res);
         this.fileOpener.open(res.toInternalURL(), 'application/pdf').then((ores) => {
               console.log('ores', ores)
         }).catch(err => {
             console.log('open error');
         });

     }).catch(err => {
                 console.log(‘error’)
     })

Hi Sathasivam,

I changed my code some bit as follows

getOwnershipCertificate(lb, bid, reason) {
    this.certificateProvider.getOwnershipCertificate(lb, bid, reason)
    .then(data => {
        let downloadPDF: any = data[0].ownershippdf;
        let base64pdf = downloadPDF;
        var binary = atob(base64pdf.replace(/\s/g, ''));
        var len = binary.length;
        var buffer = new ArrayBuffer(len);
        var view = new Uint8Array(buffer);
        for (var i = 0; i < len; i++) {
            view[i] = binary.charCodeAt(i);
        }
           
        var blobPdf = new Blob( [view], { type: "application/pdf" });
        this.file.writeFile(this.file.externalRootDirectory, 'OwnershipCertificate.pdf', blobPdf, { replace: true })
     .then(res => {
           console.log('wres', res);
         this.fileOpener.open(res.toInternalURL(), 'application/pdf').then((ores) => {
               console.log('ores', ores)
         }).catch(err => {
             console.log('open error');
         });
     }).catch(err => {
         console.log('save error');
     });
    }).catch(err => {
        console.error('ownership get error',err);
    });
 }

It work fine in Kitkat(4.4) and lolipop(5.1) . But not in Nougat and Marshmallow…

Please advise …

N.B https://app.box.com/s/r97ue9woi4ehg7d99ofmkswo2ye8tbep

In this app , there is an option to Ownership Certificate

Give Wardno and Door no as 1

in second form select Purpose as Bank

Tell is PDF downloaded … Waiting reply

Thanks

Anes

in Nougat and Marshmallow are u getting any error

No error occur… Any permission need to be added with marshmellow or Nougat… please advise

Thanks
Anes

Dear @Sathasivamr,Francois ,

But when i remove blob option I got download screen but get error and closed automatically.

The app is run on 5.1 , but not in 5.1.1

Thanks

Anes

@anespa add following lines to config.xml

<preference name="AndroidPersistentFileLocation" value="Compatibility" />
<preference name="AndroidExtraFilesystems" value="sdcard,cache" />

It’s already added , no change …

instead this one

can u try the following code may be FetchAPI will help u to solve the problem.

Dear Sathasivam,
The exact base 64 data shown in console and Network tab show contents( in chromium) as

preview

preview0
but no actual pdf Download occur.

Please advise

Have you found any working solution for this particular feature?

hi@anespa,

am also facing a similar issue can you help me to solve this

hi dear @revathys

I just make some changes in Core file … that gave the wonder solution !!!

change in /src/index.html

I put above the script inclusion

then build new apk. Now it’s Work in My mobile and Nougat also.

So see my index.html for reference as

<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
  <meta charset="UTF-8">
  <title>Ionic App</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <meta name="format-detection" content="telephone=no">
  <meta name="msapplication-tap-highlight" content="no">

  <link rel="icon" type="image/x-icon" href="assets/icon/favicon.ico">
  <link rel="manifest" href="manifest.json">
  <meta name="theme-color" content="#4e8ef7">
  <script src="build/polyfills.js"></script>
  <!-- cordova.js required for cordova apps -->
  <script src="cordova.js"></script>
  <!-- un-comment this code to enable service worker
  <script>
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('service-worker.js')
        .then(() => console.log('service worker installed'))
        .catch(err => console.error('Error', err));
    }
  </script>-->

  <link href="build/main.css" rel="stylesheet">

</head>
<body>

  <!-- Ionic's root component and where the app will load -->
  <ion-app></ion-app>

  <!-- The polyfills js is generated during the build process -->
  
  <script src="build/vendor.js"></script>
  <!-- The bundle js is generated during the build process -->
  <script src="build/main.js"></script>

</body>
</html>

For Download I used the function ( I think it has no role in this solution)…

getOwnershipCertificate(lb, bid, reason) {
    if(this.global1.getnetwork())
    {  
        this.connectivityFlag = true;
        this.certificateProvider.getOwnershipCertificate(lb, bid, reason)
        .then(data => {
            var downloadPDF: any = data[0].ownershippdf;
            var base64pdf = downloadPDF;
            var contentType = 'application/pdf';
            // only work for Android
            var pathFile = cordova.file.externalDataDirectory;
            var fileName = "Ownership.pdf";
            fetch('data:application/pdf;base64,' + downloadPDF,
            {
                method: "GET"
            }).then(res => res.blob()).then(blob => {
            this.file.writeFile(this.file.externalApplicationStorageDirectory, 'ownershipcertificate.pdf', blob, { replace: true }).then(res => {
              this.fileOpener.open(
                res.toInternalURL(),
                'application/pdf'
              ).then((res) => {

              }).catch(err => {
                console.log('open error')
              });
            }).catch(err => {
                  console.log('save error')     
       });
          }).catch(err => {
                 console.log('error')
          });
     }).catch(err => {
        console.error('ownership get error',err);

    }); 

   } else {
     this.presentAlert();
   }
 }

Hope it help you … If you prefer you can send your full source code (no worries regarding that)

Thanks
Anes P A

Thanks anespa, My web api response is byte array… can you please help me to convert it to PDF and display in mobile app.