Coder Social home page Coder Social logo

hongfaqiu / tiffimageryprovider Goto Github PK

View Code? Open in Web Editor NEW
44.0 3.0 8.0 13.77 MB

Load GeoTIFF/COG(Cloud optimized GeoTIFF) on Cesium

Home Page: https://tiff-imagery-provider.opendde.com/?panel=layer

License: MIT License

TypeScript 92.17% JavaScript 0.81% SCSS 6.85% HTML 0.14% CSS 0.04%
cesium cog geotiff tif tiff nextjs web-worker webgl

tiffimageryprovider's Introduction

TIFFImageryProvider

Load GeoTIFF/COG(Cloud optimized GeoTIFF) on Cesium

gzip size npm latest version license

中文readme

CodeSandbox

Features

  • Three band rendering.
  • Multi mode color rendering.
  • Support identify TIFF value with cartographic position.
  • WebGL accelerated rendering.
  • Band calculation.
  • [experimental] Support any projected TIFF .

Install

#npm
npm install --save tiff-imagery-provider

#yarn
yarn add tiff-imagery-provider

#pnpm
pnpm add tiff-imagery-provider

Usage

Basic

import { Viewer } from "cesium";
import TIFFImageryProvider from 'tiff-imagery-provider';

const cesiumViewer = new Viewer("cesiumContainer");

const provider = await TIFFImageryProvider.fromUrl('https://oin-hotosm.s3.amazonaws.com/56f9b5a963ebf4bc00074e70/0/56f9c2d42b67227a79b4faec.tif');

cesiumViewer.imageryLayers.addImageryProvider(provider);

You can also use the New keyword to create a new TIFFimageryProvider, which was deprecated after [email protected]+

const provider = new TIFFImageryProvider({
  url: YOUR_TIFF_URL,
});
provider.readyPromise.then(() => {
  cesiumViewer.imageryLayers.addImageryProvider(provider);
})

Experimental If TIFF's projection is not EPSG:4326 or EPSG:3857, you can pass the projFunc to handle the projection

import proj4 from 'proj4';

TIFFImageryProvider.fromUrl(YOUR_TIFF_URL, {
  projFunc: (code) => {
    if (code === 32760) {
      proj4.defs("EPSG:32760", "+proj=utm +zone=60 +south +datum=WGS84 +units=m +no_defs +type=crs");
      return {
        project: proj4("EPSG:4326", "EPSG:32760").forward,
        unproject: proj4("EPSG:4326", "EPSG:32760").inverse
      }
    }
  }
});

Band calculation

// NDVI
TIFFImageryProvider.fromUrl(YOUR_TIFF_URL, {
  renderOptions: {
    single: {
      colorScale: 'rainbow',
      domain: [-1, 1],
      expression: '(b1 - b2) / (b1 + b2)'
    }
  }
});

Custom colors

TIFFImageryProvider.fromUrl(YOUR_TIFF_URL, {
  renderOptions: {
    single: {
      "colors": [
        [1, "rgb(154, 206, 127)"],
        [2, "rgb(163, 214, 245)"],
        [3, "rgb(255, 251, 177)"],
        [4, "rgb(193, 114, 97)"],
        [5, "rgb(220, 100, 120)"],
        [6, "rgb(49, 173, 105)"]
      ],
      type: "discrete",
      useRealValue: true // use real value in colors stops
    }
  }
});

API

class TIFFImageryProvider {
  ready: boolean;
  readyPromise: Promise<void>
  bands: Record<number, {
    min: number;
    max: number;
  }>;
  origin: number[];
  reverseY: boolean;
  samples: number;
  constructor(options: TIFFImageryProviderOptions & {
    /** 
     * @deprecated 
     * Deprecated after [email protected]+, you can use fromUrl instead
     * @example 
     * const provider = await TIFFImageryProvider.fromUrl(url)
     */
    url?: string | File | Blob;
  });

  get isDestroyed(): boolean;
  destroy(): void;
  
  static fromUrl(url: string | File | Blob, options?: TIFFImageryProviderOptions): Promise<TIFFImageryProvider>;
}

