使用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                      */
};
相关推荐
Dxy1239310216几秒前
python下载pdf
数据库·python·pdf
小钱c735 分钟前
Mac下安装Apache JMeter并启动
jmeter·macos·apache
桀桀桀桀桀桀43 分钟前
数据库中的用户管理和权限管理
数据库·mysql
天行健PLUS1 小时前
【经验分享】六西格玛管理培训适合哪些人参加?
经验分享
小奥超人2 小时前
PPT文件设置了修改权限,如何取消权?
windows·经验分享·microsoft·ppt·办公技巧
superman超哥2 小时前
04 深入 Oracle 并发世界:MVCC、锁、闩锁、事务隔离与并发性能优化的探索
数据库·oracle·性能优化·dba
用户8007165452002 小时前
HTAP数据库国产化改造技术可行性方案分析
数据库
engchina3 小时前
Neo4j 和 Python 初学者指南:如何使用可选关系匹配优化 Cypher 查询
数据库·python·neo4j
engchina3 小时前
使用 Cypher 查询语言在 Neo4j 中查找最短路径
数据库·neo4j
尘浮生3 小时前
Java项目实战II基于Spring Boot的光影视频平台(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·后端·maven·intellij-idea