notmasteryet / jpgjs

JPEG/DCT data decoder
Other
237 stars 57 forks source link

Feature request: Add support for TVJS and TVML (Apple TV JavaScript and Markup Language) #41

Closed loretoparisi closed 9 years ago

loretoparisi commented 9 years ago

I run into this error

if (fileMarker !== 65496) {
                    throw "SOI not found";
                }

Following the stacktrace it starts here when requesting a image

load: function load(path) {
            this._src = path;
            loadURLasArrayBuffer(path, function(buffer) {
                this.parse(new Uint8Array(buffer));
                if (this.onload) {
                    this.onload();
                }
            }.bind(this));
        },

Which is the root cause and how to debug it?

I have some concerns about the XMLHttpRequest element, since it is wrapped by a TVJS object:

https://developer.apple.com/library/tvos/documentation/TVMLJS/Reference/TVJSXMLHttpRequest_Ref/index.html#//apple_ref/javascript/cl/XMLHttpRequest

The underlyning object is a IKJSXMLHttpRequest object, that should be a wrapper for a native object of tvOS:

> XMLHttpRequest
< function IKJSXMLHTTPRequest() {
    [native code]
} = $1

schermata 2015-11-19 alle 19 24 35

Attached the debugger screenshot of the error, since I'm not able to get a better stacktrace.

schermata 2015-11-19 alle 19 10 48

yurydelendik commented 9 years ago

Can you attach tvml file? Did you compare binary data in the file with arraybuffer content?

loretoparisi commented 9 years ago

So, I have seen that the tvOS object is slightly different and it works like

  getDocumentContents : function(url, loadCallback) {
        var templateXHR = new XMLHttpRequest();
        templateXHR.responseType = "document";
        templateXHR.addEventListener("load", function() { loadCallback(templateXHR) }, false);
        templateXHR.open("GET", url, true);
        templateXHR.send();
        return templateXHR;
  },

So I have changed the jpg.js code in this way

function loadURLasArrayBuffer(path, callback) {
    if (path.indexOf("data:") === 0) {
        var offset = path.indexOf("base64,") + 7;
        var data = atob(path.substring(offset));
        var arr = new Uint8Array(data.length);
        for (var i = data.length - 1; i >= 0; i--) {
            arr[i] = data.charCodeAt(i);
        }
        callback(arr.buffer);
        return;
    }

    console.log(path)

    var xhr = new XMLHttpRequest();
    xhr.responseType = "arraybuffer";
    xhr.addEventListener("load", function() { 
        callback(xhr.response);
    }, false);
    xhr.open("GET", path, true);
    xhr.send();
}

to be sure that it is ok. I can clearly see the image path that is correct.

The TVML xml template is a simple loop cycling json elements (that creates a carousel) and then it does

var artistImage = Core.getArtistShelfImage(song);
      var songArtworkThumb=Core.getTrackImage(song);

      try {
        var colorThief = new ColorThief();
        colorThief.getColorNoCanvas(artistImage, 1740, 500, 8, function(colors) {
            Logger.log( colors ); 
        });    
      } catch(e) {
        Logger.error(e);    
      }

The response object of the XHR seems to be a tvOS object of type NSConcreteMutableData

loretoparisi commented 9 years ago

[UPDATE] If I remove the response type I get something!

schermata 2015-11-19 alle 19 46 33

and the stacktrace (sorry again cannot print it out!) through Safari mini debugger

schermata 2015-11-19 alle 19 47 15

I obtained this doing

var xhr = new XMLHttpRequest();
    //xhr.responseType = "arraybuffer";
    xhr.addEventListener("load", function() { 

        console.log( xhr.response );

        callback(xhr.response);
    }, false);
    xhr.open("GET", path, true);
    xhr.send();

and according the Apple's doc the response type of this XHR object can be

Valid values for this attribute are the empty string, blob, document, json, and text.

So, I have tried again with the blob but I get no contents I suppose, so I'm logging out the response headers:

[Log] RESPONSE  (jpg.js, line 35)
[Log] Content-Type: image/jpeg
 (jpg.js, line 36)
Last-Modified: Mon, 02 Nov 2015 18:48:28 GMT
x-powered-by: ASP.NET
Server: cloudflare-nginx
Expires: Sun, 20 Dec 2015 18:53:25 GMT
cf-cache-status: HIT
Cache-Control: public, max-age=2678400
Date: Thu, 19 Nov 2015 18:53:25 GMT
Content-Length: 57359
cf-bgj: imgq:100
cf-ray: 247e1e28203b3da1-MXP
Accept-Ranges: bytes
Etag: "538e3f109f15d11:0"
Vary: Accept-Encoding

This time I get a IKJSBlob object:

[Log] IKJSBlob (jpg.js, line 37)

I can see a Content-Lenght so the image is there, so which check is done with the SOI?

yurydelendik commented 9 years ago

Okay, I don't really see the relation the jpg.js to this issue. This project only deals with JPEG files. Closing as invalid. Please provide a valid test case to reopen an issue.

loretoparisi commented 9 years ago

@yurydelendik I understand. The issue title is wrong, it's more like "Feature Request" to support TVJS and TVML. I suppose this makes more sense. My first question is. What this code actually checks

var fileMarker = readUint16();
                if (fileMarker !== 65496) {
                    throw "SOI not found";
                }
                fileMarker = readUint16();

The image I'm trying to load was this one

35884_7

If I try to load it (using the awesome http bash cURL tool) I can see its Content-Length:75561 bytes, but within the XHR call I can see a slightly different size, Content-Length: 57359 bytes.

Last login: Thu Nov 19 18:50:06 on ttys002
macbookproloreto:~ admin$ http "https://cloud.githubusercontent.com/assets/163333/11300434/55031b72-8f8f-11e5-8f5c-34a66bf4609b.jpg"
HTTP/1.1 200 OK
Accept-Ranges: bytes
Age: 0
Cache-Control: max-age=2592000
Connection: keep-alive
Content-Length: 75561
Content-Type: image/jpeg
Date: Fri, 20 Nov 2015 13:02:51 GMT
ETag: "3dacd2884d1eae539c747be62dcbf397"
Last-Modified: Fri, 20 Nov 2015 13:02:29 GMT
Server: GitHub Cloud
Timing-Allow-Origin: https://github.com
Via: 1.1 varnish
X-Cache: MISS
X-Cache-Hits: 0
X-Fastly-Request-ID: 0b7674bfb5b598a62c0e8ce0e6dd704944942990
X-Served-By: cache-fra1242-FRA

+-----------------------------------------+
| NOTE: binary data not shown in terminal |
+-----------------------------------------+

macbookproloreto:~ admin$ 

Could be this the issue? Do you think you can help to have jpg.js to work on TVJS/TVML?

Thank you.

yurydelendik commented 9 years ago

That is your answer above. If you will make xhr to get right data, then jpgjs will work. I cannot answer question about soi until I see binary data from xhr and curl.

loretoparisi commented 9 years ago

@yurydelendik Yes, sending you both the data. Thank you for your support.

loretoparisi commented 9 years ago

The source binary data of the test image is: https://gist.github.com/loretoparisi/19d8656ba2003ed4dc52

I have converted it to base64 using a online decoder/encoder - http://www.motobit.com/util/base64-decoder-encoder.asp

I'm now going to retrieve the binary data from TVML. This will take some extra efforts, since is undocumented - see related issue `XMLHttpRequest: Get blob file and read binary data`` https://forums.developer.apple.com/thread/26643 ).