interface TIFFImageryProviderOptions {
  requestOptions?: {
    /** defaults to false */
    forceXHR?: boolean;
    headers?: Record<string, any>;
    credentials?: boolean;
    /** defaults to 0 */
    maxRanges?: number;
    /** defaults to false */
    allowFullFile?: boolean;
    [key: string]: any;
  };
  credit?: string;
  tileSize?: number;
  maximumLevel?: number;
  minimumLevel?: number;
  enablePickFeatures?: boolean;
  hasAlphaChannel?: boolean;
  renderOptions?: TIFFImageryProviderRenderOptions;
  /**
   * If TIFF's projection is not EPSG:4326 or EPSG:3857, you can pass the ``projFunc`` to handle the projection
   * @experimental
   */
  projFunc?: (code: number) => {
    /** projection function, convert [lon, lat] position to [x, y] */
    project: ((pos: number[]) => number[]);
    /** unprojection function, convert [x, y] position to [lon, lat] */
    unproject: ((pos: number[]) => number[]);
  } | undefined;
  /** cache survival time, defaults to 60 * 1000 ms */
  cache?: number;
  /** geotiff resample method, defaults to nearest */
  resampleMethod?: 'nearest' | 'bilinear' | 'linear';
}

type TIFFImageryProviderRenderOptions = {
  /** nodata value, default read from tiff meta */
  nodata?: number;
  /** Only valid for three band rendering, defaults to { 'black': 'transparent' } */
  colorMapping?: Record<string, string>;
  /** try to render multi band cog to RGB, priority 1 */
  convertToRGB?: boolean;
  /** priority 2 */
  multi?: MultiBandRenderOptions;
  /** priority 3 */
  single?: SingleBandRenderOptions;
}

interface SingleBandRenderOptions {
  /** band index start from 1, defaults to 1 */
  band?: number;

  /**
   * The color scale image to use.
   */
  colorScaleImage?: HTMLCanvasElement | HTMLImageElement;

  /**
   * The name of a named color scale to use.
   */
  colorScale?: ColorScaleNames;

  /** custom interpolate colors, [stopValue(0 - 1), color] or [color], if the latter, means equal distribution 
   * @example
   * [[0, 'red'], [0.6, 'green'], [1, 'blue']]
  */
  colors?: [number, string][] | string[];

  /** Determine whether to use the true value range for custom color ranges, defaults to false */
  useRealValue?: boolean;

  /** defaults to continuous */
  type?: 'continuous' | 'discrete';

  /**
   * The value domain to scale the color.
   */
  domain?: [number, number];

  /**
   * Range of values that will be rendered, values outside of the range will be transparent.
   */
  displayRange?: [number, number];

  /**
   * Set if displayRange should be used.
   */
  applyDisplayRange?: boolean;

  /**
   * Whether or not values below the domain shall be clamped.
   */
  clampLow?: boolean;

  /**
   * Whether or not values above the domain shall be clamped (if not defined defaults to clampLow value).
   */
  clampHigh?: boolean;
  
  /**
   * Sets a mathematical expression to be evaluated on the plot. Expression can contain mathematical operations with integer/float values, band identifiers or GLSL supported functions with a single parameter.
   * Supported mathematical operations are: add '+', subtract '-', multiply '*', divide '/', power '**', unary plus '+a', unary minus '-a'.
   * Useful GLSL functions are for example: radians, degrees, sin, asin, cos, acos, tan, atan, log2, log, sqrt, exp2, exp, abs, sign, floor, ceil, fract.
   * Don't forget to set the domain parameter!
   * @example 
   * '-2 * sin(3.1415 - b1) ** 2'
   * '(b1 - b2) / (b1 + b2)'
   */
  expression?: string;
}

interface MultiBandRenderOptions {
  /** Band value starts from 1 */
  r?: {
    band: number;
    min?: number;
    max?: number;
  };
  g?: {
    band: number;
    min?: number;
    max?: number;
  };
  b?: {
    band: number;
    min?: number;
    max?: number;
  };
}


