使用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                      */
};
相关推荐
f***019322 分钟前
【MySQL】JDBC的连接
数据库·mysql
5***T44823 分钟前
开启mysql的binlog日志
数据库·mysql
q***333741 分钟前
UNION 和 UNION ALL 的区别:深入解析 SQL 中的合并操作
数据库·sql·oracle
郑重其事,鹏程万里44 分钟前
关系型数据库(derby)
数据库
Elastic 中国社区官方博客1 小时前
使用 A2A 协议和 MCP 在 Elasticsearch 中创建一个 LLM agent 新闻室:第二部分
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
孤廖1 小时前
终极薅羊毛指南:CLI工具免费调用MiniMax-M2/GLM-4.6/Kimi-K2-Thinking全流程
人工智能·经验分享·chatgpt·ai作画·云计算·无人机·文心一言
秋邱1 小时前
价值升维!公益赋能 + 绿色技术 + 终身学习,构建可持续教育 AI 生态
网络·数据库·人工智能·redis·python·学习·docker
郑重其事,鹏程万里1 小时前
关系型数据库(h2)
数据库
空空kkk1 小时前
MyBatis——代理Dao方式的增删改查操作
java·数据库·mybatis
Croa-vo2 小时前
TikTok 数据工程师三轮 VO 超详细面经:技术深挖 + 建模推导 + 压力测试全记录
javascript·数据结构·经验分享·算法·面试