使用Apache发布PostGIS数据库存储的栅格影像

前面有使用Node.js读取存储在PostGIS数据库中栅格影像发布xyz服务的文章,这篇是Apache版本。性能还需要优化直接上代码:

cpp 复制代码
#ifndef TILE_DATABASE_HANDLER_H
#define TILE_DATABASE_HANDLER_H

#include <libpq-fe.h>
#include <stdlib.h>

typedef struct {
    PGconn* conn;
} TileDatabaseHandler;

// Create and initialize the TileDatabaseHandler
TileDatabaseHandler* createTileDatabaseHandler();

// Destroy the TileDatabaseHandler and free its resources
void destroyTileDatabaseHandler(TileDatabaseHandler* handler);

// Get the tile data from the database given z, x, y coordinates
char* getTile(TileDatabaseHandler* handler, int z, int x, int y, size_t* dataLength);

#endif // TILE_DATABASE_HANDLER_H
cpp 复制代码
#include "TileDatabaseHandler.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

// Function to create and initialize TileDatabaseHandler
TileDatabaseHandler* createTileDatabaseHandler() {
    TileDatabaseHandler* handler = (TileDatabaseHandler*)malloc(sizeof(TileDatabaseHandler));
    if (!handler) {
        return NULL;
    }

    // Connection string
    const char* conninfo = "host=192.168.101.201 port=4321 dbname=Tile user=postgres password=root";

    // Establish connection to the database
    handler->conn = PQconnectdb(conninfo);

    // Check to ensure the connection was successful
    if (PQstatus(handler->conn) != CONNECTION_OK) {
        fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(handler->conn));
        destroyTileDatabaseHandler(handler);
        return NULL;
    }

    return handler;
}

// Function to destroy the TileDatabaseHandler and free its resources
void destroyTileDatabaseHandler(TileDatabaseHandler* handler) {
    if (handler) {
        if (handler->conn) {
            PQfinish(handler->conn);
        }
        free(handler);
    }
}

// Function to get tile data from the database given z, x, y coordinates
char* getTile(TileDatabaseHandler* handler, int z, int x, int y, size_t* dataLength) {
    if (!handler || !handler->conn) return NULL;

    const char* queryTemplate = "SELECT data FROM Tile WHERE z = $1 AND x = $2 AND y = $3";

    // Allocate memory for query parameters
    //const int paramCount = 3;
    const char* params[3];
    char zStr[12];
    char xStr[22];
    char yStr[22];

    snprintf(zStr, sizeof(zStr), "%d", z - 1);
    snprintf(xStr, sizeof(xStr), "%ld", (long)x);
    snprintf(yStr, sizeof(yStr), "%ld", (long)y);

    params[0] = zStr;
    params[1] = xStr;
    params[2] = yStr;

    // Execute the query
    PGresult* res = PQexecParams(handler->conn, queryTemplate, 3, NULL, params, NULL, NULL, 1);

    if (PQresultStatus(res) != PGRES_TUPLES_OK) {
        fprintf(stderr, "SELECT failed: %s", PQerrorMessage(handler->conn));
        PQclear(res);
        return NULL;
    }

    // Check if we have any result
    if (PQntuples(res) == 0) {
        PQclear(res);
        return NULL;
    }

    // Get the length of the data
    *dataLength = PQgetlength(res, 0, 0);
    if (*dataLength == 0) {
        PQclear(res);
        return NULL;
    }

    // Allocate memory for the tile data
    char* tileData = (char*)malloc(*dataLength);
    if (!tileData) {
        PQclear(res);
        return NULL;
    }

    // Copy the binary data to tileData buffer
    memcpy(tileData, PQgetvalue(res, 0, 0), *dataLength);

    // Clear the result to free memory
    PQclear(res);

    return tileData;
}
cpp 复制代码
#include "httpd.h"
#include "http_log.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <apr_pools.h>
#include <apr_tables.h>
#include <apr_strings.h>

// Include the C header for the TileDatabaseHandler functions
#include "TileDatabaseHandler.h"

// A wrapper to handle database context in C code

typedef struct {
    TileDatabaseHandler* dbHandler;  // Database handler struct
    char* tileDataBuffer;            // Buffer to hold the tile data
    size_t tileDataLength;           // Length of the tile data
} tilehandler_context;

