From 6374a35024269d184dbcabd0db397292bad22417 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Fri, 1 Mar 2013 14:39:46 +0100 Subject: [PATCH] NDColorModeMono and NDColorModeRGB1 eget and testServer support --- testApp/remote/eget.cpp | 88 ++++-- testApp/remote/testNTImage.cpp | 493 ++++----------------------------- testApp/remote/testServer.cpp | 114 +++++++- 3 files changed, 216 insertions(+), 479 deletions(-) diff --git a/testApp/remote/eget.cpp b/testApp/remote/eget.cpp index 60d41ac..f2b2dbd 100644 --- a/testApp/remote/eget.cpp +++ b/testApp/remote/eget.cpp @@ -540,6 +540,19 @@ void formatNTURI(std::ostream& o, PVStructurePtr const & pvStruct) void formatNTImage(std::ostream& /*o*/, PVStructurePtr const & pvStruct) { + PVIntPtr colorMode = pvStruct->getIntField("colorMode"); + if (colorMode.get() == 0) + { + std::cerr << "no int 'colorMode' field in NTImage" << std::endl; + return; + } + int32 cm = colorMode->get(); + if (cm != 0 && cm != 1 && cm != 2) + { + std::cerr << "unsupported image 'colorMode', only {0,1,2} modes are supported" << std::endl; + return; + } + PVScalarArrayPtr value = dynamic_pointer_cast(pvStruct->getSubField("value")); if (value.get() == 0) { @@ -556,19 +569,29 @@ void formatNTImage(std::ostream& /*o*/, PVStructurePtr const & pvStruct) return; } - // dim[] = { rows, columns } + // dim[] = { rows, columns } or + // dim[] = { 3, rows, columns } + IntArrayData data; size_t dims = dim->getLength(); - if (dims != 2) + dim->get(0, dims, data); + size_t imageSize; + if ((cm == 0 || cm == 1) && dims == 2) { - std::cerr << "malformed NTImage, dim[] must 2 elements instead of " << dims << std::endl; + cols = data.data[0]; + rows = data.data[1]; + imageSize = cols * rows; + } + else if (cm == 2 && dims == 3) + { + cols = data.data[1]; + rows = data.data[2]; + imageSize = cols * rows * 3; + } + else + { + std::cerr << "malformed NTImage, dim[] is invalid for specified color mode" << std::endl; return; } - - - IntArrayData data; - dim->get(0, dims, data); - cols = data.data[0]; - rows = data.data[1]; if (rows <= 0 || cols <= 0) { @@ -576,14 +599,20 @@ void formatNTImage(std::ostream& /*o*/, PVStructurePtr const & pvStruct) return; } - // TODO !!! PVByteArrayPtr array = dynamic_pointer_cast(value); if (array.get() == 0) { - std::cerr << "currently only grayscale NTImage with byte[] value field are supported" << std::endl; + std::cerr << "currently only byte[] value field is supported" << std::endl; return; } + if (array->getLength() != imageSize) + { + std::cerr << "byte[] length does not match expected image size (" << + array->getLength() << " != " << imageSize << ")" << std::endl; + return; + } + ByteArrayData img; array->get(0, array->getLength(), img); /* @@ -610,14 +639,27 @@ void formatNTImage(std::ostream& /*o*/, PVStructurePtr const & pvStruct) fprintf(gnuplotPipe, "set xrange [0:%u]\n", cols-1); fprintf(gnuplotPipe, "set yrange [0:%u]\n", rows-1); - fprintf(gnuplotPipe, "set palette grey\n"); - fprintf(gnuplotPipe, "set cbrange [0:255]\n"); + if (cm == 2) + { + // RGB - fprintf(gnuplotPipe, "plot '-' binary array=(%u,%u) flipy format='%%uchar' with image\n", cols, rows); + fprintf(gnuplotPipe, "plot '-' binary array=(%u,%u) flipy format='%%uchar' with rgbimage\n", cols, rows); - size_t len = static_cast(rows*cols); - for (size_t i = 0; i < len; i++) - fprintf(gnuplotPipe, "%c", img.data[i]); + for (size_t i = 0; i < imageSize; i++) + fprintf(gnuplotPipe, "%c", img.data[i]); + } + else + { + // grayscale + + fprintf(gnuplotPipe, "set palette grey\n"); + fprintf(gnuplotPipe, "set cbrange [0:255]\n"); + + fprintf(gnuplotPipe, "plot '-' binary array=(%u,%u) flipy format='%%uchar' with image\n", cols, rows); + + for (size_t i = 0; i < imageSize; i++) + fprintf(gnuplotPipe, "%c", img.data[i]); + } fflush(gnuplotPipe); pclose(gnuplotPipe); @@ -778,6 +820,7 @@ void usage (void) " -r : Get request string, specifies what fields to return and options, default is '%s'\n" " -w : Wait time, specifies timeout, default is %f second(s)\n" " -q: Pure pvAccess RPC based service (send NTURI.query as request argument)\n" + " -n: Do not format NT types, dump structure instread." " -t: Terse mode / transpose vector, table, matrix.\n" " -x: Use column-major order to decode matrix.\n" " -d: Enable debug output\n" @@ -1081,13 +1124,14 @@ int main (int argc, char *argv[]) bool serviceRequest = false; bool onlyQuery = false; + bool dumpStructure = false; string service; //string urlEncodedRequest; vector< pair > parameters; setvbuf(stdout,NULL,_IOLBF,BUFSIZ); /* Set stdout to line buffering */ - while ((opt = getopt(argc, argv, ":hr:s:a:w:qtxdcF:")) != -1) { + while ((opt = getopt(argc, argv, ":hr:s:a:w:qntxdcF:")) != -1) { switch (opt) { case 'h': /* Print usage */ usage(); @@ -1131,6 +1175,9 @@ int main (int argc, char *argv[]) case 'q': /* pvAccess RPC mode */ onlyQuery = true; break; + case 'n': /* Do not format NT types */ + dumpStructure = true; + break; case 't': /* Terse mode */ mode = TerseMode; break; @@ -1453,7 +1500,10 @@ int main (int argc, char *argv[]) allOK &= rpcRequesterImpl->waitUntilRPC(timeOut); if (allOK) { - formatNT(std::cout, rpcRequesterImpl->getLastResponse()); + if (dumpStructure) + std::cout << *(rpcRequesterImpl->getLastResponse().get()) << std::endl; + else + formatNT(std::cout, rpcRequesterImpl->getLastResponse()); std::cout << std::endl; } } diff --git a/testApp/remote/testNTImage.cpp b/testApp/remote/testNTImage.cpp index 37f9aef..008a7e1 100644 --- a/testApp/remote/testNTImage.cpp +++ b/testApp/remote/testNTImage.cpp @@ -75,27 +75,42 @@ epics::pvData::StructureConstPtr makeImageStruc() return imageStruc; } -void setImageArrayValues(PVStructure::shared_pointer const & imagePV) +void setImageArrayValues( + 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 + ) { String id = imagePV->getStructure()->getID(); PVByteArrayPtr pvField = static_pointer_cast(imagePV->getSubField("value")); - size_t dataSize = epicsv4_raw_size; + size_t dataSize = raw_size; pvField->setCapacity(dataSize); - const int8_t *data = epicsv4_raw; - pvField->put(0, dataSize, data, 0); + const int8_t *data = raw; + if (data) + pvField->put(0, dataSize, data, 0); PVIntArrayPtr dimField = static_pointer_cast( imagePV->getScalarArrayField(String("dim"), pvInt)); - dimField->setCapacity(2); - const int32_t *dim = epicsv4_raw_dim; - dimField->put(0, 2, dim, 0); + dimField->setCapacity(raw_dim_size); + const int32_t *dim = raw_dim; + dimField->put(0, raw_dim_size, dim, 0); } -void setImageImageValues(PVStructure::shared_pointer const & imagePV) +void setImageImageValues( + PVStructure::shared_pointer const & imagePV, + const int32_t colorMode, + const size_t raw_dim_size, + const int32_t* raw_dim + ) { - PVIntArrayPtr offsetField = static_pointer_cast( + PVIntPtr colorModeField = imagePV->getIntField(String("colorMode")); + colorModeField->put(colorMode); + + PVIntArrayPtr offsetField = static_pointer_cast( imagePV->getScalarArrayField(String("offset"), pvInt)); offsetField->setCapacity(2); int32_t offsets[] = { 0, 0 }; @@ -115,9 +130,9 @@ void setImageImageValues(PVStructure::shared_pointer const & imagePV) PVIntArrayPtr fullDimField = static_pointer_cast( imagePV->getScalarArrayField(String("fullDim"), pvInt)); - fullDimField->setCapacity(2); - const int32_t *fullDim = epicsv4_raw_dim; - fullDimField->put(0, 2, fullDim, 0); + fullDimField->setCapacity(raw_dim_size); + const int32_t *fullDim = raw_dim; + fullDimField->put(0, raw_dim_size, fullDim, 0); } @@ -134,14 +149,28 @@ void setImageMetadataValues(PVStructure::shared_pointer const & imagePV) } -void initImage(PVStructure::shared_pointer const & imagePV) +void initImage( + PVStructure::shared_pointer const & imagePV, + const int32_t colorMode, + const size_t raw_dim_size, + const int32_t* raw_dim, + const size_t raw_size, + const int8_t* raw + ) { - setImageArrayValues(imagePV); - setImageImageValues(imagePV); + setImageArrayValues(imagePV, raw_dim_size, raw_dim, raw_size, raw); + setImageImageValues(imagePV, colorMode, raw_dim_size, raw_dim); setImageMetadataValues(imagePV); } -void rotateImage(PVStructure::shared_pointer const & imagePV, float deg) +void initImageEPICSv4GrayscaleLogo(PVStructure::shared_pointer const & imagePV) +{ + setImageArrayValues(imagePV, 2, epicsv4_raw_dim, epicsv4_raw_size, epicsv4_raw); + setImageImageValues(imagePV, 0 /* monochrome */, 2 /* 2d image */, epicsv4_raw_dim); + setImageMetadataValues(imagePV); +} + +void rotateImage(PVStructure::shared_pointer const & imagePV, const int8_t* originalImage, float deg) { PVScalarArrayPtr value = static_pointer_cast(imagePV->getSubField("value")); PVIntArrayPtr dim = static_pointer_cast(imagePV->getScalarArrayField("dim", pvInt)); @@ -156,10 +185,6 @@ void rotateImage(PVStructure::shared_pointer const & imagePV, float deg) PVByteArrayPtr array = static_pointer_cast(value); - ByteArrayData dimg; - size_t imgSize = array->getLength(); - array->get(0, imgSize, dimg); - double fi = 3.141592653589793238462 * deg / 180.0; double cosFi = 16.0 * cos(fi); double sinFi = 16.0 * sin(fi); @@ -170,7 +195,7 @@ void rotateImage(PVStructure::shared_pointer const & imagePV, float deg) int32 colsm2 = cols-2; int32 rowsm2 = rows-2; - int8_t* img = &dimg.data[0]; + int8_t* img = array->get(); for (int32 y = 0; y < rows; y++) { @@ -192,7 +217,7 @@ void rotateImage(PVStructure::shared_pointer const & imagePV, float deg) } else { - const int8_t* srcline = epicsv4_raw + ny*cols; + const int8_t* srcline = originalImage + ny*cols; int32 xf = tnx & 0x0F; int32 yf = tny & 0x0F; @@ -207,432 +232,8 @@ void rotateImage(PVStructure::shared_pointer const & imagePV, float deg) } } } - array->put(0, imgSize, img, 0); PVIntPtr uniqueIdField = imagePV->getIntField(String("uniqueId")); uniqueIdField->put(uniqueIdField->get()+1); } - - -void -rotateAMColorFastLow(uint32 *datad, - int32 w, - int32 h, - int32 wpld, - uint32 *datas, - int32 wpls, - float angle, - uint32 colorval); - -void rotateRGBImage(PVStructure::shared_pointer const & imagePV, float deg) -{ - PVScalarArrayPtr value = static_pointer_cast(imagePV->getSubField("value")); - PVIntArrayPtr dim = static_pointer_cast(imagePV->getScalarArrayField("dim", pvInt)); - // dim[] = { rows, columns } - int32 rows, cols; - size_t dims = dim->getLength(); - - IntArrayData data; - dim->get(0, dims, data); - cols = data.data[0]; - rows = data.data[1]; - - PVIntArrayPtr array = static_pointer_cast(value); - - IntArrayData dimg; - size_t imgSize = array->getLength(); - array->get(0, imgSize, dimg); - - rotateAMColorFastLow((uint32*)&dimg.data[0], - cols, - rows, - cols, - (uint32*)&dimg.data[0], - cols, - 3.141592653589793238462 * deg / 180.0, - 0x00000000); - - array->put(0, imgSize, &dimg.data[0], 0); - - PVIntPtr uniqueIdField = imagePV->getIntField(String("uniqueId")); - uniqueIdField->put(uniqueIdField->get()+1); - -} - -/*====================================================================* - - Copyright (C) 2001 Leptonica. All rights reserved. - - - - Redistribution and use in source and binary forms, with or without - - modification, are permitted provided that the following conditions - - are met: - - 1. Redistributions of source code must retain the above copyright - - notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above - - copyright notice, this list of conditions and the following - - disclaimer in the documentation and/or other materials - - provided with the distribution. - - - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY - - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *====================================================================*/ - - -#include -#include - -/*------------------------------------------------------------------* - * Fast RGB color rotation about center * - *------------------------------------------------------------------*/ -/*! - * rotateAMColorFastLow() - * - * This is a special simplification of area mapping with division - * of each pixel into 16 sub-pixels. The exact coefficients that - * should be used are the same as for the 4x linear interpolation - * scaling case, and are given there. I tried to approximate these - * as weighted coefficients with a maximum sum of 4, which - * allows us to do the arithmetic in parallel for the R, G and B - * components in a 32 bit pixel. However, there are three reasons - * for not doing that: - * (1) the loss of accuracy in the parallel implementation - * is visually significant - * (2) the parallel implementation (described below) is slower - * (3) the parallel implementation requires allocation of - * a temporary color image - * - * There are 16 cases for the choice of the subpixel, and - * for each, the mapping to the relevant source - * pixels is as follows: - * - * subpixel src pixel weights - * -------- ----------------- - * 0 sp1 - * 1 (3 * sp1 + sp2) / 4 - * 2 (sp1 + sp2) / 2 - * 3 (sp1 + 3 * sp2) / 4 - * 4 (3 * sp1 + sp3) / 4 - * 5 (9 * sp1 + 3 * sp2 + 3 * sp3 + sp4) / 16 - * 6 (3 * sp1 + 3 * sp2 + sp3 + sp4) / 8 - * 7 (3 * sp1 + 9 * sp2 + sp3 + 3 * sp4) / 16 - * 8 (sp1 + sp3) / 2 - * 9 (3 * sp1 + sp2 + 3 * sp3 + sp4) / 8 - * 10 (sp1 + sp2 + sp3 + sp4) / 4 - * 11 (sp1 + 3 * sp2 + sp3 + 3 * sp4) / 8 - * 12 (sp1 + 3 * sp3) / 4 - * 13 (3 * sp1 + sp2 + 9 * sp3 + 3 * sp4) / 16 - * 14 (sp1 + sp2 + 3 * sp3 + 3 * sp4) / 8 - * 15 (sp1 + 3 * sp2 + 3 * sp3 + 9 * sp4) / 16 - * - * Another way to visualize this is to consider the area mapping - * (or linear interpolation) coefficients for the pixel sp1. - * Expressed in fourths, they can be written as asymmetric matrix: - * - * 4 3 2 1 - * 3 2.25 1.5 0.75 - * 2 1.5 1 0.5 - * 1 0.75 0.5 0.25 - * - * The coefficients for the three neighboring pixels can be - * similarly written. - * - * This is implemented here, where, for each color component, - * we inline its extraction from each participating word, - * construct the linear combination, and combine the results - * into the destination 32 bit RGB pixel, using the appropriate shifts. - * - * It is interesting to note that an alternative method, where - * we do the arithmetic on the 32 bit pixels directly (after - * shifting the components so they won't overflow into each other) - * is significantly inferior. Because we have only 8 bits for - * internal overflows, which can be distributed as 2, 3, 3, it - * is impossible to add these with the correct linear - * interpolation coefficients, which require a sum of up to 16. - * Rounding off to a sum of 4 causes appreciable visual artifacts - * in the rotated image. The code for the inferior method - * can be found in prog/rotatefastalt.c, for reference. - * - * *** Warning: explicit assumption about RGB component ordering *** - */ -void -rotateAMColorFastLow(uint32 *datad, - int32 w, - int32 h, - int32 wpld, - uint32 *datas, - int32 wpls, - float angle, - uint32 colorval) -{ -int32 i, j, xcen, ycen, wm2, hm2; -int32 xdif, ydif, xpm, ypm, xp, yp, xf, yf; -uint32 word1, word2, word3, word4, red, blue, green; -uint32 *pword, *lines, *lined; -float sina, cosa; - - xcen = w / 2; - wm2 = w - 2; - ycen = h / 2; - hm2 = h - 2; - sina = 4. * sin(angle); - cosa = 4. * cos(angle); - - for (i = 0; i < h; i++) { - ydif = ycen - i; - lined = datad + i * wpld; - for (j = 0; j < w; j++) { - xdif = xcen - j; - xpm = (int32)(-xdif * cosa - ydif * sina); - ypm = (int32)(-ydif * cosa + xdif * sina); - xp = xcen + (xpm >> 2); - yp = ycen + (ypm >> 2); - xf = xpm & 0x03; - yf = ypm & 0x03; - - /* if off the edge, write input grayval */ - if (xp < 0 || yp < 0 || xp > wm2 || yp > hm2) { - *(lined + j) = colorval; - continue; - } - - lines = datas + yp * wpls; - pword = lines + xp; - - switch (xf + 4 * yf) - { - case 0: - *(lined + j) = *pword; - break; - case 1: - word1 = *pword; - word2 = *(pword + 1); - red = 3 * (word1 >> 24) + (word2 >> 24); - green = 3 * ((word1 >> 16) & 0xff) + - ((word2 >> 16) & 0xff); - blue = 3 * ((word1 >> 8) & 0xff) + - ((word2 >> 8) & 0xff); - *(lined + j) = ((red << 22) & 0xff000000) | - ((green << 14) & 0x00ff0000) | - ((blue << 6) & 0x0000ff00); - break; - case 2: - word1 = *pword; - word2 = *(pword + 1); - red = (word1 >> 24) + (word2 >> 24); - green = ((word1 >> 16) & 0xff) + ((word2 >> 16) & 0xff); - blue = ((word1 >> 8) & 0xff) + ((word2 >> 8) & 0xff); - *(lined + j) = ((red << 23) & 0xff000000) | - ((green << 15) & 0x00ff0000) | - ((blue << 7) & 0x0000ff00); - break; - case 3: - word1 = *pword; - word2 = *(pword + 1); - red = (word1 >> 24) + 3 * (word2 >> 24); - green = ((word1 >> 16) & 0xff) + - 3 * ((word2 >> 16) & 0xff); - blue = ((word1 >> 8) & 0xff) + - 3 * ((word2 >> 8) & 0xff); - *(lined + j) = ((red << 22) & 0xff000000) | - ((green << 14) & 0x00ff0000) | - ((blue << 6) & 0x0000ff00); - break; - case 4: - word1 = *pword; - word3 = *(pword + wpls); - red = 3 * (word1 >> 24) + (word3 >> 24); - green = 3 * ((word1 >> 16) & 0xff) + - ((word3 >> 16) & 0xff); - blue = 3 * ((word1 >> 8) & 0xff) + - ((word3 >> 8) & 0xff); - *(lined + j) = ((red << 22) & 0xff000000) | - ((green << 14) & 0x00ff0000) | - ((blue << 6) & 0x0000ff00); - break; - case 5: - word1 = *pword; - word2 = *(pword + 1); - word3 = *(pword + wpls); - word4 = *(pword + wpls + 1); - red = 9 * (word1 >> 24) + 3 * (word2 >> 24) + - 3 * (word3 >> 24) + (word4 >> 24); - green = 9 * ((word1 >> 16) & 0xff) + - 3 * ((word2 >> 16) & 0xff) + - 3 * ((word3 >> 16) & 0xff) + - ((word4 >> 16) & 0xff); - blue = 9 * ((word1 >> 8) & 0xff) + - 3 * ((word2 >> 8) & 0xff) + - 3 * ((word3 >> 8) & 0xff) + - ((word4 >> 8) & 0xff); - *(lined + j) = ((red << 20) & 0xff000000) | - ((green << 12) & 0x00ff0000) | - ((blue << 4) & 0x0000ff00); - break; - case 6: - word1 = *pword; - word2 = *(pword + 1); - word3 = *(pword + wpls); - word4 = *(pword + wpls + 1); - red = 3 * (word1 >> 24) + 3 * (word2 >> 24) + - (word3 >> 24) + (word4 >> 24); - green = 3 * ((word1 >> 16) & 0xff) + - 3 * ((word2 >> 16) & 0xff) + - ((word3 >> 16) & 0xff) + - ((word4 >> 16) & 0xff); - blue = 3 * ((word1 >> 8) & 0xff) + - 3 * ((word2 >> 8) & 0xff) + - ((word3 >> 8) & 0xff) + - ((word4 >> 8) & 0xff); - *(lined + j) = ((red << 21) & 0xff000000) | - ((green << 13) & 0x00ff0000) | - ((blue << 5) & 0x0000ff00); - break; - case 7: - word1 = *pword; - word2 = *(pword + 1); - word3 = *(pword + wpls); - word4 = *(pword + wpls + 1); - red = 3 * (word1 >> 24) + 9 * (word2 >> 24) + - (word3 >> 24) + 3 * (word4 >> 24); - green = 3 * ((word1 >> 16) & 0xff) + - 9 * ((word2 >> 16) & 0xff) + - ((word3 >> 16) & 0xff) + - 3 * ((word4 >> 16) & 0xff); - blue = 3 * ((word1 >> 8) & 0xff) + - 9 * ((word2 >> 8) & 0xff) + - ((word3 >> 8) & 0xff) + - 3 * ((word4 >> 8) & 0xff); - *(lined + j) = ((red << 20) & 0xff000000) | - ((green << 12) & 0x00ff0000) | - ((blue << 4) & 0x0000ff00); - break; - case 8: - word1 = *pword; - word3 = *(pword + wpls); - red = (word1 >> 24) + (word3 >> 24); - green = ((word1 >> 16) & 0xff) + ((word3 >> 16) & 0xff); - blue = ((word1 >> 8) & 0xff) + ((word3 >> 8) & 0xff); - *(lined + j) = ((red << 23) & 0xff000000) | - ((green << 15) & 0x00ff0000) | - ((blue << 7) & 0x0000ff00); - break; - case 9: - word1 = *pword; - word2 = *(pword + 1); - word3 = *(pword + wpls); - word4 = *(pword + wpls + 1); - red = 3 * (word1 >> 24) + (word2 >> 24) + - 3 * (word3 >> 24) + (word4 >> 24); - green = 3 * ((word1 >> 16) & 0xff) + ((word2 >> 16) & 0xff) + - 3 * ((word3 >> 16) & 0xff) + ((word4 >> 16) & 0xff); - blue = 3 * ((word1 >> 8) & 0xff) + ((word2 >> 8) & 0xff) + - 3 * ((word3 >> 8) & 0xff) + ((word4 >> 8) & 0xff); - *(lined + j) = ((red << 21) & 0xff000000) | - ((green << 13) & 0x00ff0000) | - ((blue << 5) & 0x0000ff00); - break; - case 10: - word1 = *pword; - word2 = *(pword + 1); - word3 = *(pword + wpls); - word4 = *(pword + wpls + 1); - red = (word1 >> 24) + (word2 >> 24) + - (word3 >> 24) + (word4 >> 24); - green = ((word1 >> 16) & 0xff) + ((word2 >> 16) & 0xff) + - ((word3 >> 16) & 0xff) + ((word4 >> 16) & 0xff); - blue = ((word1 >> 8) & 0xff) + ((word2 >> 8) & 0xff) + - ((word3 >> 8) & 0xff) + ((word4 >> 8) & 0xff); - *(lined + j) = ((red << 22) & 0xff000000) | - ((green << 14) & 0x00ff0000) | - ((blue << 6) & 0x0000ff00); - break; - case 11: - word1 = *pword; - word2 = *(pword + 1); - word3 = *(pword + wpls); - word4 = *(pword + wpls + 1); - red = (word1 >> 24) + 3 * (word2 >> 24) + - (word3 >> 24) + 3 * (word4 >> 24); - green = ((word1 >> 16) & 0xff) + 3 * ((word2 >> 16) & 0xff) + - ((word3 >> 16) & 0xff) + 3 * ((word4 >> 16) & 0xff); - blue = ((word1 >> 8) & 0xff) + 3 * ((word2 >> 8) & 0xff) + - ((word3 >> 8) & 0xff) + 3 * ((word4 >> 8) & 0xff); - *(lined + j) = ((red << 21) & 0xff000000) | - ((green << 13) & 0x00ff0000) | - ((blue << 5) & 0x0000ff00); - break; - case 12: - word1 = *pword; - word3 = *(pword + wpls); - red = (word1 >> 24) + 3 * (word3 >> 24); - green = ((word1 >> 16) & 0xff) + - 3 * ((word3 >> 16) & 0xff); - blue = ((word1 >> 8) & 0xff) + - 3 * ((word3 >> 8) & 0xff); - *(lined + j) = ((red << 22) & 0xff000000) | - ((green << 14) & 0x00ff0000) | - ((blue << 6) & 0x0000ff00); - break; - case 13: - word1 = *pword; - word2 = *(pword + 1); - word3 = *(pword + wpls); - word4 = *(pword + wpls + 1); - red = 3 * (word1 >> 24) + (word2 >> 24) + - 9 * (word3 >> 24) + 3 * (word4 >> 24); - green = 3 * ((word1 >> 16) & 0xff) + ((word2 >> 16) & 0xff) + - 9 * ((word3 >> 16) & 0xff) + 3 * ((word4 >> 16) & 0xff); - blue = 3 *((word1 >> 8) & 0xff) + ((word2 >> 8) & 0xff) + - 9 * ((word3 >> 8) & 0xff) + 3 * ((word4 >> 8) & 0xff); - *(lined + j) = ((red << 20) & 0xff000000) | - ((green << 12) & 0x00ff0000) | - ((blue << 4) & 0x0000ff00); - break; - case 14: - word1 = *pword; - word2 = *(pword + 1); - word3 = *(pword + wpls); - word4 = *(pword + wpls + 1); - red = (word1 >> 24) + (word2 >> 24) + - 3 * (word3 >> 24) + 3 * (word4 >> 24); - green = ((word1 >> 16) & 0xff) +((word2 >> 16) & 0xff) + - 3 * ((word3 >> 16) & 0xff) + 3 * ((word4 >> 16) & 0xff); - blue = ((word1 >> 8) & 0xff) + ((word2 >> 8) & 0xff) + - 3 * ((word3 >> 8) & 0xff) + 3 * ((word4 >> 8) & 0xff); - *(lined + j) = ((red << 21) & 0xff000000) | - ((green << 13) & 0x00ff0000) | - ((blue << 5) & 0x0000ff00); - break; - case 15: - word1 = *pword; - word2 = *(pword + 1); - word3 = *(pword + wpls); - word4 = *(pword + wpls + 1); - red = (word1 >> 24) + 3 * (word2 >> 24) + - 3 * (word3 >> 24) + 9 * (word4 >> 24); - green = ((word1 >> 16) & 0xff) + 3 * ((word2 >> 16) & 0xff) + - 3 * ((word3 >> 16) & 0xff) + 9 * ((word4 >> 16) & 0xff); - blue = ((word1 >> 8) & 0xff) + 3 * ((word2 >> 8) & 0xff) + - 3 * ((word3 >> 8) & 0xff) + 9 * ((word4 >> 8) & 0xff); - *(lined + j) = ((red << 20) & 0xff000000) | - ((green << 12) & 0x00ff0000) | - ((blue << 4) & 0x0000ff00); - break; - default: - fprintf(stderr, "shouldn't get here\n"); - break; - } - } - } - - return; -} diff --git a/testApp/remote/testServer.cpp b/testApp/remote/testServer.cpp index 48f68c8..2fd01e4 100644 --- a/testApp/remote/testServer.cpp +++ b/testApp/remote/testServer.cpp @@ -218,7 +218,8 @@ public: { try { - rotateImage(pvImage, angle); + // TODO not nice, since we supply original here + rotateImage(pvImage, epicsv4_raw, angle); angle += 1; notifyStructureChanged(name); } catch (std::exception &ex) { @@ -902,7 +903,7 @@ class MockChannelRPC : public ChannelRPC if (columns.get() == 0) { PVStructure::shared_pointer nullPtr; - Status errorStatus(Status::STATUSTYPE_ERROR, "no columns specified"); + Status errorStatus(Status::STATUSTYPE_ERROR, "no 'columns' argument specified"); m_channelRPCRequester->requestDone(errorStatus, nullPtr); } else @@ -974,7 +975,7 @@ class MockChannelRPC : public ChannelRPC if (columns.get() == 0) { PVStructure::shared_pointer nullPtr; - Status errorStatus(Status::STATUSTYPE_ERROR, "no columns specified"); + Status errorStatus(Status::STATUSTYPE_ERROR, "no 'columns' argument specified"); m_channelRPCRequester->requestDone(errorStatus, nullPtr); } else @@ -1029,7 +1030,7 @@ class MockChannelRPC : public ChannelRPC if (rows.get() == 0 || columns.get() == 0) { PVStructure::shared_pointer nullPtr; - Status errorStatus(Status::STATUSTYPE_ERROR, "no rows and columns specified"); + Status errorStatus(Status::STATUSTYPE_ERROR, "no 'rows' and 'columns' arguments specified"); m_channelRPCRequester->requestDone(errorStatus, nullPtr); } else @@ -1071,7 +1072,86 @@ class MockChannelRPC : public ChannelRPC m_channelRPCRequester->requestDone(Status::Ok, result); } } - else if (m_channelName == "testNTURI") + else if (m_channelName.find("testImage") == 0) + { + PVStructure::shared_pointer args( + (pvArgument->getStructure()->getID() == "uri:ev4:nt/2012/pwd:NTURI") ? + pvArgument->getStructureField("query") : + pvArgument + ); + + PVStringPtr file = static_pointer_cast(args->getSubField("file")); + PVStringPtr w = static_pointer_cast(args->getSubField("w")); + PVStringPtr h = static_pointer_cast(args->getSubField("h")); + if (file.get() == 0 || w.get() == 0 || h.get() == 0) + { + PVStructure::shared_pointer nullPtr; + Status errorStatus(Status::STATUSTYPE_ERROR, "not all 'file', 'w' and 'h' arguments specified"); + m_channelRPCRequester->requestDone(errorStatus, nullPtr); + } + else + { + int32 wv = atoi(w->get().c_str()); + int32 hv = atoi(h->get().c_str()); + String filev = file->get(); + + // ImageMagick conversion + // RGB888: convert img.png img.rgb + // grayscale: convert img.png img.g + bool isRGB = (filev.find(".rgb") != string::npos); + + ifstream in(filev.c_str(), ifstream::in | ifstream::binary); + if (in.is_open()) + { + // get file size + in.seekg(0, ifstream::end); + std::size_t fileSize = in.tellg(); + + // in case of negative values, etc., this will return right result, however it will fail next check + std::size_t expectedSize = wv*hv* (isRGB ? 3 : 1); + if (expectedSize == fileSize) + { + in.seekg(0, ifstream::beg); + + // TODO sync missing on m_pvStructure + if (isRGB) + { + const int32_t dim[] = { 3, wv, hv }; + initImage(m_pvStructure, 2 /* RGB */, 3, dim, fileSize, 0); + } + else + { + const int32_t dim[] = { wv, hv }; + initImage(m_pvStructure, 0 /* grayscale */, 2, dim, fileSize, 0); + } + + PVByteArrayPtr value = std::tr1::dynamic_pointer_cast(m_pvStructure->getSubField("value")); + value->setCapacity(fileSize); + + value->setLength(fileSize); + in.readsome((char*)value->get(), fileSize); + + m_channelRPCRequester->requestDone(Status::Ok, m_pvStructure); + + // for monitors + notifyStructureChanged(m_channelName); + } + else + { + PVStructure::shared_pointer nullPtr; + Status errorStatus(Status::STATUSTYPE_ERROR, "file size does not match given 'w' and 'h'"); + m_channelRPCRequester->requestDone(errorStatus, nullPtr); + } + } + else + { + PVStructure::shared_pointer nullPtr; + Status errorStatus(Status::STATUSTYPE_ERROR, "failed to open image file specified"); + m_channelRPCRequester->requestDone(errorStatus, nullPtr); + } + } + } + else if (m_channelName == "testNTURI") { if (pvArgument->getStructure()->getID() != "uri:ev4:nt/2012/pwd:NTURI") { @@ -1415,11 +1495,12 @@ class MockChannel : public Channel { printf("=============------------------------------------!!!\n"); */ } - else if (m_name.find("testNTImage") == 0 || m_name.find("testImage") == 0) + else if (m_name.find("testNTImage") == 0 || m_name.find("testMP") == 0 + || m_name.find("testImage") == 0) { m_pvStructure = getPVDataCreate()->createPVStructure(makeImageStruc()); - initImage(m_pvStructure); - } + initImageEPICSv4GrayscaleLogo(m_pvStructure); + } else if (m_name.find("testADC") == 0) { int i = 0; @@ -1694,7 +1775,7 @@ class MockServerChannelProvider : public ChannelProvider, m_mockChannelFind(), m_counterChannel(), m_adcChannel(), - m_ntImageChannel(), + m_mpChannel(), m_scan1Hz(1.0), m_scan1HzThread(), m_adcAction(), @@ -1732,9 +1813,9 @@ class MockServerChannelProvider : public ChannelProvider, m_adcAction.adcSim = createSimADC("testADC"); m_adcThread.reset(new Thread("adcThread", highPriority, &m_adcAction)); - m_ntImageChannel = MockChannel::create(chProviderPtr, cr, "testImage", "local"); - m_imgAction.name = "testImage"; - m_imgAction.pvImage = static_pointer_cast(m_ntImageChannel)->m_pvStructure; + m_mpChannel = MockChannel::create(chProviderPtr, cr, "testMP", "local"); + m_imgAction.name = "testMP"; + m_imgAction.pvImage = static_pointer_cast(m_mpChannel)->m_pvStructure; m_imgThread.reset(new Thread("imgThread", highPriority, &m_imgAction)); } @@ -1783,7 +1864,12 @@ class MockServerChannelProvider : public ChannelProvider, channelRequester->channelCreated(Status::Ok, m_adcChannel); return m_adcChannel; } - else + else if (channelName == "testMP") + { + channelRequester->channelCreated(Status::Ok, m_mpChannel); + return m_mpChannel; + } + else { ChannelProvider::shared_pointer chProviderPtr = shared_from_this(); Channel::shared_pointer channel = MockChannel::create(chProviderPtr, channelRequester, channelName, address); @@ -1804,7 +1890,7 @@ class MockServerChannelProvider : public ChannelProvider, ChannelFind::shared_pointer m_mockChannelFind; Channel::shared_pointer m_counterChannel; Channel::shared_pointer m_adcChannel; - Channel::shared_pointer m_ntImageChannel; + Channel::shared_pointer m_mpChannel; ProcessAction m_scan1Hz; auto_ptr m_scan1HzThread;