ctypes Arraypointer

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
Antworten
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Ich habe eine C-Funktion:

Code: Alles auswählen

typedef unsigned char u8;

Compress( u8 const* rgba, void* block, int flags )
Wobei die Funktion `rgba` entgegen nimmt und in `block` das Ergebnis "speichert", in C wäre das einfach, ich passe einfach ein Array aus `unsigned char`s und benutzte `malloc` um genügend speicher für `block` zu reservieren.

Nur wie mache ich das mit Ctypes?
Ich habe einen String, welcher den Inhalt für `rgba` enthält (wird aus einer Datei gelesen). Wie passe ich das nun mit ctypes als c_ubyte?
Und wie reserviere ich genügend speicher für `block` (ich weiß im vornherein wie viel Speicher benötigt wird).
the more they change the more they stay the same
BlackJack

@Dav1d: Für `rgba` erstellst Du aus dem `str` mit `ctypes.create_string_buffer()` ein Array. Für den Rückgabewert kannst Du das gleiche machen, nur mit der Grösse als Argument statt den Daten.
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Oh na klar, ist je egal ob unsigned oder nicht, die C-Funktion behandelt es als unsigned und somit ist das gut. Danke
the more they change the more they stay the same
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Mache ich es falsch?

Code: Alles auswählen

#include <squish.h>

typedef unsigned char u8;

extern "C" {
	void CompressMasked( u8 const* rgba, int mask, void* block, int flags ) {
		squish::CompressMasked(rgba, mask, block, flags);
	}

	void Compress( u8 const* rgba, void* block, int flags ) {
		squish::Compress(rgba, block, flags);
	}

	void Decompress( u8* rgba, void const* block, int flags ) {
		squish::Decompress(rgba, block, flags);
	}

	int GetStorageRequirements( int width, int height, int flags ) {
		return squish::GetStorageRequirements(width, height, flags);
	}

	void CompressImage( u8 const* rgba, int width, int height, void* blocks, int flags ) {
		squish::CompressImage(rgba, width, height, blocks, flags);
	}

	void DecompressImage( u8* rgba, int width, int height, void const* blocks, int flags ) {
		squish::DecompressImage(rgba, width, height, blocks, flags);
	}
}

Code: Alles auswählen

from ctypes import CDLL, c_int, byref, create_string_buffer
import os.path

libsquish_path = os.path.join(os.path.split(os.path.abspath(__file__))[0], 'libsquishc.so')
libsquish = CDLL(libsquish_path)

DXT1 = 1 << 0 
DXT3 = 1 << 1 
DXT5 = 1 << 2 

COLOR_ITERATIVE_CLUSTER_FIT = 1 << 8    
COLOR_CLUSTER_FIT = 1 << 3    
COLOR_RANGE_FIT = 1 << 4
WEIGHT_COLOR_BY_ALPHA = 1 << 7


GetStorageRequirements = libsquish.GetStorageRequirements
GetStorageRequirements.argtypes = [c_int, c_int, c_int]
GetStorageRequirements.restype = c_int

def compress_image(rgba, width, height, flags):
    rgba = create_string_buffer(rgba)
    
    c = GetStorageRequirements(width, height, flags)
    buffer = create_string_buffer(c)
    
    libsquish.Compress(byref(rgba), byref(buffer), c_int(flags))
    
    return buffer.raw

def decompress_image(block, width, height, flags):
    block = create_string_buffer(block)
    
    c = width*height*4
    rgba = create_string_buffer(c)
    
    libsquish.DecompressImage(byref(rgba), c_int(width), c_int(height), byref(block), c_int(flags))
    
    return rgba.raw
Denn `rgba.raw` ist immer "leer", also ein enthält nur \x00

//Edit: Compress funktioniert auch nicht richtig, nach ein paar bytes kommt nur noch \x00
the more they change the more they stay the same
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Die c-Funktionsaufrufe sind irgendwie komisch. Woher weiss Compress(), wie groß das char-Array rgba ist? Gleiches gilt für blocks beim Dekomprimieren. Ich vermute, dass Dir da eine Deklaration fehlt (da die Größen nicht als Parameter übergeben werden).
lunar

@Dav1d: Entferne die Aufrufe von "byref()". Der Rückgabewert von "create_string_buffer()" ist bereits ein Zeiger, durch das anschließende "byref()" erzeugst Du einen Zeiger auf den Zeiger, sprich "u8**" statt "u8*"

@jerch: Nun ja, es geht offensichtlich um RGBA-Werte, da ist die Größe des Arrays eigentlich ziemlich eindeutig :)
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@lunar:
Dav1d hat geschrieben:Ich habe einen String, welcher den Inhalt für `rgba` enthält (wird aus einer Datei gelesen).
Das klingt für mich eher nach Bilddaten in RGBA, die auch unterschiedlich groß sein dürfen.

@David:
Wie sieht denn ein funktionierendes Bsp. in C aus?
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Danke.

Es funktioniert, auch mein Code, sieht so aus als kam libsquish mit meinen Daten nicht zurecht und hat einfach nichts gemacht.

@jerch
Stimmt, das ist mir garnicht aufgefallen, ein Beispielaufruf:

Code: Alles auswählen

#include <squish.h>

int main()
{
    squish::u8 pixels[16*4];  // 16 pixels of input
    squish::u8 block[8];      // 8 bytes of output

    /* write some pixel data */

    // compress the 4x4 block using DXT1 compression
    squish::Compress( pixels, block, squish::kDxt1 );
    
    // decompress the 4x4 block using DXT1 compression
    squish::Decompress( pixels, block, squish::kDxt1 );
}
1:1 von der Homepage. Auch hier wird nirgends die Größe angegeben. Man berechnet zwar mit `GetStorageRequirements` die Größe des Buffers den man mir übergeben muss, man teilt der Compress-Funktion nie mit wie groß der ist oder die Ausgangsdaten sind.
the more they change the more they stay the same
lunar

@Dav1d: Laut Dokumentation erwarten "Compress()" und "Decompress()" exakt 16 Pixel. Bei "CompressImage()" und "DecompressImage()" wird die Größe der Eingabe und Ausgabe aus der übergebenen Breite und Höhe des Bildes berechnet.

Hast Du "byref()" nun entfernt? Ich bin mir eigentlich ziemlich sicher, dass das da nicht hingehört.
BlackJack

@lunar: Das `byref()` sollte keinen Unterschied machen. In C macht ``some_array`` oder ``&some_array`` auch keinen Unterschied bei der Übergabe. `create_string_buffer()` gibt ein Arrayobjekt zurück und kein Zeigerobjekt.
Antworten