tilehandler_context* create_tilehandler_context() {
    tilehandler_context* context = (tilehandler_context*)malloc(sizeof(tilehandler_context));
    if (context) {
        context->dbHandler = createTileDatabaseHandler();
        context->tileDataBuffer = NULL;
        context->tileDataLength = 0;
    }
    return context;
}

void destroy_tilehandler_context(tilehandler_context* context) {
    if (context) {
        if (context->tileDataBuffer) {
            free(context->tileDataBuffer);
        }
        destroyTileDatabaseHandler(context->dbHandler);
        free(context);
    }
}

// Get tile data and its length
const char* get_tile_data(tilehandler_context* context, int z, int x, int y) {
    if (!context) return NULL;

    if (context->tileDataBuffer) {
        free(context->tileDataBuffer);
        context->tileDataBuffer = NULL;
    }

    // Assuming getTile is modified to return BLOB data and its length
    context->tileDataBuffer = getTile(context->dbHandler, z, x, y, &(context->tileDataLength));
    if (!context->tileDataBuffer || context->tileDataLength == 0) {
        return NULL;
    }

    return context->tileDataBuffer;
}

/* The sample content handler */
static int tilehandler_module_handler(request_rec* r) {
    if (strcmp(r->handler, "tilehandler_module")) {
        return DECLINED;
    }

    if (r->method_number != M_GET) {
        return HTTP_METHOD_NOT_ALLOWED;
    }

    int z, x, y;
    // Extract coordinates from the URI, removing possible file extension
    if (sscanf(r->uri, "/tiles/%d/%d/%d", &z, &x, &y) != 3) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Failed to parse URI: %s", r->uri);
        return HTTP_BAD_REQUEST;
    }

    // Create context
    tilehandler_context* context = create_tilehandler_context();
    if (!context) {
        return HTTP_INTERNAL_SERVER_ERROR;
    }

    const char* tileData = get_tile_data(context, z, x, y);

    if (tileData && context->tileDataLength > 0) {
        // Set correct MIME type based on your image format
        ap_set_content_type(r, "image/jpeg"); // Change to "image/png" if needed

        // Set Content-Length header
        apr_table_setn(r->headers_out, "Content-Length", apr_psprintf(r->pool, "%zu", context->tileDataLength));

        // Write the image data
        ap_rwrite(tileData, context->tileDataLength, r);
    }
    else {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Tile not found for z=%d, x=%d, y=%d", z, x, y);
        ap_set_content_type(r, "text/plain");
        ap_rprintf(r, "Tile not found");
        destroy_tilehandler_context(context);
        return HTTP_NOT_FOUND;
    }

    destroy_tilehandler_context(context);
    return OK;
}

static void tilehandler_module_register_hooks(apr_pool_t* p) {
    ap_hook_handler(tilehandler_module_handler, NULL, NULL, APR_HOOK_MIDDLE);
}

/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA tilehandler_module = {
    STANDARD20_MODULE_STUFF,
    NULL,                  /* create per-dir    config structures */
    NULL,                  /* merge  per-dir    config structures */
    NULL,                  /* create per-server config structures */
    NULL,                  /* merge  per-server config structures */
    NULL,                  /* table of config file commands       */
    tilehandler_module_register_hooks  /* register hooks                      */
};
相关推荐
白水先森2 小时前
ArcGIS Pro热力图制作指南:从基础到进阶
经验分享·arcgis·信息可视化
夜泉_ly2 小时前
MySQL -安装与初识
数据库·mysql
qq_529835353 小时前
对计算机中缓存的理解和使用Redis作为缓存
数据库·redis·缓存
StickToForever4 小时前
第4章 信息系统架构(五)
经验分享·笔记·学习·职场和发展
月光水岸New5 小时前
Ubuntu 中建的mysql数据库使用Navicat for MySQL连接不上
数据库·mysql·ubuntu
狄加山6755 小时前
数据库基础1
数据库
我爱松子鱼5 小时前
mysql之规则优化器RBO
数据库·mysql
chengooooooo6 小时前
苍穹外卖day8 地址上传 用户下单 订单支付
java·服务器·数据库
Rverdoser7 小时前
【SQL】多表查询案例
数据库·sql
Galeoto7 小时前
how to export a table in sqlite, and import into another
数据库·sqlite