使用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                      */
};
相关推荐
The_Ticker3 分钟前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程
Elastic 中国社区官方博客9 分钟前
Elasticsearch 开放推理 API 增加了对 IBM watsonx.ai Slate 嵌入模型的支持
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
企鹅侠客14 分钟前
ETCD调优
数据库·etcd
Json_1817901448020 分钟前
电商拍立淘按图搜索API接口系列,文档说明参考
前端·数据库
煎饼小狗31 分钟前
Redis五大基本类型——Zset有序集合命令详解(命令用法详解+思维导图详解)
数据库·redis·缓存
永乐春秋1 小时前
WEB-通用漏洞&SQL注入&CTF&二次&堆叠&DNS带外
数据库·sql
打鱼又晒网1 小时前
【MySQL】数据库精细化讲解:内置函数知识穿透与深度学习解析
数据库·mysql
大白要努力!1 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
tatasix2 小时前
MySQL UPDATE语句执行链路解析
数据库·mysql
南城花随雪。2 小时前
硬盘(HDD)与固态硬盘(SSD)详细解读
数据库