Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ionic 3: WARNING: sanitizing unsafe URL value

I´m trying to take a photo and analyze it with the tesseract OCR engine in ionic 3 App for iOS. I´m trying to run it on a iPhone 8 iOS 11.2.6 Unfortunately I get an error in Xcode after taking a photo, and the app crashes:

NSURLConnection finished with error - code -1002 and also WARNING: sanitizing unsafe URL value assets-library://asset/asset.JPG?id=A791150A-3E89-400E-99D3-E7B3A3D888AA&ext=JPG

Thank you for your help

home.html

  <h3 *ngIf="debugText">Debug: {{debugText}}</h3>
    <span>{{recognizedText}}</span>
    <!--<img src="assets/img/demo.png" #demoImg class="start-api" />-->
    <img [src]="image" #imageResult />

    <div *ngIf="_ocrIsLoaded && !image">
            <!--<img src="assets/img/Start-arrow.png" #start class="start-arrow" />-->
    </div>

home.ts:

import { Component, ViewChild, ElementRef, NgZone } from '@angular/core';
import { NavController } from 'ionic-angular';
import { Camera } from '@ionic-native/camera';
import { Platform, ActionSheetController, LoadingController } from 'ionic-angular';

import Tesseract from 'tesseract.js';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  @ViewChild('imageResult') private imageResult: ElementRef;
  @ViewChild('demoImg') private demoImg: ElementRef;

  private recognizedText: string;

  image: string = '';
  _zone: any;
  _ocrIsLoaded: boolean = false;

  brightness: number = 12;
  contrast: number = 52;
  unsharpMask: any = { radius: 100, strength: 2 };
  hue: number = -100;
  saturation: number = -100;

  showEditFilters: boolean = false;

  debugText: string = '';

  constructor(
    private camera: Camera,
    public navCtrl: NavController,
    public platform: Platform,
    public loadingCtrl: LoadingController,
    public actionsheetCtrl: ActionSheetController) {

    this._zone = new NgZone({ enableLongStackTrace: false });
  }

  openMenu() {
    if (this._ocrIsLoaded === true) {
      let actionSheet;
      if (!this.image) {
        actionSheet = this.actionsheetCtrl.create({
          title: 'Actions',
          cssClass: 'action-sheets-basic-page',
          buttons: [
            {
              text: 'Random demo',
              icon: !this.platform.is('ios') ? 'shuffle' : null,
              handler: () => {
                this.randomDemo()
              }
            },
            {
              text: 'Take Photo',
              icon: !this.platform.is('ios') ? 'camera' : null,
              handler: () => {
                this.takePicture()
              }
            },
            {
              text: 'Cancel',
              role: 'cancel', // will always sort to be on the bottom
              icon: !this.platform.is('ios') ? 'close' : null,
              handler: () => {
                console.log('Cancel clicked');
              }
            }
          ]
        });
      }
      else {
        actionSheet = this.actionsheetCtrl.create({
          title: 'Actions',
          cssClass: 'action-sheets-basic-page',
          buttons: [
            {
              text: 'Random demo',
              icon: !this.platform.is('ios') ? 'shuffle' : null,
              handler: () => {
                this.randomDemo()
              }
            },
            {
              text: 'Re-Take photo',
              icon: !this.platform.is('ios') ? 'camera' : null,
              handler: () => {
                this.takePicture()
              }
            },
            {
              text: 'Apply filters',
              icon: !this.platform.is('ios') ? 'barcode' : null,
              handler: () => {
                this.filter()
              }
            },
            {
              text: 'Clean filters',
              icon: !this.platform.is('ios') ? 'refresh' : null,
              handler: () => {
                this.restoreImage()
              }
            },
            {
              text: this.showEditFilters == false ? 'Customize filters' : 'Hide customization filters',
              icon: !this.platform.is('ios') ? 'hammer' : null,
              handler: () => {
                this.showEditFilters = this.showEditFilters == false ? true : false;
              }
            },
            {
              text: 'Read image',
              icon: !this.platform.is('ios') ? 'analytics' : null,
              handler: () => {
                this.analyze(this.imageResult.nativeElement.src, false);
              }
            },
            {
              text: 'Cancel',
              role: 'cancel', // will always sort to be on the bottom
              icon: !this.platform.is('ios') ? 'close' : null,
              handler: () => {
                console.log('Cancel clicked');
              }
            }
          ]
        });
      }
      actionSheet.present();
    }
    else {
      alert('OCR API is not loaded');
    }
  }

  restoreImage() {
    if (this.image) {
      this.imageResult.nativeElement.src = this.image;
    }
  }

  takePicture() {
    let loader = this.loadingCtrl.create({
      content: 'Please wait...'
    });
    loader.present();

    // Take a picture saving in device, as jpg and allows edit
    this.camera.getPicture({
      quality: 100,
      destinationType: this.camera.DestinationType.NATIVE_URI,
      encodingType: this.camera.EncodingType.JPEG,
      targetHeight: 1000,
      sourceType: 1,
      allowEdit: true,
      saveToPhotoAlbum: true,
      correctOrientation: true
    }).then((imageURI) => {
      loader.dismissAll();

      this.image = imageURI;
      this.debugText = imageURI;

    }, (err) => {
      //console.log(`ERROR -> ${JSON.stringify(err)}`);
    });
  }

  filter() {
    /// Initialization of glfx.js
    /// is important, to use js memory elements
    /// access to Window element through (<any>window)
    try {
      var canvas = (<any>window).fx.canvas();
    } catch (e) {
      alert(e);
      return;
    }

    /// taken from glfx documentation
    var imageElem = this.imageResult.nativeElement; // another trick is acces to DOM element
    var texture = canvas.texture(imageElem);

    canvas.draw(texture)
      .hueSaturation(this.hue / 100, this.saturation / 100)//grayscale
      .unsharpMask(this.unsharpMask.radius, this.unsharpMask.strength)
      .brightnessContrast(this.brightness / 100, this.contrast / 100)
      .update();

    /// replace image src 
    imageElem.src = canvas.toDataURL('image/png');
  }

  analyze(image, loadAPI) {
    let loader = this.loadingCtrl.create({
      content: 'Please wait...'
    });
    loader.present();

    if (loadAPI == true) {
      this._ocrIsLoaded = false;
    }
    /// Recognize data from image
    Tesseract.recognize(image, {})
      .progress((progress) => {
        this._zone.run(() => {
          loader.setContent(`${progress.status}: ${Math.floor(progress.progress * 100)}%`)
          console.log('progress:', progress);
        })
      })
      .then((tesseractResult) => {
        this._zone.run(() => {
          loader.dismissAll();
          if (loadAPI == true) {
            this._ocrIsLoaded = true;
          }
          console.log('Tesseract result: ');
          console.log(tesseractResult);
          /// Show a result if data isn't initializtion
          if (loadAPI != true) { this.recognizedText = tesseractResult.text; }
        });
      });
  }

  randomDemo() {

  }

  ionViewDidLoad() {
    console.log('loaded')
    this.analyze(this.demoImg.nativeElement.src, true);
  }
}