/** see https://observablehq.com/@d3/color-schemes */
type ColorScaleNames = 'viridis' | 'inferno' | 'turbo' | 'rainbow' | 'jet' | 'hsv' | 'hot' | 'cool' | 'spring' | 'summer' | 'autumn' | 'winter' | 'bone' | 'copper' | 'greys' | 'ylgnbu' | 'greens' | 'ylorrd' | 'bluered' | 'rdbu' | 'picnic' | 'portland' | 'blackbody' | 'earth' | 'electric' | 'magma' | 'plasma' | 'redblue' | 'coolwarm' | 'diverging_1' | 'diverging_2' | 'blackwhite' | 'twilight' | 'twilight_shifted';

Demo

online Demo

  • Powered by Next.js.
  • Dark mode with Semi-UI.
  • Simple cog custom render method.

Launch the app in the demo folder, and then visit http://localhost:3000/

pnpm install
cd example
pnpm dev
screenshot.png classify.png landsat.png

Plans

  • GPU speed up calculation
  • More efficient tile request method

Credits

https://github.com/geotiffjs/geotiff.js

https://github.com/santilland/plotty

tiffimageryprovider's People

Contributors

hongfaqiu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

tiffimageryprovider's Issues

TypeError: Cannot read properties of undefined (reading 'hasAlphaChannel')

static async fromUrl(url: string | File | Blob, options?: TIFFImageryProviderOptions) {

When i use this code to load tiff, it is error.
code:

const provider = await TIFFImageryProvider.fromUrl(url);
viewer.imageryLayers.addImageryProvider(provider);

error info:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'hasAlphaChannel')
at new TIFFImageryProvider (TIFFImageryProvider.ts:172:36)
at TIFFImageryProvider.<anonymous> (TIFFImageryProvider.ts:362:22)
at Generator.next (<anonymous>)
at tslib.es6.js:121:71
at new Promise (<anonymous>)
at __awaiter (tslib.es6.js:117:12)
at TIFFImageryProvider.fromUrl (TIFFImageryProvider.ts:361:87)

The reason for the error is that i didn't pass in options, so it is undefined , but the TIFFImageryProvider function need its attributes.

static async fromUrl(url: string | File | Blob, options?: TIFFImageryProviderOptions) {
    const provider = new TIFFImageryProvider(options);
    await provider._build(url, options)
    
    return provider;
  }

so may be you can change the source code like this:

static async fromUrl(url: string | File | Blob, options?: TIFFImageryProviderOptions) {
    if(options === undefined){
     options = {};
   }
    const provider = new TIFFImageryProvider(options);
    await provider._build(url, options)
    
    return provider;
  }

"No data" areas show as solid black instead of transparent when using convertToRGB true or multi-band

Great library! Struggling on one issue, I have a number of multi-band RGB TIFFs I'm trying to render but I can't seem to find a way to get the "empty" no data area to just be transparent so that the background shows through. Instead, it is always solid black - presumably because the RGB value across the bands is 0 / 0 / 0.

As an example, here's what I see using TIFFImageryProvider in Cesium:
image

Here is what I see for the same image using QGIS which is setup by default to use "No Color" for the no data values, so these no data areas just display the layer beneath rather than solid black:
image

If I change the QGIS No Data color to black, I get a result that looks like the TIFFImageryProvider in Cesium which is what makes me think TIFFImageryProvider must be using rgb(0,0,0) for the no data color:

image

Any help greatly appreciated! Thank you.

ArrayBuffer Exception

Thanks for the library @hongfaqiu. I have an issue that when i try to upload tiff file, it does not show up and then a few seconds later RangeError: Array buffer allocation failed error is thrown. How can i fix this?

image

Seems like display range is not applied when expression is applied

I'm rendering an NDVI index map from multiband geotiff using single mode with expression and domain parameters configured and everything works perfect.

However when I add displayRange configuration (with applyDisplayRange = true of course) it does not effects visualization at all. The value of domain parameter in my case is equal to [0, 1] and the value of displayRange parameter is equal to [0.5, 0.8]

Am I doing something wrong or expression is not compatible with displayRange?

Thanks in advance.

实现轮播效果时,如果使用blob方式加载图像,16次后webgl会崩溃

出现
WARNING: Too many active WebGL contexts. Oldest context will be lost.

然后出现
TypeError: Cannot read properties of null (reading 'createShader')

