arrays — передать изображение из c ++ в Haskell и получить строку назад

Я хочу вызвать функцию Haskell из c ++ с изображением в качестве параметра. Это просто массив без знака с информацией о ширине и высоте в пикселях.

Пока у меня есть этот рабочий код.

-- Stuff.hs

module Stuff where

import Data.List
import Data.Word
import qualified Data.Vector.Unboxed as V

import Foreign.Ptr
import Foreign.Storable
import Foreign.C.Types
import Foreign.C.String
import Foreign.Marshal.Array
import Foreign.Marshal.Alloc

foreign export ccall freeResult :: CString -> IO ()
foreign export ccall doWithImageStruct :: ImageStruct -> IO CString

data Image = Image Word32 Word32 (V.Vector Double)

type ImageStruct = Ptr ImageStructType

-- CUInt is Word32.
-- https://hackage.haskell.org/package/base-4.6.0.0/docs/Foreign-C-Types.html#t:CInt
data ImageStructType = ImageStructType CUInt CUInt (Ptr CUChar)

instance Storable ImageStructType where
sizeOf _ = 12
alignment = sizeOf
peek ptr = do
w <- peekByteOff ptr 0
h <- peekByteOff ptr 4
p <- peekByteOff ptr 8
return (ImageStructType w h p)

imageStructTypeToImage :: ImageStructType -> IO Image
imageStructTypeToImage (ImageStructType (CUInt width) (CUInt height) p) = do
pixelsCUChar <- peekArray (fromIntegral $ width * height) p
let pixels = map (\(CUChar c) -> fromIntegral c) pixelsCUChar
return $ Image width height (V.fromList pixels)

doWithImage :: Image -> String
doWithImage (Image w h p) =
intercalate " " [show w, show h, show $ V.sum p]

doWithImageStruct :: ImageStruct -> IO CString
doWithImageStruct is = do
imageStruct <- peek is
image <- imageStructTypeToImage imageStruct
newCString $ doWithImage image

freeResult :: CString -> IO ()
freeResult s = free s

а также

// StartEnd.c
#include <Rts.h>

void HsStart()
{
int argc = 1;
char* argv[] = {"ghcDll", NULL}; // argv must end with NULL

// Initialize Haskell runtime
char** args = argv;
hs_init(&argc, &args);
}

void HsEnd()
{
hs_exit();
}

Компилируется с

ghc -Wall -O2 -outputdir build -shared -o build\Stuff.dll Stuff.hs StartEnd.c

Часть cpp (MSVC 2010) выглядит следующим образом:

// main.cpp
// link with /OPT:NOREF

#pragma comment(lib,"Stuff.dll.a")
#include "HsFFI.h"#include "Stuff_stub.h"#include <cstdint>
#include <iostream>
#include <string>
#include <vector>

extern "C" {
void HsStart();
void HsEnd();
}

struct Image {
Image( std::uint32_t w, std::uint32_t h, std::uint8_t* p )
: width_( w ), height_( h ), pixels_( p )
{}
std::uint32_t width_;
std::uint32_t height_;
std::uint8_t* pixels_;
};

int main()
{
using namespace std;

HsStart();

// create image
const uint32_t width = 320;
const uint32_t height = 240;
vector<uint8_t> mem( width * height, 10 );
mem[1] = 13;
Image image( width, height, &mem[0] );

// Send Image to Haskell and receive a String.
auto resultPtr = doWithImageStruct( &image );
string result( reinterpret_cast<char*>( resultPtr ) );
freeResult( resultPtr );

cout << result << "\n";

HsEnd();
}

Результат, как и ожидалось:

320 240 768003.0

Мой вопрос: это правильный способ сделать это? Или это просто чистая удача, что он не падает прямо сейчас, и на самом деле у меня неопределенное поведение?

Редактировать: я исправил приведенный выше код, чтобы показать правильное использование фиксированных целых чисел битовой ширины для будущих читателей этого потока.

7

Решение

Я бы предложил вам использовать C-> Hs чтобы генерировать Storable ImageStructType пример. Все остальное выглядит хорошо.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]