Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

app.getFileIcon returns empty PNG #8767

Closed
karacas opened this issue Feb 24, 2017 · 21 comments
Closed

app.getFileIcon returns empty PNG #8767

karacas opened this issue Feb 24, 2017 · 21 comments

Comments

@karacas
Copy link

karacas commented Feb 24, 2017

  • Electron version: 1.6.1 beta
  • Operating system: Microsoft Windows [Version 10.0.14393]
app.getFileIcon(path.normalize(file), (err, icon) => {
    if (icon) {
        console.log(icon.toBitmap()); // [buffer array]
        console.log(icon.toBitmap().length); // 9216
        console.log(icon.getBitmap()); // [buffer array]
        console.log(icon.getBitmap().length); // 9216
        console.log(icon.toPNG()); // EMPTY buffer array []
        console.log(icon.toPNG().length); // 0
        console.log(icon.getSize()); // {width: 32, height: 32}
        console.log(icon.toDataURL()); // "data:image/png;base64,"
    }
});
@karacas karacas changed the title nativeImage toDataURL problem getFileIcon / nativeImage toDataURL() Feb 24, 2017
@kevinsawicki
Copy link
Contributor

@karacas what is the value of err when this happens?

@karacas
Copy link
Author

karacas commented Feb 24, 2017

console.log(err) // null

@kevinsawicki
Copy link
Contributor

@karacas can you include the path you are specifying to app.getFileIcon?

@karacas
Copy link
Author

karacas commented Feb 24, 2017

i try all options \, / , nomalice...

direct nativeImage works well

app.getFileIcon("d:\\tmp\\file.png", (_err, _icon) => {
  if (_icon && _icon.getSize() && _icon.getSize().width) {
    data.iconType = "dataURL";
    data.iconUrl = _icon.toDataURL();
    console.log(_err);

    // [WIP] !!!!!!
    if (true && data.iconUrl.length < 25) {
      try {
        data.iconUrl = nativeImage
          .createFromPath("d:\\tmp\\file.png")
          .toDataURL();
      } catch (e) {}
    }
  }
  resolve(data);
});

@kevinsawicki
Copy link
Contributor

@YurySolovyov would you be able to take a look into this?

I'm able to reproduce on Windows 10 with running the following from the dev tools:

require('electron').remote.app.getFileIcon(__filename, (err, icon) => console.log(icon.toDataURL()))

@karacas
Copy link
Author

karacas commented Feb 24, 2017

require('electron').remote.app.getFileIcon("d:\\tmp\\ColorCop.exe", (err, icon) => console.log(icon.toDataURL())) // data:image/png;base64,

@kevinsawicki kevinsawicki changed the title getFileIcon / nativeImage toDataURL() app.getFileIcon returns empty PNG Feb 24, 2017
@karacas
Copy link
Author

karacas commented Feb 24, 2017

            require('electron').remote.app.getFileIcon("d:\\tmp\\file.png", (err, icon) => console.log(icon.toDataURL())) // data:image/png;base64,
            console.log(nativeImage.createFromPath("d:\\tmp\\file.png").toDataURL())  // data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADGElEQ…yYmHajr47NvMrhTohyh/5OR1mUOznciXZw+J4fp636Us/zjwgSUWiIJzHNAAAAAElFTkSuQmCC

@kevinsawicki
Copy link
Contributor

This might be more of an issue with the nativeImage class than with the app.getFileIcon API, will investigate further.

@YurySolovyov
Copy link
Contributor

On Microsoft Windows [Version 10.0.14393] x64
Using the following snippet works for me:

(function() {
    document.write('');
    var app = require('electron').remote.app;
    app.getFileIcon(__filename, { size: 'normal' }, function(err, res) {
        document.write('<img src="' + res.toDataURL() + '" />');
    });
})()

image

@YurySolovyov
Copy link
Contributor

Also, can you try writing the buffer to file and opening it in some image viewer?

@karacas
Copy link
Author

karacas commented Feb 27, 2017

electron_test_getIcon.zip
electron_test_geticon

document.addEventListener('DOMContentLoaded', function () {
	// var __filename = "d:\\tmp\\ColorCop.exe"
	var __filename = "file.png"
	document.write("");
	var app = require("electron").remote.app;
	app.getFileIcon(__filename, {
		size: "normal"
	}, function(err, res) {
		document.write("<img src=\"" + res.toDataURL() + "\" />");
	});
});

@YurySolovyov
Copy link
Contributor

@karacas can you also attach "d:\\tmp\\ColorCop.exe" ?

@karacas
Copy link
Author

karacas commented Feb 27, 2017

ColorCop.zip

@YurySolovyov
Copy link
Contributor

@karacas I was able to get the icon using the API, but you probably need to call path.resolve to get properly-formatted path on windows.

@kevinsawicki should we fix this in API, or just note in the docs?

image

@kevinsawicki
Copy link
Contributor

should we fix this in API, or just note in the docs?

