2017-11-25 98 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 + "')"); 
    } 
});