使用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                      */
};
相关推荐
铁匠匠匠1 小时前
从零开始学数据结构系列之第六章《排序简介》
c语言·数据结构·经验分享·笔记·学习·开源·课程设计
高兴就好(石2 小时前
DB-GPT部署和试用
数据库·gpt
这孩子叫逆2 小时前
6. 什么是MySQL的事务?如何在Java中使用Connection接口管理事务?
数据库·mysql
Karoku0662 小时前
【网站架构部署与优化】web服务与http协议
linux·运维·服务器·数据库·http·架构
码农郁郁久居人下2 小时前
Redis的配置与优化
数据库·redis·缓存
天玑y3 小时前
算法设计与分析(背包问题
c++·经验分享·笔记·学习·算法·leetcode·蓝桥杯
MuseLss4 小时前
Mycat搭建分库分表
数据库·mycat
Hsu_kk4 小时前
Redis 主从复制配置教程
数据库·redis·缓存
DieSnowK4 小时前
[Redis][环境配置]详细讲解
数据库·redis·分布式·缓存·环境配置·新手向·详细讲解
程序猿小D4 小时前
第二百三十五节 JPA教程 - JPA Lob列示例
java·数据库·windows·oracle·jdk·jpa