I think the API, what was the difference between the two paths?

@YurySolovyov
Copy link
Contributor

I think ATM we only do separators conversion, but really, we should call path.resolve or path.normalize on path strings. Need @karacas to confirm that it helps.

@karacas
Copy link
Author

karacas commented Mar 1, 2017

@YurySolovyov my prj needs absolute paths.
I check in another machine and runs well, but in the first one not yet (same package-build / electron.exe).
The doubt is why i can get

app.getFileIcon(path.normalize(file), (err, icon) => {
        console.log(icon.toBitmap().length); // 9216
        console.log(icon.getBitmap().length); // 9216
        console.log(icon.toPNG().length); // 0
});

Anyway i will try path.resolve

@YurySolovyov
Copy link
Contributor

I check in another machine and runs well

Meaning you do get expected icon and all that, right?

Makes me think it fails to decode png on that other machine for some reason.

@karacas
Copy link
Author

karacas commented Mar 1, 2017

yes, in second machine works fine.
I'll investigate further & comment. Maybe is a not a electron problem. thanks for the patience =)

@karacas
Copy link
Author

karacas commented Mar 2, 2017

i can convert data from res.toBitmap() with https://gist.github.com/vukicevic/8112515 and works well:

let res2bitmap = drawArray(res.toBitmap(), 32)
document.write('<img src="' + res2bitmap + '" />');

electron_test

Electron app for test:
test_icon.zip

Example code:

import os from "os"; // native node.js module
import { remote } from "electron"; // native electron module
import jetpack from "fs-jetpack"; // module loaded from npm
import { greet } from "./hello_world/hello_world"; // code authored by you in this project
import env from "./env";
import path from "path";

console.log("Loaded environment variables:", env);

var app = remote.app;
var appDir = jetpack.cwd(app.getAppPath());

// Holy crap! This is browser window with HTML and stuff, but I can read
// here files like it is node.js! Welcome to Electron world :)
console.log(
  "The author of this app is:",
  appDir.read("package.json", "json").author
);

function drawArray(arr, depth) {
  var offset, height, data, image;

  function conv(size) {
    return String.fromCharCode(
      size & 0xff,
      size >> 8 & 0xff,
      size >> 16 & 0xff,
      size >> 24 & 0xff
    );
  }

  offset = depth <= 8 ? 54 + Math.pow(2, depth) * 4 : 54;
  height = Math.ceil(Math.sqrt(arr.length * 8 / depth));

  //BMP Header
  data = "BM"; // ID field
  data += conv(offset + arr.length); // BMP size
  data += conv(0); // unused
  data += conv(offset); // pixel data offset

  //DIB Header
  data += conv(40); // DIB header length
  data += conv(height); // image height
  data += conv(height); // image width
  data += String.fromCharCode(1, 0); // colour panes
  data += String.fromCharCode(depth, 0); // bits per pixel
  data += conv(0); // compression method
  data += conv(arr.length); // size of the raw data
  data += conv(2835); // horizontal print resolution
  data += conv(2835); // vertical print resolution
  data += conv(0); // colour palette, 0 == 2^n
  data += conv(0); // important colours

  //Grayscale tables for bit depths <= 8
  if (depth <= 8) {
    data += conv(0);

    for (
      var s = Math.floor(255 / (Math.pow(2, depth) - 1)), i = s;
      i < 256;
      i += s
    ) {
      data += conv(i + i * 256 + i * 65536);
    }
  }

  //Pixel data
  data += String.fromCharCode.apply(String, arr);
  return "data:image/bmp;base64," + btoa(data);
}

document.addEventListener("DOMContentLoaded", function() {
  var __filename = path.resolve("d:\\tmp\\ColorCop.exe");

  //var __filename = "file.png"
  document.write("");
  var app = require("electron").remote.app;

  app.getFileIcon(
    __filename,
    {
      size: "normal"
    },
    function(err, res) {

    	let res2bitmap = drawArray(res.toBitmap(), 32)

      document.write('<img src="' + res.toDataURL() + '" />');
      document.write('<br><br>');
      document.write('<img src="' + res2bitmap + '" />');

      console.log("\nOUTPUTS: ");
      console.log("__filename :", __filename);
      console.log("res.toDataURL() : ", res.toDataURL());
      console.log("res.toPNG().length : ", res.toPNG().length);
      console.log("res.getBitmap().length : ", res.getBitmap().length);
      console.log("res2bitmap.length : ", res2bitmap.length);
    }
  );
});

@kevinsawicki
Copy link
Contributor

Looks like this happens when the DPI scale is non-1.

The image is loaded with the machine's DPI scale here,

gfx::ImageSkia image_skia(gfx::ImageSkiaRep(*bitmap,
display::win::GetDPIScale()));

But toPNG only supports 1x scale:

scoped_refptr<base::RefCountedMemory> png = image_.As1xPNGBytes();

So this probably works on any machine with 1x scale, but fails on others.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants