Phaser: how to load data URIs?

Created on 24 May 2018  路  10Comments  路  Source: photonstorm/phaser

version: 3.8.0

I use webpack load all images , but phaser apis is image urls...how to change give image element or use data URIs

const diamonds = require("./diamonds32x24x5.png")
function preload() {
  this.load.spritesheet('diamonds',diamonds , { frameWidth: 32, frameHeight: 24 });
}
Local data URIs are not supported: diamonds
load @ File.js:291
(anonymous) @ LoaderPlugin.js:773
each @ Set.js:194
checkLoadQueue @ LoaderPlugin.js:758
start @ LoaderPlugin.js:716
bootScene @ SceneManager.js:475
start @ SceneManager.js:1068
bootQueue @ SceneManager.js:224
emit @ index.js:201
updatePending @ TextureManager.js:148
emit @ index.js:182
image.onload @ TextureManager.js:250
load (async)
addBase64 @ TextureManager.js:242
boot @ TextureManager.js:128
emit @ index.js:201
boot @ Game.js:290
check @ DOMContentLoaded.js:38

Most helpful comment

Fair enough. This is the top google result for the error. I misunderstood how both Phaser and Webpack work and it's been a challenge.

The two links above were helpful. The webpack !! syntax to override rules is also helpful.

const spriteFile = require('!!file-loader?name=[hash]/[name].[ext]!./sprites.png')

/*  
require('!!file-loader?name=[hash]/[name].[ext]!./sprites.png')
require('                                                    ') - emit a file and return a path string
         !!                                                     - turn off all webpack config for this require()
           file-loader                                          - write a file and return a path
                      ?name=[hash]/[name].[ext]                 - file-loader option: set file and path 
                                               !                - end webpack configuration
                                                ./sprites.png   - file to work on
*/

This was very helpful when trying to integrate a spritemap from TexturePacker: https://www.codeandweb.com/texturepacker/tutorials/how-to-create-sprite-sheets-for-phaser3

    // Sprites in files: ./sprites.png and ./sprites.json

    // this.load.multiatlas('multiatlas', jsonFile, pngDirectory);  
    // loader wants json and directory.  
    // sprites.json format hardcodes "sprites.png", so webpack can't change file name.

    // Webpack sprites.png -> [hash]/sprites.png
    const spriteFile = require('!!file-loader?name=[hash]/[name].[ext]!./sprites.png')

    // Use [hash] as last param to multiatlas loader
    this.load.multiatlas('multiatlas', require('./sprites.json'), spriteFile.split('/').shift());  

All 10 comments

use code

function dataURLtoBlob(dataurl) {
    var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }

    return new Blob([u8arr], { type: mime });
}

const diamonds = require("./diamonds32x24x5")
const blob = dataURLtoBlob(diamonds)
var url = URL.createObjectURL(blob);

and

this.load.spritesheet('diamonds', url, { frameWidth: 32, frameHeight: 24 })

```typescript
export class BlobUtils {
public static base64ToURL(base64: string): string {
const blob = this.base64ToBlob(base64)
return URL.createObjectURL(blob)
}
public static base64ToBlob(base64: string): Blob {
var arr = base64.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
}
}

```typescript
function preload() {
    this.load.spritesheet(
        'diamonds',
        BlobUtils.base64ToURL(require("./diamonds32x24x5")),
        {
            frameWidth: 32,
            frameHeight: 24,
        },
    )
}

that is ok ,But there's a better way to do it?

Is there a good reason you want all your assets as data URIs? They are bigger, waste more space in your bundle, offer no compression benefits and generally slow things down as they have to be processed in and out of the string format to the final texture. There is literally no benefit to using them in a _game_.

In order to organize code and files better, images and other resources are easy to be forgotten when the content is more complex. But with code organization, it's easier to migrate and reuse.

I'm sorry, but this is such a bad practice to have all assets as base64 URLs to begin with that it's not something I'm going to natively support in the Loader. Your workaround above will have to be something you implement directly in your own code. But I would strongly suggest you spend the time sorting out a better workflow / file organisation structure for your projects instead.

3q . thanks!

I've been spending hours trying to work around this bug to use phaser as a library in another webpack project.

It's a bummer that phaser can't work easily with the most common HTML tooling - webpack.

Here are some workarounds in phaser and an example of a webpack config.

"Common" doesn't mean sensible or good practice. It's a terrible thing to use for games. Avoid it at all costs.

Hi Richard, when we're not building frameworks, we're using them.

And most of the time we're using them within the context of larger systems. And on the web, those larger systems will inevitably use webpack.

I get your strong judgements about asset loading and won't submit a PR.

There's nothing wrong with using webpack. Phaser 3 has been built with it from day 1. It doesn't mean it's sensible to use for binary game _assets_ though.

Fair enough. This is the top google result for the error. I misunderstood how both Phaser and Webpack work and it's been a challenge.

The two links above were helpful. The webpack !! syntax to override rules is also helpful.

const spriteFile = require('!!file-loader?name=[hash]/[name].[ext]!./sprites.png')

/*  
require('!!file-loader?name=[hash]/[name].[ext]!./sprites.png')
require('                                                    ') - emit a file and return a path string
         !!                                                     - turn off all webpack config for this require()
           file-loader                                          - write a file and return a path
                      ?name=[hash]/[name].[ext]                 - file-loader option: set file and path 
                                               !                - end webpack configuration
                                                ./sprites.png   - file to work on
*/

This was very helpful when trying to integrate a spritemap from TexturePacker: https://www.codeandweb.com/texturepacker/tutorials/how-to-create-sprite-sheets-for-phaser3

    // Sprites in files: ./sprites.png and ./sprites.json

    // this.load.multiatlas('multiatlas', jsonFile, pngDirectory);  
    // loader wants json and directory.  
    // sprites.json format hardcodes "sprites.png", so webpack can't change file name.

    // Webpack sprites.png -> [hash]/sprites.png
    const spriteFile = require('!!file-loader?name=[hash]/[name].[ext]!./sprites.png')

    // Use [hash] as last param to multiatlas loader
    this.load.multiatlas('multiatlas', require('./sprites.json'), spriteFile.split('/').shift());  
Was this page helpful?
0 / 5 - 0 ratings