Fabric.js seems limited to 2048 texture size despite using WebGL

Viewed 591

I'm setting up an app that allows the user to upload an image and make minor modifications (zoom, brightness, rotate, etc). I'm running into an issue with the brightness adjustment where Fabric.js just redraws a 2,048 x 2,048 segment of the image, rather than the entire thing. This is despite the max texture size being 16,384.

The image I'm uploading is large (5,400 x 3,600), but that's on purpose. These days even cell phones have high resolution cameras, so I need to be prepared for users to upload large images.

I found that if I randomly resize the image down by .5 as soon as it's loaded, then the brightness adjustment works just fine. That's not the end of the world - but I need to know how far to resize any image upon receipt. So is there a way to calculate the current texture size and then resize it down to something I can be sure Fabric.js will handle? I thought the current texture size could be the larger of either the pixel width or height of the image, but something must be wrong there, because my current image would be 5,400 which is well below the max of 16,384 (and resizing it by half would bring it down to 2,700, which is still above 2,048, but this actually works).

Any ideas on how to either:

  1. determine how far to resize the image so Fabric.js can handle it
  2. or, get Fabric.js to use the max texture size (since it seems to be ignoring it)

Here are some code snippets..

var FabricCanvas = new fabric.Canvas('FabricCanvas');

// image file upload handler
jQuery(".FabricPhotoUpload").on("change", function( event_change ) {
   var reader = new FileReader();
   reader.onload = function ( event_onload ) {
      var imgObj = new Image();
      imgObj.src = event.target.result;
      imgObj.onload = function () {
         var FabricImage = new fabric.Image(imgObj);
         FabricImage.set({ angle: 0, top: 0, left: 0 });
         fabric.filterBackend = fabric.initFilterBackend();
         if ( fabric.isWebglSupported() ) {
            fabric.textureSize = fabric.maxTextureSize;
         }
         FabricCanvas.add(FabricImage);
         FabricCanvas.renderAll();
      }
   }
   reader.readAsDataURL( event_change.target.files[0] );
   event_change.target.value = "";
});

// using jQueryUI for the brightness slider
window.FabricSliderMax_Bright = 50;
jQuery( ".FabricBrightness" ).slider({
   slide: function( event, ui ) {
      var NewBrightness = ui.value / window.FabricSliderMax_Bright;
      // for now I'm assuming FabricImage.filters[0] is the brightness filter
      if ( typeof( FabricImage.filters[0] ) == "undefined" ) {
         FabricImage.filters[0] = new fabric.Image.filters.Brightness({ brightness: NewBrightness });
      } else {
         FabricImage.filters[0].brightness = NewBrightness;
      }

      FabricImage.applyFilters();
      FabricCanvas.renderAll();
   },
   max: window.FabricSliderMax_Bright,
   min: -50,
   value: 1
});

2 Answers

I too am playing with maxTextureSize. I have not yet determined if there is a valid method to [pre]determine the hardware's limit for all platforms, but you can set it directly;

    if (fabric.isWebglSupported()) fabric.textureSize = 65536;

I suspect it definitely needs to be at the least mod4 (4 bytes per pixel) ... but whether the increments can be less than 1k, I have yet to determine.

I've found that I need to first init the filter backend, then set the max texture size, then re-init the filter backend again. I'm not sure if this will work for everyone or not, but it fixed the issue for me:

// @ts-ignore
fabric.filterBackend = fabric.initFilterBackend(); //this will init WebGL
// @ts-ignore
fabric.textureSize = fabric.maxTextureSize; //allows for larger images

//This will re-init WebGL with the larger image textureSize.
//  For some reason we need this extra re-init.
//  Otherwise we get an error about 'RangeError out-of-bounds Uint8Array on ArrayBuffer'
// @ts-ignore
fabric.filterBackend = fabric.initFilterBackend();
Related