我有从API中提取对象的服务。某些对象可能包含图像URL。后端当前扫描这些,并通过get_file_contents()处理它们(在PHP中)并将它们转换为内联数据。这大大加载了我服务器上的吞吐量。我这样做的原因是因为我想稍后缓存图像以便脱机,但是我仍然可以使用常规角度来渲染对象。
我无法在$http.get()
的浏览器中使用Javascript进行处理,因为托管图像的网站阻止了跨网站请求。我想要做的是在浏览器中创建一个<IMG>
元素,一旦加载就调用该服务,这样我就可以提取数据并用它处理对象。
我无法控制服务工作者从应用程序内部存储get,并且应用程序在下载API对象之前随时都不知道URL。
我确实考虑过重做服务工作者来存储来自我网站的内容,但这似乎有点不对,而且我不确定它的效果如何,加上,在开发时,我关掉了服务工作者,因为这意味着我必须让整个网站加载两次才能完全刷新。
有人可以帮助我通过浏览器将图像数据导入我的服务吗?
答案 0 :(得分:-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 + "')");
}
});