2017-11-25 100 views
-2

我有從API中提取對象的服務。某些對象可能包含圖片網址。後端正在掃描這些內容,並通過get_file_contents()處理它們(在PHP中)並將它們轉換爲內嵌數據。這大大加載了我服務器上的吞吐量。我這樣做的原因是因爲我想稍後緩存圖片以便脫機,但是仍然可以使用常規角度來呈現對象。將圖像作爲服務加載

我不能因爲託管圖像的網站阻止跨站點請求與$http.get()做處理在Javascript在瀏覽器中。然後,我想要做的是在瀏覽器中創建一個元素,該元素在加載後調用服務,以便我可以提取數據並使用它處理對象。

我無法控制服務工作者存儲應用程序內部的get,並且在下載API對象之前,應用程序無法隨時瞭解URL。

我確實想過重做服務人員存儲從我的網站也得到,但這似乎有點不對,我不知道它會工作多麼好,再加上,在開發時,我切換關閉服務人員,因爲這意味着我必須讓整個網站加載兩次才能完全刷新。

誰能幫助我的方式通過瀏覽器進入我的服務來獲取圖像數據嗎?

+0

爲什麼匿名downvote? :( –

回答

-1

如果我在第一個地方找到了一個支持CORS的圖像主機,我可能不需要這個,並且可能剛剛使用了$http調用。

一個指令,服務和控制器都是必需的,以及一個支持CORS(Imgur例如)的主機。我也用this base64 canvas code

下面是javascript代碼:

// Using this from https://stackoverflow.com/questions/934012/get-image-data-in-javascript 
function getBase64Image(img) { 
    // Create an empty canvas element 
    var canvas = document.createElement("canvas"); 
    canvas.width = img.width; 
    canvas.height = img.height; 

    // Copy the image contents to the canvas 
    var ctx = canvas.getContext("2d"); 
    ctx.drawImage(img, 0, 0); 

    // Get the data-URL formatted image 
    // Firefox supports PNG and JPEG. You could check img.src to 
    // guess the original format, but be aware the using "image/jpg" 
    // will re-encode the image. 
    var dataURL = canvas.toDataURL("image/png"); 

    return dataURL; 
    // return dataURL.replace(/^data:image\/(png|jpg);base64,/, ""); 
} 

// Used on the img tag to handle the DOM notification feeding into the service 
app.directive('notifyimgsvc', function() { 
    return {restrict : 'A', link : function(scope, element, attrs) { 
     element.bind('load', function() { 
      console.log('imgSvc::notify() image is loaded'); 
      console.log("imgSvc::notify(): " + this.src); 
      imgSvc.notifyLoad(this.src, getBase64Image(this)); 

     }); 
     element.bind('error', function() { 
      console.log('imgSvc::notify() image could not be loaded'); 
      console.log("imgSvc::notify(): " + this.src); 
     }); 
    }}; 
}); 

// A core service to handle the comms in both directions from requests to data 
app.service('imgSvc', [function(netSvc) { 
    imgSvc = this; // to avoid ambiguoity in some inner function calls 

    imgSvc.images = {}; // a cache of images 
    imgSvc.requests = []; // the requests and their callbacks 
    imgSvc.handlers = []; // handlers that will render images 

    console.log("imgSvc::init()"); 

    // Allows a controller to be notified of a request for an image and 
    // a callback to call when an image is added. There should only ever 
    // be one of these so an array is probaby not needed and any further 
    // requests should probably throw an error. 
    imgSvc.registerHandler = function(callback) { 
     console.log("imgSvc::registerHandler()"); 
     if (imgSvc.requests.length) { 
      // Already have image requests, so tell the new handler about them 
      for (var i in imgSvc.requests) { 
       callback(imgSvc.requests[i].url); 
      } 
     } 
     // Add the new handler to the stack 
     imgSvc.handlers.push(callback); 
    }; 

    // The usage function from your code, provide a callback to get notified 
    // of the data when it loads. 
    imgSvc.getImg = function(url, callback) { 
     console.log("imgSvc::getImg('" + url + "')"); 

     // If we have pre-cached it, send it back immediately. 
     if (imgSvc.images[url] != undefined) { 
      console.log("imgSvc::getImg('" + url + "'): Already have data for this one"); 
      callback(url, imgSvc.images[url]); 
      return; 
     } 

     // push an object into the request queue so we can process returned data later. 
     // Doing it this way als means you can have multiple requests before any data 
     // is returned and they all get notified easily just by looping through the array. 
     var obj = {"url" : url, "callback" : callback}; 
     if (imgSvc.handlers.length) { 
      console.log("imgSvc::getImg('" + url + "'): informing handler"); 
      for (var i in imgSvc.handlers) { 
       imgSvc.handlers[i](obj.url); 
      } 
     } 
     imgSvc.requests.push(obj); 
    }; 

    // Notification of a successful load (or fail if src == null). 
    imgSvc.notifyLoad = function(url, src) { 
     console.log("imgSvc.notifyLoad()"); 
     // Save the data to the cache so any further calls can be handled 
     // immediately without a request being created. 
     imgSvc.images[url] = src; 

     // Go though the requests list and call any callbacks that are registered. 
     if (imgSvc.requests.length) { 
      console.log("imgSvc.notifyLoadCallback('" + url + "'): scanning requests"); 
      for (var i = 0; i < imgSvc.requests.length; i++) { 
       if (imgSvc.requests[i].url == url) { 
        console.log("imgSvc.notifyLoadCallback('" + url + "'): found request"); 
        // found the request so remove it from the request list and call it 
        var req = imgSvc.requests.splice(i, 1)[0]; 
        i = i - 1; 
        console.log("imgSvc.notifyLoadCallback('" + url + "')"); 
        req.callback(url, src); 
       } else { 
        console.log("imgSvc.notifyLoadCallback('" + url + "'): skipping request for '" + imgSvc.requests[i].url + "'"); 
       } 
      } 
     } else { 
      console.log("imgSvc.notifyLoadCallback('" + url + "'): No requests present??"); 
     } 
    }; 

    // The notifiy fail is just a logging wrapper around the failure. 
    imgSvc.notifyFail = function(url) { 
     console.log("imgSvc.notifyFail()"); 
     imgSvc.notifyLoad(url, null); 
    }; 
}]); 

// A simple controller to handle the browser loading of images. 
// Could probably generate the HTML, but just doing simply here. 
app.controller('ImageSvcCtrl', ["$scope", function($scope) { 
    $scope.images = []; 
    console.log("imgSvcCtrl::init()"); 

    // Register this handler so as images are pushed to the service, 
    // this controller can render them using regular angular. 
    imgSvc.registerHandler(function(url) { 
     console.log("imgSvcCtrl::addUrlHandler('" + url + "')"); 
     // Only add it if we don't hqve it already. The caching in the 
     // service will handle multiple request for the same URL, and 
     // all associated malarkey 
     if ($scope.images.indexOf(url) == -1) { 
      $scope.images.push(url); 
     } 
    }); 

}]); 

你需要這樣做的HTML是非常簡單的:

<div data-ng-controller="ImageSvcCtrl" style="display:none;"> 
    <img data-ng-repeat="img in images" data-ng-src="{{img}}" alt="loading image" crossorigin="anonymous" notifyimgsvc /> 
</div> 

而你把它叫做你的控制器內是這樣的:

var req_url = "https://i.imgur.com/lsRhmIp.jpg"; 
imgSvc.getImg(req_url, function(url, data) { 
    if(data) { 
     logger("MyCtrl.notify('" + url + "')"); 
    } else { 
     logger("MyCtrl.notifyFailed('" + url + "')"); 
    } 
});