at createProgram (index.js:1122:1)
at new plot (index.js:1334:1)
at TIFFImageryProvider.eval (index.js:2156:1)
at Generator.next ()
at fulfilled (index.js:22:1)

`let i = 0;
window.setInterval(async () => {

      that.viewer.imageryLayers.remove(baseImagelayer);
      baseProvider.destroy();

      imageBlob = null;
      
      imageBlob = await axios.get('http://localhost/api/file/export/734615026031136768.TIF', {
        responseType: "blob"
      });

      baseProvider = new TIFFImageryProvider({            
        url: imageBlob.data,
        renderOptions: {
          nodata: -999,
          single: {
            colorScale: "jet",
            //colorScaleImage: image,
            domain: [0, 80],
          }
        }, 
        enablePickFeatures: true,
        //resampleMethod: 'bilinear',
      });
      baseImagelayer = new Cesium.ImageryLayer(baseProvider); 
      that.viewer.imageryLayers.add(baseImagelayer);

      i++;
      console.log(i);
    },2000);`

TypeError: Cannot read properties of undefined (reading 'nodata')

When loading any .tiff file as proposed in a readme file:

provider.readyPromise().then(() => {
  cesiumViewer.imageryLayers.addImageryProvider(provider);
})

,I always get the error:

caught (in promise) TypeError: Cannot read properties of undefined (reading 'nodata')
    at TIFFImageryProvider.eval (index.js:2031:55)
    at Generator.next (<anonymous>)
    at fulfilled (index.js:39:58)

I am handling this issue by specifying the bands numbers and there min and max values in renderOptions. Is there some additional preprocessing in the demo that is missing in the library, because I never face this issue when working with demo?

Cannot Open TIF File from Local

error

When I write the code below I faced up with this issue. I saw your comment in one of your issues "Alignment issues when source cog is in non-native projection #16 " that I switch to "WebMercatorTilingScheme" from tileXYToRectangle. And I thought you forgot to update the repo. Could you help me with this issue.

const provider = TIFFImageryProvider.fromUrl("https://stafs-cogs.s3.ap-southeast-2.amazonaws.com/Whian_Whian_TCI_4326_cog.tif");
viewer.imageryLayers.addImageryProvider(provider); 

provider.readyPromise is not a function

When loading any .tiff file as proposed in a readme file:

provider.readyPromise().then(() => {
  cesiumViewer.imageryLayers.addImageryProvider(provider);
})

,I always get the error:

caught TypeError: provider.readyPromise is not a function
    at eval (index.js:33:10)
    at ./src/index.js (app.js:1702:1)
    at __webpack_require__ (app.js:13123:33)
    at app.js:14328:37
    at app.js:14330:12

I'am using Cesium 1.99 so this should not be a problem with deprecated API.

Mulitband raster algebra

In the version 2.2.1 an expression parameter has been added to single rendering mode allowing to perform raster algebra with a selected band before rendering.

If I may I would like to suggest that it would be just great to have an ability to perform raster algebra operations with several band of a .tiff file in future versions. This feature will open unlimited possibilities for agriculture, forestry, ecology and users from other industries who are used to work with indexes like NDVI / NDRE e.t.c.

GeoTIFFImage.getTileOrStrip Fail when rendering large multiband tiff file

When rendering 5 band 3.9 Gb .tiff file in multi mode the error described below often occurs. Looks like it does not lead to anything bad, but I decided to report it for further investigation if required.

index.js:2292 AggregateError: Request failed
    at BlockedSource.fetch (blockedsource.js:160:13)
    at async GeoTIFFImage.getTileOrStrip (geotiffimage.js:396:20)
    at async Promise.all (:8081/index 0)
    at async GeoTIFFImage._readRaster (geotiffimage.js:528:5)
    at async GeoTIFFImage.readRasters (geotiffimage.js:622:20)

Data to reproduce the issue on Google Drive.

2.9.5版本默认加载数据颠倒

从低版本升级到2.9.5版本,
发现正常加载的数据在该版本下颠倒,
怀疑跟2.9.5新增加的
SingleBandRenderOptions 属性有关
reverseY: boolean = false;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.