info.plist:

    <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>CFBundleDevelopmentRegion</key>
    <string>English</string>
    <key>CFBundleDisplayName</key>
    <string>Diagnyzer</string>
    <key>CFBundleExecutable</key>
    <string>${EXECUTABLE_NAME}</string>
    <key>CFBundleIcons</key>
    <dict/>
    <key>CFBundleIcons~ipad</key>
    <dict/>
    <key>CFBundleIdentifier</key>
    <string>io.ionic.diagnyzer</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>${PRODUCT_NAME}</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleShortVersionString</key>
    <string>0.0.1</string>
    <key>CFBundleSignature</key>
    <string>????</string>
    <key>CFBundleVersion</key>
    <string>0.0.1</string>
    <key>LSRequiresIPhoneOS</key>
    <true/>
    <key>NSMainNibFile</key>
    <string/>
    <key>NSMainNibFile~ipad</key>
    <string/>
    <key>UISupportedInterfaceOrientations</key>
    <array>
      <string>UIInterfaceOrientationPortrait</string>
      <string>UIInterfaceOrientationLandscapeLeft</string>
      <string>UIInterfaceOrientationLandscapeRight</string>
    </array>
    <key>UISupportedInterfaceOrientations~ipad</key>
    <array>
      <string>UIInterfaceOrientationPortrait</string>
      <string>UIInterfaceOrientationLandscapeLeft</string>
      <string>UIInterfaceOrientationPortraitUpsideDown</string>
      <string>UIInterfaceOrientationLandscapeRight</string>
    </array>
    <key>UIRequiresFullScreen</key>
    <true/>
    <key>NSAppTransportSecurity</key>
    <dict>
      <key>NSExceptionDomains</key>
      <dict>
        <key>ionic.local</key>
        <dict>
          <key>NSExceptionAllowsInsecureHTTPLoads</key>
          <true/>
        </dict>
      </dict>
      <key>NSAllowsArbitraryLoads</key>
      <true/>
    </dict>
    <key>NSCameraUsageDescription</key>
    <string>This app needs camera access</string>
    <key>NSPhotoLibraryUsageDescription</key>
    <string>This app needs read/write-access photo library access</string>
    <key>NSLocationWhenInUseUsageDescription</key>
    <string/>
    <key>NSMicrophoneUsageDescription</key>
    <string>This app needs microphone access</string>
    <key>NSPhotoLibraryAddUsageDescription</key>
    <string>This app needs write-access to photo library</string>
  </dict>
</plist>
like image 224
mm1975 Avatar asked May 30 '18 12:05

mm1975


2 Answers

I do not know much about Ionic, but loading an img in Angular could cause an UnsafeUrl Exception.

Maybe you need to use a Dom Sanitizer.

DomSanitizer using example:

Inject it:

constructor(private sanitizer: DomSanitizer,) {}

And use a function to get the img content:

getImgContent(): SafeUrl {
        return this.sanitizer.bypassSecurityTrustUrl(this.imgFile);
    }

So you use in HTML Part:

<img class="object-img"
                   [src]="getImgContent()">
like image 62
J. S. Avatar answered Sep 16 '22 13:09

J. S.


Answering a bit late, but try to add File Path plugin to your project. You can pass your URL and the plugin will resolve it.

Note that this plugin is supported only on Android devices

like image 43
Matteo Meil Avatar answered Sep 20 '22 13:09

Matteo Meil