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

Add wms image raw implementation #17

Merged
merged 1 commit into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
ger-benjamin marked this conversation as resolved.
Show resolved Hide resolved
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
Loading