249 lines
8.0 KiB
C++
249 lines
8.0 KiB
C++
#include "epicsv4Grayscale.h"
|
|
|
|
epics::pvData::StructureConstPtr createNTNDArrayStructure()
|
|
{
|
|
static epics::pvData::StructureConstPtr ntndArrayStructure;
|
|
|
|
if (!ntndArrayStructure.get())
|
|
{
|
|
StandardFieldPtr standardField = getStandardField();
|
|
FieldBuilderPtr fb = getFieldCreate()->createFieldBuilder();
|
|
|
|
for (int i = pvBoolean; i < pvString; ++i)
|
|
{
|
|
ScalarType st = static_cast<ScalarType>(i);
|
|
fb->addArray(std::string(ScalarTypeFunc::name(st)) + "Value", st);
|
|
}
|
|
UnionConstPtr valueType = fb->createUnion();
|
|
|
|
StructureConstPtr codecStruc = fb->setId("codec_t")->
|
|
add("name", pvString)->
|
|
add("parameters", getFieldCreate()->createVariantUnion())->
|
|
createStructure();
|
|
|
|
StructureConstPtr dimensionStruc = fb->setId("dimension_t")->
|
|
add("size", pvInt)->
|
|
add("offset", pvInt)->
|
|
add("fullSize", pvInt)->
|
|
add("binning", pvInt)->
|
|
add("reverse", pvBoolean)->
|
|
createStructure();
|
|
|
|
StructureConstPtr attributeStruc = fb->setId("ev4:nt/NTAttribute:1.0")->
|
|
add("name", pvString)->
|
|
add("value", getFieldCreate()->createVariantUnion())->
|
|
add("descriptor", pvString)->
|
|
add("sourceType", pvInt)->
|
|
add("source", pvString)->
|
|
createStructure();
|
|
|
|
|
|
ntndArrayStructure = fb->setId("ev4:nt/NTNDArray:1.0")->
|
|
add("value", valueType)->
|
|
add("codec", codecStruc)->
|
|
add("compressedSize", pvLong)->
|
|
add("uncompressedSize", pvLong)->
|
|
addArray("dimension", dimensionStruc)->
|
|
add("uniqueId", pvInt)->
|
|
add("dataTimeStamp", standardField->timeStamp())->
|
|
addArray("attribute", attributeStruc)->
|
|
//add("descriptor", pvString)->
|
|
//add("timeStamp", standardField->timeStamp())->
|
|
//add("alarm", standardField->alarm())->
|
|
//add("display", standardField->display())->
|
|
createStructure();
|
|
}
|
|
|
|
return ntndArrayStructure;
|
|
}
|
|
|
|
void setNTNDArrayValue(
|
|
PVStructure::shared_pointer const & imagePV,
|
|
const size_t raw_dim_size,
|
|
const int32_t* raw_dim,
|
|
const size_t raw_size,
|
|
const int8_t* raw
|
|
)
|
|
{
|
|
PVUnionPtr unionValue = imagePV->getSubField<PVUnion>("value");
|
|
// assumes byteArray
|
|
PVByteArrayPtr pvField = unionValue->select<PVByteArray>("byteValue");
|
|
|
|
const int8_t *data = raw;
|
|
size_t dataSize = raw_size;
|
|
|
|
PVByteArray::svector temp(pvField->reuse());
|
|
temp.resize(dataSize);
|
|
if (data)
|
|
std::copy(data, data + dataSize, temp.begin());
|
|
pvField->replace(freeze(temp));
|
|
|
|
PVStructureArrayPtr dimField = imagePV->getSubField<PVStructureArray>("dimension");
|
|
|
|
PVStructureArray::svector dimVector(dimField->reuse());
|
|
dimVector.resize(raw_dim_size);
|
|
for (size_t i = 0; i < raw_dim_size; i++)
|
|
{
|
|
PVStructurePtr d = dimVector[i];
|
|
if (!d)
|
|
d = dimVector[i] = getPVDataCreate()->createPVStructure(dimField->getStructureArray()->getStructure());
|
|
d->getSubField<PVInt>("size")->put(raw_dim[i]);
|
|
d->getSubField<PVInt>("offset")->put(0);
|
|
d->getSubField<PVInt>("fullSize")->put(raw_dim[i]);
|
|
d->getSubField<PVInt>("binning")->put(1);
|
|
d->getSubField<PVBoolean>("reverse")->put(false);
|
|
}
|
|
dimField->replace(freeze(dimVector));
|
|
|
|
imagePV->getSubField<PVLong>("uncompressedSize")->put(static_cast<int64>(raw_size));
|
|
|
|
PVTimeStamp timeStamp;
|
|
timeStamp.attach(imagePV->getSubField<PVStructure>("dataTimeStamp"));
|
|
TimeStamp current;
|
|
current.getCurrent();
|
|
timeStamp.set(current);
|
|
}
|
|
|
|
|
|
|
|
void setNTNDArrayData(
|
|
PVStructure::shared_pointer const & imagePV,
|
|
const string & codec,
|
|
int32 colorMode
|
|
)
|
|
{
|
|
imagePV->getSubField<PVString>("codec.name")->put(codec);
|
|
|
|
imagePV->getSubField<PVInt>("uniqueId")->put(0);
|
|
|
|
PVStructureArray::shared_pointer pvAttributes = imagePV->getSubField<PVStructureArray>("attribute");
|
|
|
|
PVStructureArray::svector attributes(pvAttributes->reuse());
|
|
|
|
bool addNew = false;
|
|
|
|
PVStructure::shared_pointer attribute;
|
|
|
|
// find ColorMode
|
|
for (PVStructureArray::const_svector::const_iterator iter = attributes.begin();
|
|
iter != attributes.end();
|
|
iter++)
|
|
{
|
|
PVStructure::shared_pointer fattribute = *iter;
|
|
PVString::shared_pointer pvName = fattribute->getSubField<PVString>("name");
|
|
if (pvName && pvName->get() == "ColorMode")
|
|
{
|
|
attribute = fattribute;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!attribute)
|
|
{
|
|
attribute = getPVDataCreate()->createPVStructure(pvAttributes->getStructureArray()->getStructure());
|
|
addNew = true;
|
|
}
|
|
|
|
attribute->getSubField<PVString>("name")->put("ColorMode");
|
|
PVInt::shared_pointer pvColorMode = getPVDataCreate()->createPVScalar<PVInt>();
|
|
pvColorMode->put(colorMode);
|
|
|
|
if (addNew)
|
|
attributes.push_back(attribute);
|
|
|
|
attribute->getSubField<PVUnion>("value")->set(pvColorMode);
|
|
attribute->getSubField<PVString>("descriptor")->put("Color mode");
|
|
attribute->getSubField<PVInt>("sourceType")->put(0);
|
|
attribute->getSubField<PVString>("source")->put("");
|
|
|
|
pvAttributes->replace(freeze(attributes));
|
|
}
|
|
|
|
void initImage(
|
|
PVStructure::shared_pointer const & imagePV,
|
|
const string & codec,
|
|
int32 colorMode,
|
|
const size_t raw_dim_size,
|
|
const int32_t* raw_dim,
|
|
const size_t raw_size,
|
|
const int8_t* raw
|
|
)
|
|
{
|
|
setNTNDArrayValue(imagePV, raw_dim_size, raw_dim, raw_size, raw);
|
|
setNTNDArrayData(imagePV, codec, colorMode);
|
|
}
|
|
|
|
void initImageEPICSv4GrayscaleLogo(PVStructure::shared_pointer const & imagePV)
|
|
{
|
|
setNTNDArrayValue(imagePV, 2, epicsv4_raw_dim, epicsv4_raw_size, epicsv4_raw);
|
|
setNTNDArrayData(imagePV, "", 0 /* NDColorModeMono=0 */);
|
|
}
|
|
|
|
void rotateImage(PVStructure::shared_pointer const & imagePV, const int8_t* originalImage, float deg)
|
|
{
|
|
PVUnionPtr unionValue = imagePV->getSubField<PVUnion>("value");
|
|
PVStructureArrayPtr dim = imagePV->getSubField<PVStructureArray>("dimension");
|
|
|
|
PVStructureArray::const_svector data = dim->view();
|
|
// 2d NTNDArray - { x, y }
|
|
int32 cols = data[0]->getSubField<PVInt>("size")->get();
|
|
int32 rows = data[1]->getSubField<PVInt>("size")->get();
|
|
|
|
// assumes byteArray
|
|
PVByteArrayPtr array = unionValue->get<PVByteArray>();
|
|
|
|
double fi = 3.141592653589793238462 * deg / 180.0;
|
|
double cosFi = 16.0 * cos(fi);
|
|
double sinFi = 16.0 * sin(fi);
|
|
|
|
int32 cx = cols/2;
|
|
int32 cy = rows/2;
|
|
|
|
int32 colsm2 = cols-2;
|
|
int32 rowsm2 = rows-2;
|
|
|
|
PVByteArray::svector imgData(array->reuse());
|
|
int8_t* img = imgData.data();
|
|
|
|
for (int32 y = 0; y < rows; y++)
|
|
{
|
|
int8_t* imgline = img + y*cols;
|
|
int32 dcy = y - cy;
|
|
for (int32 x = 0; x < cols; x++)
|
|
{
|
|
int32 dcx = x - cx;
|
|
|
|
int32 tnx = static_cast<int32>(cosFi*dcx + sinFi*dcy);
|
|
int32 tny = static_cast<int32>(-sinFi*dcx + cosFi*dcy);
|
|
|
|
int32 nx = (tnx >> 4) + cx;
|
|
int32 ny = (tny >> 4) + cy;
|
|
|
|
if (nx < 0 || ny < 0 || nx > colsm2 || ny > rowsm2)
|
|
{
|
|
imgline[x] = 0;
|
|
}
|
|
else
|
|
{
|
|
const int8_t* srcline = originalImage + ny*cols;
|
|
|
|
int32 xf = tnx & 0x0F;
|
|
int32 yf = tny & 0x0F;
|
|
|
|
int32 v00 = (16 - xf) * (16 - yf) * (srcline[nx] + 128);
|
|
int32 v10 = xf * (16 - yf) * (srcline[nx + 1] + 128);
|
|
int32 v01 = (16 - xf) * yf * (srcline[cols + nx] + 128);
|
|
int32 v11 = xf * yf * (srcline[cols + nx + 1] + 128);
|
|
uint8_t val = static_cast<uint8_t>((v00 + v01 + v10 + v11 + 128) / 256);
|
|
imgline[x] = static_cast<int32>(val) - 128;
|
|
|
|
}
|
|
}
|
|
}
|
|
array->replace(freeze(imgData));
|
|
|
|
PVIntPtr uniqueIdField = imagePV->getSubField<PVInt>("uniqueId");
|
|
uniqueIdField->put(uniqueIdField->get()+1);
|
|
|
|
}
|