Skip to content

Commit

Permalink
Add wms image raw implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
ger-benjamin committed Feb 19, 2024
1 parent b6b7a2e commit c7a0d38
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 59 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 0.2.4
- Move createReport to utils.
- Add **raw** encode support for WMS and Tile WMS layers.

## 0.2.3
- Add utility functions.
Expand Down
4 changes: 2 additions & 2 deletions demo/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ document.querySelector('#print').addEventListener('click', async () => {
*/
const mapSpec = await encoder.encodeMap({
map,
scale: 1,
printResolution: 96,
scale: 10000,
printResolution: map.getView().getResolution(),
dpi: 254,
customizer: customizer,
});
Expand Down
186 changes: 131 additions & 55 deletions src/MFPEncoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@ import {drawFeaturesToContext, createCoordinateToPixelTransform} from './mvtUtil

import TileLayer from 'ol/layer/Tile.js';
import WMTSSource from 'ol/source/WMTS.js';
import TileWMSSource from 'ol/source/TileWMS.js';
import OSMSource from 'ol/source/OSM.js';

import {getWidth as getExtentWidth, getHeight as getExtentHeight} from 'ol/extent.js';

import BaseCustomizer from './BaseCustomizer';
import type Map from 'ol/Map.js';
import type {MFPImageLayer, MFPLayer, MFPMap, MFPOSMLayer, MFPWmtsLayer} from './types';
import type {MFPImageLayer, MFPLayer, MFPMap, MFPOSMLayer, MFPWmtsLayer, MFPWmsLayer} from './types';
import type WMTS from 'ol/source/WMTS.js';

import type {Geometry} from 'ol/geom.js';
import type {State} from 'ol/layer/Layer.js';
import ImageLayer from 'ol/layer/Image.js';
import ImageWMSSource from 'ol/source/ImageWMS.js';
import {toDegrees} from 'ol/math.js';
import VectorTileLayer from 'ol/layer/VectorTile.js';
import VectorLayer from 'ol/layer/Vector.js';
Expand Down Expand Up @@ -89,7 +91,6 @@ export default class MFPBaseEncoder {

const layers: MFPLayer[] = [];
for (const layerState of layerStates) {
console.assert(printResolution !== undefined);
const spec = await this.encodeLayerState(layerState, printResolution, customizer);
if (spec) {
if (Array.isArray(spec)) {
Expand Down Expand Up @@ -123,65 +124,77 @@ export default class MFPBaseEncoder {
}
const layer = layerState.layer;

if (layer instanceof VectorTileLayer) {
return await this.encodeMVTLayerState(layerState, printResolution, customizer);
if (layer instanceof ImageLayer) {
return this.encodeImageLayerState(layerState, customizer);
}

if (layer instanceof TileLayer) {
return this.encodeTileLayerState(layerState, customizer);
} else if (layer instanceof VectorLayer) {
if (layer instanceof VectorLayer) {
const encoded = new VectorEncoder(layerState, customizer).encodeVectorLayer(printResolution)!;
const renderAsSvg = layer.get('renderAsSvg');
const renderAsSvg = layerState.layer.get('renderAsSvg');
if (renderAsSvg !== undefined) {
encoded.renderAsSvg = renderAsSvg;
}
return encoded;
}

if (layer instanceof TileLayer) {
return this.encodeTileLayerState(layerState, customizer);
}

if (layer instanceof VectorTileLayer) {
return await this.encodeMVTLayerState(layerState, printResolution, customizer);
}

return null;
}

/**
*
* @param layerState An MVT layer state
* @param printResolution
* @param customizer
* @return a spec fragment
* @returns An Encoded WMS Image layer from an Image Layer (high level method).
*/
async encodeMVTLayerState(
layerState: State,
printResolution: number,
customizer: BaseCustomizer,
): Promise<MFPLayer[] | MFPLayer | null> {
const layer = layerState.layer as VectorTileLayer;
const {MVTEncoder} = await import('@geoblocks/print');
const encoder = new MVTEncoder();
const printExtent = customizer.getPrintExtent();
const width = getExtentWidth(printExtent) / printResolution;
const height = getExtentHeight(printExtent) / printResolution;
const canvasSize: [number, number] = [width, height];
const printOptions = {
layer,
printExtent: customizer.getPrintExtent(),
tileResolution: printResolution,
styleResolution: printResolution,
canvasSize: canvasSize,
encodeImageLayerState(layerState: State, customizer: BaseCustomizer): MFPWmsLayer | null {
const layer = layerState.layer;
if (!(layer instanceof ImageLayer)) {
console.assert(layer instanceof ImageLayer);
}
const source = layer.getSource();
if (source instanceof ImageWMSSource) {
return this.encodeImageWmsLayerState(layerState, customizer);
}
return null;
}

/**
* @returns An Encoded WMS Image layer from an Image WMS Source (high level method).
*/
encodeImageWmsLayerState(layerState: State, customizer: BaseCustomizer) {
const layer = layerState.layer;
const source = layer.getSource() as ImageWMSSource;
console.assert(layer instanceof ImageWMSSource);
const url = source.getUrl();
if (url !== undefined) {
return this.encodeWmsLayerState(layerState, url, source.getParams(), customizer);
}
return null;
}

/**
* @returns An Encoded WMS Image layer from an Image WMS Source.
*/
encodeWmsLayerState(layerState: State, url: string, params: any, customizer: BaseCustomizer): MFPWmsLayer {
const layer = layerState.layer;
return {
name: layer.get('name'),
baseURL: url,
imageFormat: 'image/png',
layers: [''],
customParams: {},
serverType: 'mapserver',
type: 'wms',
opacity: layer.getOpacity(),
version: params.VERSION,
useNativeAngle: true,
styles: [''],
};
const results = await encoder.encodeMVTLayer(printOptions);
return results
.filter((resut) => resut.baseURL.length > 6)
.map(
(result) =>
Object.assign(
{
type: 'image',
name: layer.get('name'),
opacity: 1,
imageFormat: 'image/png',
},
result,
) as MFPLayer,
);
}

/**
Expand All @@ -190,17 +203,39 @@ export default class MFPBaseEncoder {
* @param customizer
* @return a spec fragment
*/
encodeTileLayerState(layerState: State, customizer: BaseCustomizer): MFPOSMLayer | MFPWmtsLayer {
encodeTileLayerState(
layerState: State,
customizer: BaseCustomizer,
): MFPOSMLayer | MFPWmtsLayer | MFPWmsLayer | null {
const layer = layerState.layer;
console.assert(layer instanceof TileLayer);
const source = layer.getSource();
if (source instanceof WMTSSource) {
return this.encodeTileWmtsLayer(layerState, customizer);
} else if (source instanceof OSMSource) {
return this.encodeTileWmtsLayerState(layerState, customizer);
}
if (source instanceof TileWMSSource) {
return this.encodeTileWmsLayerState(layerState, customizer);
}
if (source instanceof OSMSource) {
return this.encodeOSMLayerState(layerState, customizer);
} else {
return null;
}
return null;
}

/**
* Encodes a tiled WMS layerState as a MFPWmsLayer
* @param layerState
* @param customizer
* @return a spec fragment
*/
encodeTileWmsLayerState(layerState: State, customizer: BaseCustomizer): MFPWmsLayer {
const layer = layerState.layer;
console.assert(layer instanceof TileLayer);
const source = layer.getSource() as TileWMSSource;
console.assert(layer instanceof TileWMSSource);
const urls = source.getUrls();
console.assert(!!urls);
return this.encodeWmsLayerState(layerState, urls[0], source.getParams(), customizer);
}

/**
Expand All @@ -226,7 +261,7 @@ export default class MFPBaseEncoder {
* @param customizer
* @return a spec fragment
*/
encodeTileWmtsLayer(layerState: State, customizer: BaseCustomizer): MFPWmtsLayer {
encodeTileWmtsLayerState(layerState: State, customizer: BaseCustomizer): MFPWmtsLayer {
const layer = layerState.layer;
console.assert(layer instanceof TileLayer);
const source = layer.getSource()! as WMTS;
Expand Down Expand Up @@ -254,6 +289,48 @@ export default class MFPBaseEncoder {
return wmtsLayer;
}

/**
* @param layerState An MVT layer state
* @param printResolution
* @param customizer
* @return a spec fragment
*/
async encodeMVTLayerState(
layerState: State,
printResolution: number,
customizer: BaseCustomizer,
): Promise<MFPLayer[] | MFPLayer | null> {
const layer = layerState.layer as VectorTileLayer;
const {MVTEncoder} = await import('@geoblocks/print');
const encoder = new MVTEncoder();
const printExtent = customizer.getPrintExtent();
const width = getExtentWidth(printExtent) / printResolution;
const height = getExtentHeight(printExtent) / printResolution;
const canvasSize: [number, number] = [width, height];
const printOptions = {
layer,
printExtent: customizer.getPrintExtent(),
tileResolution: printResolution,
styleResolution: printResolution,
canvasSize: canvasSize,
};
const results = await encoder.encodeMVTLayer(printOptions);
return results
.filter((resut) => resut.baseURL.length > 6)
.map(
(result) =>
Object.assign(
{
type: 'image',
name: layer.get('name'),
opacity: 1,
imageFormat: 'image/png',
},
result,
) as MFPLayer,
);
}

/**
* Encodes Image layerState.
* @param layerState
Expand Down Expand Up @@ -289,14 +366,13 @@ export default class MFPBaseEncoder {
additionalDraw,
);

const spec: MFPImageLayer = {
return {
type: 'image',
extent: printExtent,
imageFormat: 'image/png', // this is the target image format in the mapfish-print
opacity: 1, // FIXME: mapfish-print is not handling the opacity correctly for images with dataurl.
name: layer.get('name'),
baseURL: asOpacity(this.scratchCanvas, layer.getOpacity()).toDataURL('PNG'),
};
return spec;
}
}
15 changes: 15 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,21 @@ export interface MFPWmtsLayer extends MFPLayer {
version: string;
}

export interface MFPWmsLayer extends MFPLayer {
type: 'wms';
baseURL: string;
imageFormat: string;
layers: string[];
customParams: Record<string, string>;
/** The server type ("mapserver", "geoserver" or "qgisserver"). */
serverType: string;
opacity: number;
version: string;
styles: string[];
/** For GeoServer, and MapServer, ask the map server to do the rotation. */
useNativeAngle: boolean;
}

export interface MFPImageLayer extends MFPLayer {
type: 'image';
extent: number[];
Expand Down
4 changes: 2 additions & 2 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ test('Empty map', async (t) => {
const result = await encoder.encodeMap({
map,
scale: 1,
printResolution: 96,
printResolution: map.getView().getResolution(),
dpi: 300,
customizer: customizer,
});
Expand Down Expand Up @@ -56,7 +56,7 @@ test('OSM map', async (t) => {
const spec = await encoder.encodeMap({
map,
scale: 1,
printResolution: 96,
printResolution: map.getView().getResolution(),
dpi: 254,
customizer: customizer,
});
Expand Down

0 comments on commit c7a0d38

Please sign in to comment.