BlinkenArea - GitList
Repositories
Blog
Wiki
BlinkenLib
Code
Commits
Branches
Tags
Search
Tree:
bf06f77
Branches
Tags
master
v0.1
v0.2
v0.3
v0.3.1
v0.4
v0.4.1
v0.5
v0.5.1
v0.5.2
v0.5.3
v0.5.4
v0.5.5
v0.6.0
v0.6.1
v0.6.2
v0.6.3
v0.6.4
v0.6.5
v0.6.6
v0.6.7
v0.6.8
v0.6.9
v0.7.0
v0.7.1
v0.7.10
v0.7.2
v0.7.3
v0.7.4
v0.7.5
v0.7.6
v0.7.7
v0.7.8
v0.7.9
v0.8.0
v0.8.1
BlinkenLib
src
BlinkenFrame.c
implement getting/setting pixel data
Stefan Schuermans
commited
bf06f77
at 2019-05-30 18:29:21
BlinkenFrame.c
Blame
History
Raw
/* BlinkenLib Copyright 2004-2014 Stefan Schuermans <stefan@schuermans.info> Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html a blinkenarea.org project */ #include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef WIN32 #include <winsock2.h> #include <windows.h> typedef WORD uint16_t; typedef DWORD uint32_t; #else #include <stdint.h> #include <netinet/in.h> #endif #include <BlinkenLib/BlinkenColorizer.h> #include <BlinkenLib/BlinkenFrame.h> #include "BlinkenConstants.h" #include "BlinkenProtoIntern.h" #include "Tools.h" struct sBlinkenFrame { int height; int width; int channels; int maxval; int duration; unsigned char **ppData; }; stBlinkenFrame *BlinkenFrameNew(int height, int width, int channels, int maxval, int duration) { stBlinkenFrame *pFrame; if (height < BlinkenHeightMin) height = BlinkenHeightMin; if (height > BlinkenHeightMax) height = BlinkenHeightMax; if (width < BlinkenWidthMin) width = BlinkenWidthMin; if (width > BlinkenWidthMax) width = BlinkenWidthMax; if (channels < BlinkenChannelsMin) channels = BlinkenChannelsMin; if (channels > BlinkenChannelsMax) channels = BlinkenMaxvalMax; if (maxval < BlinkenMaxvalMin) maxval = BlinkenMaxvalMin; if (maxval > BlinkenMaxvalMax) maxval = BlinkenMaxvalMax; if (duration < BlinkenDurationMin) duration = BlinkenDurationMin; if (duration > BlinkenDurationMax) duration = BlinkenDurationMax; pFrame = (stBlinkenFrame *) malloc(sizeof(stBlinkenFrame)); if (pFrame == NULL) return NULL; pFrame->height = height; pFrame->width = width; pFrame->channels = channels; pFrame->maxval = maxval; pFrame->duration = duration; pFrame->ppData = (unsigned char **)BlinkenMalloc2D(height, width * channels, sizeof(unsigned char)); if (pFrame->ppData == NULL) { free(pFrame); return NULL; } return pFrame; } stBlinkenFrame *BlinkenFrameClone(stBlinkenFrame *pSrcFrame) { int y, x, c, i; stBlinkenFrame *pFrame; if (pSrcFrame == NULL) return NULL; pFrame = BlinkenFrameNew(pSrcFrame->height, pSrcFrame->width, pSrcFrame->channels, pSrcFrame->maxval, pSrcFrame->duration); if (pFrame == NULL) return NULL; for (y = 0; y < pFrame->height; y++) for (x = 0, i = 0; x < pFrame->width; x++) for (c = 0; c < pFrame->channels; c++, i++) pFrame->ppData[y][i] = pSrcFrame->ppData[y][i]; return pFrame; } void BlinkenFrameFree(stBlinkenFrame *pFrame) { if (pFrame == NULL) return; free(pFrame->ppData); free(pFrame); } void BlinkenFrameClear(stBlinkenFrame *pFrame) { int y, x, c, i; if (pFrame == NULL) return; for (y = 0; y < pFrame->height; y++) for (x = 0, i = 0; x < pFrame->width; x++) for (c = 0; c < pFrame->channels; c++, i++) pFrame->ppData[y][i] = 0; } int BlinkenFrameGetHeight(stBlinkenFrame *pFrame) { if (pFrame == NULL) return 0; return pFrame->height; } int BlinkenFrameGetWidth(stBlinkenFrame *pFrame) { if (pFrame == NULL) return 0; return pFrame->width; } int BlinkenFrameGetChannels(stBlinkenFrame *pFrame) { if (pFrame == NULL) return 0; return pFrame->channels; } int BlinkenFrameGetMaxval(stBlinkenFrame *pFrame) { if (pFrame == NULL) return 0; return pFrame->maxval; } int BlinkenFrameGetDuration(stBlinkenFrame *pFrame) { if (pFrame == NULL) return 0; return pFrame->duration; } void BlinkenFrameSetDuration(stBlinkenFrame *pFrame, int duration) { if (pFrame == NULL) return; if (duration < BlinkenDurationMin) duration = BlinkenDurationMin; if (duration > BlinkenDurationMax) duration = BlinkenDurationMax; pFrame->duration = duration; } unsigned char BlinkenFrameGetPixel(stBlinkenFrame *pFrame, int y, int x, int c) { if (pFrame == NULL || y < 0 || y >= pFrame->height || x < 0 || x >= pFrame->width || c < 0 || c >= pFrame->channels) return 0; return pFrame->ppData[y][x * pFrame->channels + c]; } void BlinkenFrameSetPixel(stBlinkenFrame *pFrame, int y, int x, int c, unsigned char val) { if (pFrame == NULL || y < 0 || y >= pFrame->height || x < 0 || x >= pFrame->width || c < 0 || c >= pFrame->channels) return; if (val > pFrame->maxval) val = pFrame->maxval; pFrame->ppData[y][x * pFrame->channels + c] = val; } unsigned long BlinkenFrameGetColor(stBlinkenFrame *pFrame, int y, int x) { int i; if (pFrame == NULL || y < 0 || y >= pFrame->height || x < 0 || x >= pFrame->width) return 0; i = x * pFrame->channels; if (pFrame->channels == 1) return (((unsigned long)pFrame->ppData[y][i + 0] * 255 + pFrame->maxval / 2) / pFrame-> maxval) << 16 | (((unsigned long)pFrame->ppData[y][i + 0] * 255 + pFrame->maxval / 2) / pFrame->maxval) << 8 | (((unsigned long) pFrame->ppData[y][i + 0] * 255 + pFrame->maxval / 2) / pFrame->maxval); if (pFrame->channels == 2) return (((unsigned long)pFrame->ppData[y][i + 0] * 255 + pFrame->maxval / 2) / pFrame-> maxval) << 16 | (((unsigned long)pFrame->ppData[y][i + 1] * 255 + pFrame->maxval / 2) / pFrame->maxval) << 8; return (((unsigned long)pFrame->ppData[y][i + 0] * 255 + pFrame->maxval / 2) / pFrame->maxval) << 16 | (((unsigned long)pFrame->ppData[y][i + 1] * 255 + pFrame->maxval / 2) / pFrame->maxval) << 8 | (((unsigned long) pFrame->ppData[y] [i + 2] * 255 + pFrame->maxval / 2) / pFrame->maxval); } void BlinkenFrameSetColor(stBlinkenFrame *pFrame, int y, int x, unsigned long color) { int i, alpha, alpha_, c; if (pFrame == NULL || y < 0 || y >= pFrame->height || x < 0 || x >= pFrame->width) return; i = x * pFrame->channels; alpha = (color >> 24) & 0xFF; alpha_ = 255 - alpha; if (pFrame->channels >= 1) pFrame->ppData[y][i + 0] = (unsigned char)((((((color >> 16) & 0xFF) * pFrame->maxval + 127) / 255) * alpha + (unsigned long)pFrame->ppData[y][i + 0] * alpha_) / 255); if (pFrame->channels >= 2) pFrame->ppData[y][i + 1] = (unsigned char)((((((color >> 8) & 0xFF) * pFrame->maxval + 127) / 255) * alpha + (unsigned long)pFrame->ppData[y][i + 1] * alpha_) / 255); if (pFrame->channels >= 3) pFrame->ppData[y][i + 2] = (unsigned char)(((((color & 0xFF) * pFrame->maxval + 127) / 255) * alpha + (unsigned long)pFrame->ppData[y][i + 2] * alpha_) / 255); for (c = 3; c < pFrame->channels; c++) pFrame->ppData[y][i + c] = (unsigned char)((0 + (unsigned long) pFrame->ppData[y][i + c] * alpha_) / 255); } void BlinkenFrameGetPixelData(stBlinkenFrame const *pFrame, int y, int dy, int x, int dx, int c, int dc, unsigned char *pData) { int height, width, channels; unsigned char const **ppFrameData; int sy, ey, iy, sx, ex, ix, sc, ec, ic; // start/end/index x/y/channel int fy, fix, fic; // indexes into frame data int biy, bix, bic; // index into caller's data buffer // no frame -> leave if (pFrame == NULL) { return; } height = pFrame->height; width = pFrame->width; channels = pFrame->channels; ppFrameData = (unsigned char const **)pFrame->ppData; // compute start and end for each coordinate sy = y < 0 ? -y : 0; ey = y + dy > height ? height - y : dy; sx = x < 0 ? -x : 0; ex = x + dx > width ? width - x : dx; sc = c < 0 ? -c : 0; ec = c + dc > channels ? channels - c : dc; // get pixel data for (iy = sy, fy = y, biy = (sy * dx + sx) * dc + sc; iy < ey; ++iy, ++fy, biy += dx * dc) { for (ix = sx, fix = x * channels + c, bix = biy; ix < ex; ++ix, fix += channels, bix += dc) { for (ic = sc, fic = fix, bic = bix; ic < ec; ++ic, ++fic, ++bic) { pData[bic] = ppFrameData[fy][fic]; } } } } void BlinkenFrameSetPixelData(stBlinkenFrame *pFrame, int y, int dy, int x, int dx, int c, int dc, unsigned char const *pData) { int height, width, channels; unsigned char maxval; unsigned char **ppFrameData; int sy, ey, iy, sx, ex, ix, sc, ec, ic; // start/end/index x/y/channel int fy, fix, fic; // indexes into frame data int biy, bix, bic; // index into caller's data buffer unsigned char value; // no frame -> leave if (pFrame == NULL) { return; } height = pFrame->height; width = pFrame->width; channels = pFrame->channels; maxval = pFrame->maxval; ppFrameData = pFrame->ppData; // compute start and end for each coordinate sy = y < 0 ? -y : 0; ey = y + dy > height ? height - y : dy; sx = x < 0 ? -x : 0; ex = x + dx > width ? width - x : dx; sc = c < 0 ? -c : 0; ec = c + dc > channels ? channels - c : dc; // set pixel data for (iy = sy, fy = y, biy = (sy * dx + sx) * dc + sc; iy < ey; ++iy, ++fy, biy += dx * dc) { for (ix = sx, fix = x * channels + c, bix = biy; ix < ex; ++ix, fix += channels, bix += dc) { for (ic = sc, fic = fix, bic = bix; ic < ec; ++ic, ++fic, ++bic) { value = pData[bic]; ppFrameData[fy][fic] = value > maxval ? maxval : value; } } } } int BlinkenFrameIsEmpty(stBlinkenFrame *pFrame) // returns 1 if frame is empty (i.e. black), returns 0 otherwise { int y, x, c, i; if (pFrame == NULL) return 0; for (y = 0; y < pFrame->height; y++) { for (x = 0, i = 0; x < pFrame->width; x++) { for (c = 0; c < pFrame->channels; c++, i++) { if (pFrame->ppData[y][i] != 0) break; // pixel is not black -> abort } if (c < pFrame->channels) break; } if (x < pFrame->width) break; } if (y < pFrame->height) return 0; // aborted somewhere -> at least ony pixel is not black else return 1; // not aborted -> all pixels are black } int BlinkenFrameCompare(stBlinkenFrame *pFrame1, stBlinkenFrame *pFrame2) // returns -1 for frame1 smaller, 0 for equal, 1 for frame2 smaller { int y, cmp; if (pFrame1->height < pFrame2->height) return -1; if (pFrame1->height > pFrame2->height) return 1; if (pFrame1->width < pFrame2->width) return -1; if (pFrame1->width > pFrame2->width) return 1; if (pFrame1->channels < pFrame2->channels) return -1; if (pFrame1->channels > pFrame2->channels) return 1; if (pFrame1->maxval < pFrame2->maxval) return -1; if (pFrame1->maxval > pFrame2->maxval) return 1; for (y = 0; y < pFrame1->height; y++) { cmp = memcmp(pFrame1->ppData[y], pFrame2->ppData[y], pFrame1->width * pFrame2->channels); if (cmp != 0) return cmp; } return 0; } static void BlinkenFramePadCrop(stBlinkenFrame *pFrame, int height, int width, int channels, int maxval, int emptyY, int emptyX, int skipY, int skipX) { unsigned char **ppData; int y, x, c, i, j; int rangeY, rangeX; unsigned long val, div; if (pFrame == NULL) return; if (height < BlinkenHeightMin) height = BlinkenHeightMin; if (height > BlinkenHeightMax) height = BlinkenHeightMax; if (width < BlinkenWidthMin) width = BlinkenWidthMin; if (width > BlinkenWidthMax) width = BlinkenWidthMax; if (channels < BlinkenChannelsMin) channels = BlinkenChannelsMin; if (channels > BlinkenChannelsMax) channels = BlinkenMaxvalMax; if (maxval < BlinkenMaxvalMin) maxval = BlinkenMaxvalMin; if (maxval > BlinkenMaxvalMax) maxval = BlinkenMaxvalMax; if (height == pFrame->height && width == pFrame->width && channels == pFrame->channels && maxval == pFrame->maxval && emptyX == 0 && emptyY == 0 && skipY == 0 && skipX == 0) return; // allocate new data array ppData = (unsigned char **)BlinkenMalloc2D(height, width * channels, sizeof(unsigned char)); if (ppData == NULL) return; for (y = 0; y < height; y++) for (x = 0, i = 0; x < width; x++) for (c = 0; c < channels; c++, i++) ppData[y][i] = 0; // sanitize number of pixels to skip / to leave empty in X and Y direction if (emptyY < 0) emptyY = 0; if (emptyY > height) emptyY = height; if (emptyX < 0) emptyX = 0; if (emptyX > width) emptyX = width; if (skipY < 0) skipY = 0; if (skipY > pFrame->height) skipY = pFrame->height; if (skipX < 0) skipX = 0; if (skipX > pFrame->width) skipX = pFrame->width; rangeY = mini(height - emptyY, pFrame->height - skipY); rangeX = mini(width - emptyX, pFrame->width - skipX); // pad/crop frame with help of calculated parameters for (y = 0; y < rangeY; y++) { for (x = 0; x < rangeX; x++) { i = (skipX + x) * pFrame->channels; j = (emptyX + x) * channels; if (channels >= pFrame->channels) // add channels: copy last channel // into new channels { for (c = 0; c < pFrame->channels; c++, i++, j++) ppData[emptyY + y][j] = (unsigned char)(((unsigned long)pFrame->ppData[skipY + y][i] * maxval + pFrame->maxval / 2) / pFrame->maxval); for (; c < channels; c++, j++) ppData[emptyY + y][j] = ppData[emptyY + y][j - 1]; } else // remove channels: merge leftover channels with last kept // channel { val = 0; for (c = 0; c < channels - 1; c++, i++, j++) ppData[emptyY + y][j] = (unsigned char)(((unsigned long)pFrame->ppData[skipY + y][i] * maxval + pFrame->maxval / 2) / pFrame->maxval); for (c = channels - 1; c < pFrame->channels; c++, i++) val += (unsigned long)pFrame->ppData[skipY + y][i]; div = pFrame->maxval * (pFrame->channels - channels + 1); ppData[emptyY + y][j++] = (unsigned char)((val * maxval + div / 2) / div); } } } pFrame->height = height; pFrame->width = width; pFrame->channels = channels; pFrame->maxval = maxval; free(pFrame->ppData); pFrame->ppData = ppData; } void BlinkenFrameResize(stBlinkenFrame *pFrame, int height, int width, int channels, int maxval) { int emptyY, emptyX, skipY, skipX; if (pFrame == NULL) return; if (height < BlinkenHeightMin) height = BlinkenHeightMin; if (height > BlinkenHeightMax) height = BlinkenHeightMax; if (width < BlinkenWidthMin) width = BlinkenWidthMin; if (width > BlinkenWidthMax) width = BlinkenWidthMax; if (channels < BlinkenChannelsMin) channels = BlinkenChannelsMin; if (channels > BlinkenChannelsMax) channels = BlinkenMaxvalMax; if (maxval < BlinkenMaxvalMin) maxval = BlinkenMaxvalMin; if (maxval > BlinkenMaxvalMax) maxval = BlinkenMaxvalMax; if (height == pFrame->height && width == pFrame->width && channels == pFrame->channels && maxval == pFrame->maxval) return; // get number of pixels to skip / to leave empty in X and Y direction if (height > pFrame->height) { emptyY = (height - pFrame->height) / 2; skipY = 0; } else { emptyY = 0; skipY = (pFrame->height - height) / 2; } if (width > pFrame->width) { emptyX = (width - pFrame->width) / 2; skipX = 0; } else { emptyX = 0; skipX = (pFrame->width - width) / 2; } // resize frame with help of calculated parameters BlinkenFramePadCrop(pFrame, height, width, channels, maxval, emptyY, emptyX, skipY, skipX); } void BlinkenFrameCrop(stBlinkenFrame *pFrame, int top, int left, int height, int width) { if (pFrame == NULL) return; if (top < 0) top = 0; if (top > pFrame->height - BlinkenHeightMin) top = pFrame->height - BlinkenHeightMin; if (height < BlinkenHeightMin) height = BlinkenHeightMin; if (height > pFrame->height - top) height = pFrame->height - top; if (left < 0) left = 0; if (left > pFrame->width - BlinkenWidthMin) left = pFrame->width - BlinkenWidthMin; if (width < BlinkenWidthMin) width = BlinkenWidthMin; if (width > pFrame->width - left) width = pFrame->width - left; if (top == 0 && left == 0 && height == pFrame->height && width == pFrame->width) return; // crop frame with help of calculated parameters BlinkenFramePadCrop(pFrame, height, width, pFrame->channels, pFrame->maxval, 0, 0, top, left); } void BlinkenFrameScale(stBlinkenFrame *pFrame, int height, int width) { unsigned char **ppData; double scaleHor, scaleVer, ox, oy, ox1, oy1, val; int chans, c, nx, ny, x, y, oxi, oyi, ox1i, oy1i; if (pFrame == NULL) return; if (height < BlinkenHeightMin) height = BlinkenHeightMin; if (height > BlinkenHeightMax) height = BlinkenHeightMax; if (width < BlinkenWidthMin) width = BlinkenWidthMin; if (width > BlinkenWidthMax) width = BlinkenWidthMax; if (height == pFrame->height && width == pFrame->width) return; scaleHor = (double)width / (double)pFrame->width; scaleVer = (double)height / (double)pFrame->height; // allocate new data array ppData = (unsigned char **)BlinkenMalloc2D(height, width * pFrame->channels, sizeof(unsigned char)); if (ppData == NULL) return; // scale every channel chans = pFrame->channels; for (c = 0; c < chans; c++) { for (ny = 0; ny < height; ny++) { for (nx = 0; nx < width; nx++) { oy = (double)ny / scaleVer; // sub-pixel exact range in old // picture ox = (double)nx / scaleHor; oy1 = (double)(ny + 1) / scaleVer - 0.000001; ox1 = (double)(nx + 1) / scaleHor - 0.000001; if (oy < 0 || ox < 0 || oy1 >= pFrame->height || ox1 >= pFrame->width) // out of old picture ppData[ny][nx * chans + c] = 0; else { oyi = (int)oy; oxi = (int)ox; oy1i = (int)oy1; ox1i = (int)ox1; if (oyi == oy1i) { if (oxi == ox1i) // one source pixel { val = (double)pFrame->ppData[oyi][oxi * chans + c]; } else // one line of source pixels { val = (double)pFrame->ppData[oyi][oxi * chans + c] * (1 - ox + oxi) + (double)pFrame->ppData[oyi][ox1i * chans + c] * (ox1 - ox1i); for (x = oxi + 1; x < ox1i; x++) val += (double)pFrame->ppData[oyi][x * chans + c]; val /= ox1 - ox; } } else // one column of source pixels { if (oxi == ox1i) { val = (double)pFrame->ppData[oyi][oxi * chans + c] * (1 - oy + oyi) + (double)pFrame->ppData[oy1i][oxi * chans + c] * (oy1 - oy1i); for (y = oyi + 1; y < oy1i; y++) val += (double)pFrame->ppData[y][oxi * chans + c]; val /= oy1 - oy; } else // rectangle of source pixels { val = (double)pFrame->ppData[oyi][oxi * chans + c] * (1 - oy + oyi) * (1 - ox + oxi) + (double)pFrame->ppData[oyi][ox1i * chans + c] * (1 - oy + oyi) * (ox1 - ox1i) + (double)pFrame->ppData[oy1i][oxi * chans + c] * (oy1 - oy1i) * (1 - ox + oxi) + (double)pFrame->ppData[oy1i][ox1i * chans + c] * (oy1 - oy1i) * (ox1 - ox1i); for (y = oyi + 1; y < oy1i; y++) { val += (double)pFrame->ppData[y][oxi * chans + c] * (1 - ox + oxi) + (double)pFrame->ppData[y][ox1i * chans + c] * (ox1 - ox1i); } for (x = oxi + 1; x < ox1i; x++) { val += (double)pFrame->ppData[oyi][x * chans + c] * (1 - oy + oyi) + (double)pFrame->ppData[oy1i][x * chans + c] * (oy1 - oy1i); } for (y = oyi + 1; y < oy1i; y++) for (x = oxi + 1; x < ox1i; x++) val += (double)pFrame->ppData[y][x * chans + c]; val /= (oy1 - oy) * (ox1 - ox); } } ppData[ny][nx * chans + c] = (unsigned char)(val + 0.5); } } // for( nx ... } // for( ny ... } // for( c ... pFrame->height = height; pFrame->width = width; free(pFrame->ppData); pFrame->ppData = ppData; } void BlinkenFrameColorize(stBlinkenFrame *pFrame, int channels, int mode, int step) { unsigned char **ppData; int y, x, c, i, j; unsigned int val; if (pFrame == NULL) return; if (channels < BlinkenChannelsMin) channels = BlinkenChannelsMin; if (channels > BlinkenChannelsMax) channels = BlinkenMaxvalMax; // allocate new data array ppData = (unsigned char **)BlinkenMalloc2D(pFrame->height, pFrame->width * channels, sizeof(unsigned char)); if (ppData == NULL) return; for (y = 0; y < pFrame->height; y++) for (x = 0, i = 0; x < pFrame->width; x++) for (c = 0; c < channels; c++, i++) ppData[y][i] = 0; // colorize frame for (y = 0; y < pFrame->height; y++) { for (x = 0; x < pFrame->width; x++) { i = x * pFrame->channels; // merge channels val = 0; for (c = 0; c < pFrame->channels; c++, i++) val += pFrame->ppData[y][i]; val = (val + pFrame->channels / 2) / pFrame->channels; val = (val * BlinkenMaxvalMax + pFrame->maxval / 2) / pFrame->maxval; // colorize j = x * channels; for (c = 0; c < channels; c++, j++) { int color = BlinkenColorizerGetColor(channels, mode, step, y, x, c); ppData[y][j] = (unsigned char)((val * color + 127) / 255); } } } pFrame->channels = channels; pFrame->maxval = BlinkenMaxvalMax; free(pFrame->ppData); pFrame->ppData = ppData; } void BlinkenFrameCopyRect(stBlinkenFrame *pDest, int destY, int destX, stBlinkenFrame *pSrc, int srcY, int srcX, int height, int width) { int bFreeSrc = 0; int destI, srcI, y, x, c, dy, sy, di, si; if (pDest == NULL || pSrc == NULL) return; // make sure source frame matches dest frame in channels and maxval if (pSrc->channels != pDest->channels || pSrc->maxval != pDest->maxval) { pSrc = BlinkenFrameClone(pSrc); if (pSrc == NULL) return; BlinkenFrameResize(pSrc, pSrc->height, pSrc->width, pDest->channels, pDest->maxval); bFreeSrc = 1; // source is now a temporary copy that needs to be freed } // correct coordinates if (destY < 0) { height += destY; srcY -= destY; destY = 0; } if (destX < 0) { width += destX; srcX -= destX; destX = 0; } if (srcY < 0) { height += srcY; destY -= srcY; srcY = 0; } if (srcX < 0) { width += srcX; destX -= srcX; srcX = 0; } if (height > pDest->height - destY) height = pDest->height - destY; if (width > pDest->width - destX) width = pDest->width - destX; if (height > pSrc->height - srcY) height = pSrc->height - srcY; if (width > pSrc->width - srcX) width = pSrc->width - srcX; if (height < 0) height = 0; if (width < 0) width = 0; // copy rectangular area destI = destX * pDest->channels; srcI = srcX * pSrc->channels; for (y = 0, dy = destY, sy = srcY; y < height; y++, dy++, sy++) for (x = 0, di = destI, si = srcI; x < width; x++) for (c = 0; c < pDest->channels; c++, di++, si++) pDest->ppData[dy][di] = pSrc->ppData[sy][si]; // free source if it is a temporary copy if (bFreeSrc) BlinkenFrameFree(pSrc); } void BlinkenFrameRotateCw(stBlinkenFrame *pFrame) { int height, width, channels, y, x, c, i, j; unsigned char **ppData; if (pFrame == NULL) return; // allocate new data array height = pFrame->width; width = pFrame->height; channels = pFrame->channels; ppData = (unsigned char **)BlinkenMalloc2D(height, width * channels, sizeof(unsigned char)); if (ppData == NULL) return; // rotate for (y = 0; y < height; y++) { for (x = 0, i = 0; x < width; x++) { j = y * channels; for (c = 0; c < channels; c++, i++, j++) ppData[y][i] = pFrame->ppData[width - 1 - x][j]; } } // use new data array pFrame->height = height; pFrame->width = width; free(pFrame->ppData); pFrame->ppData = ppData; } void BlinkenFrameRotateCcw(stBlinkenFrame *pFrame) { int height, width, channels, y, x, c, i, j; unsigned char **ppData; if (pFrame == NULL) return; // allocate new data array height = pFrame->width; width = pFrame->height; channels = pFrame->channels; ppData = (unsigned char **)BlinkenMalloc2D(height, width * channels, sizeof(unsigned char)); if (ppData == NULL) return; // rotate for (y = 0; y < height; y++) { for (x = 0, i = 0; x < width; x++) { j = (height - 1 - y) * channels; for (c = 0; c < channels; c++, i++, j++) ppData[y][i] = pFrame->ppData[x][j]; } } // use new data array pFrame->height = height; pFrame->width = width; free(pFrame->ppData); pFrame->ppData = ppData; } void BlinkenFrameRotateHalf(stBlinkenFrame *pFrame) { int y1, y2, x1, x2, c, i1, i2; if (pFrame == NULL) return; for (y1 = 0, y2 = pFrame->height - 1 ; y1 < pFrame->height; y1++, y2--) { for (x1 = 0, x2 = pFrame->width - 1, i1 = 0, i2 = (pFrame->width - 1) * pFrame->channels; x1 < pFrame->width / 2; x1++, x2--, i2 -= 2 * pFrame->channels) { for (c = 0; c < pFrame->channels; c++, i1++, i2++) { unsigned char tmp = pFrame->ppData[y1][i1]; pFrame->ppData[y1][i1] = pFrame->ppData[y2][i2]; pFrame->ppData[y2][i2] = tmp; } } } } void BlinkenFrameMirrorHor(stBlinkenFrame *pFrame) { int y, x1, x2, c, i1, i2; if (pFrame == NULL) return; for (y = 0; y < pFrame->height; y++) { for (x1 = 0, x2 = pFrame->width - 1, i1 = 0, i2 = (pFrame->width - 1) * pFrame->channels; x1 < pFrame->width / 2; x1++, x2--, i2 -= 2 * pFrame->channels) { for (c = 0; c < pFrame->channels; c++, i1++, i2++) { unsigned char tmp = pFrame->ppData[y][i1]; pFrame->ppData[y][i1] = pFrame->ppData[y][i2]; pFrame->ppData[y][i2] = tmp; } } } } void BlinkenFrameMirrorVer(stBlinkenFrame *pFrame) { int y1, y2, x, c, i; if (pFrame == NULL) return; for (y1 = 0, y2 = pFrame->height - 1; y1 < pFrame->height / 2; y1++, y2--) { for (x = 0, i = 0; x < pFrame->width; x++) { for (c = 0; c < pFrame->channels; c++, i++) { unsigned char tmp = pFrame->ppData[y1][i]; pFrame->ppData[y1][i] = pFrame->ppData[y2][i]; pFrame->ppData[y2][i] = tmp; } } } } void BlinkenFrameMirrorDiag(stBlinkenFrame *pFrame) { int height, width, channels, y, x, c, i, j; unsigned char **ppData; if (pFrame == NULL) return; // allocate new data array height = pFrame->width; width = pFrame->height; channels = pFrame->channels; ppData = (unsigned char **)BlinkenMalloc2D(height, width * channels, sizeof(unsigned char)); if (ppData == NULL) return; // mirror for (y = 0; y < height; y++) { for (x = 0, i = 0; x < width; x++) { j = y * channels; for (c = 0; c < channels; c++, i++, j++) ppData[y][i] = pFrame->ppData[x][j]; } } // use new data array pFrame->height = height; pFrame->width = width; free(pFrame->ppData); pFrame->ppData = ppData; } void BlinkenFrameMirrorDiag2(stBlinkenFrame *pFrame) { int height, width, channels, y, x, c, i, j; unsigned char **ppData; if (pFrame == NULL) return; // allocate new data array height = pFrame->width; width = pFrame->height; channels = pFrame->channels; ppData = (unsigned char **)BlinkenMalloc2D(height, width * channels, sizeof(unsigned char)); if (ppData == NULL) return; // mirror for (y = 0; y < height; y++) { for (x = 0, i = 0; x < width; x++) { j = (height - 1 - y) * channels; for (c = 0; c < channels; c++, i++, j++) ppData[y][i] = pFrame->ppData[width - 1 - x][j]; } } // use new data array pFrame->height = height; pFrame->width = width; free(pFrame->ppData); pFrame->ppData = ppData; } char *BlinkenFrameToString(stBlinkenFrame *pFrame) { int size, y, x, c, i; char *str, *ptr; unsigned long val; if (pFrame == NULL) return NULL; size = pFrame->height * (pFrame->width + 1) + 32; str = (char *)malloc(size); if (str == NULL) return NULL; ptr = str; for (y = 0; y < pFrame->height; y++) { for (x = 0, i = 0; x < pFrame->width; x++) { val = 0; for (val = 0, c = 0; c < pFrame->channels; c++, i++) val += pFrame->ppData[y][i]; val = val * 7 / pFrame->maxval / pFrame->channels; *ptr = " -+*%#&@"[val]; ptr++; } *ptr = '\n'; ptr++; } sprintf(ptr, "%u ms\n", pFrame->duration); return str; } int BlinkenFrameToNetwork(stBlinkenFrame *pFrame, etBlinkenProto proto, char *pData, int maxLength) // returns length or -1 on error { int y, x, c, i, j, val; if (pFrame == NULL) return -1; switch (proto) { case BlinkenProtoNone: return 0; case BlinkenProtoBlp: // buffer too short if (maxLength < (int)sizeof(stBlinkenProtoBlpHdr) + pFrame->height * pFrame->width) return -1; // build header ((stBlinkenProtoBlpHdr *) pData)->magic = htonl(BlinkenProtoBlpMagic); ((stBlinkenProtoBlpHdr *) pData)->frameNo = htonl(0); ((stBlinkenProtoBlpHdr *) pData)->width = htons((uint16_t) pFrame->width); ((stBlinkenProtoBlpHdr *) pData)->height = htons((uint16_t) pFrame->height); i = sizeof(stBlinkenProtoBlpHdr); // put data into packet for (y = 0; y < pFrame->height; y++) { for (x = 0, j = 0; x < pFrame->width; x++, i++) { val = 0; for (c = 0; c < pFrame->channels; c++, j++) val += pFrame->ppData[y][j]; pData[i] = (val >= pFrame->channels * (pFrame->maxval + 1) / 2 ? 0x01 : 0x00); } } return i; // return length case BlinkenProtoEblp: // buffer too short if (maxLength < (int)sizeof(stBlinkenProtoEblpHdr) + pFrame->height * pFrame->width) return -1; // build header ((stBlinkenProtoEblpHdr *) pData)->magic = htonl(BlinkenProtoEblpMagic); ((stBlinkenProtoEblpHdr *) pData)->frameNo = htonl(0); ((stBlinkenProtoEblpHdr *) pData)->width = htons((uint16_t) pFrame->width); ((stBlinkenProtoEblpHdr *) pData)->height = htons((uint16_t) pFrame->height); i = sizeof(stBlinkenProtoEblpHdr); // put data into packet for (y = 0; y < pFrame->height; y++) { for (x = 0, j = 0; x < pFrame->width; x++, i++) { val = 0; for (c = 0; c < pFrame->channels; c++, j++) val += pFrame->ppData[y][j]; val /= pFrame->channels; pData[i] = (pFrame->maxval == 255 ? (unsigned char)val : (unsigned char)((val * 255 + pFrame->maxval / 2) / pFrame->maxval)); } } return i; // return length case BlinkenProtoMcuf: // buffer too short if (maxLength < (int)sizeof(stBlinkenProtoMcufHdr) + pFrame->height * pFrame->width * pFrame->channels) return -1; // build header ((stBlinkenProtoMcufHdr *) pData)->magic = htonl(BlinkenProtoMcufMagic); ((stBlinkenProtoMcufHdr *) pData)->height = htons((uint16_t) pFrame->height); ((stBlinkenProtoMcufHdr *) pData)->width = htons((uint16_t) pFrame->width); ((stBlinkenProtoMcufHdr *) pData)->channels = htons((uint16_t) pFrame->channels); ((stBlinkenProtoMcufHdr *) pData)->maxval = htons((uint16_t) pFrame->maxval); i = sizeof(stBlinkenProtoMcufHdr); // put data into packet for (y = 0; y < pFrame->height; y++) for (x = 0, j = 0; x < pFrame->width; x++) for (c = 0; c < pFrame->channels; c++, i++, j++) pData[i] = pFrame->ppData[y][j]; return i; // return length default: return -1; } } stBlinkenFrame *BlinkenFrameFromNetwork(const char *pData, int length, etBlinkenProto * pProto) // returns protocol in *pProto if pProto not NULL { stBlinkenFrame *pFrame; int height, width, channels, maxval, y, x, c, i, j; if (length >= (int)sizeof(stBlinkenProtoBlpHdr) && ((stBlinkenProtoBlpHdr *) pData)->magic == htonl(BlinkenProtoBlpMagic)) { if (pProto != NULL) // return protocol *pProto = BlinkenProtoBlp; // get header data height = ntohs(((stBlinkenProtoBlpHdr *) pData)->height); width = ntohs(((stBlinkenProtoBlpHdr *) pData)->width); // check length of packet if (length < (int)sizeof(stBlinkenProtoBlpHdr) + height * width) return NULL; // check header data if (height < BlinkenHeightMin || height > BlinkenHeightMax || width < BlinkenWidthMin || width > BlinkenWidthMax) return NULL; pFrame = BlinkenFrameNew(height, width, 1, 1, 0); // create frame // according to // header data if (pFrame == NULL) return NULL; i = sizeof(stBlinkenProtoBlpHdr); // put data into frame for (y = 0; y < pFrame->height; y++) for (x = 0; x < pFrame->width; x++, i++) pFrame->ppData[y][x] = pData[i] ? 0x01 : 0x00; return pFrame; } if (length >= (int)sizeof(stBlinkenProtoEblpHdr) && ((stBlinkenProtoEblpHdr *) pData)->magic == htonl(BlinkenProtoEblpMagic)) { if (pProto != NULL) // return protocol *pProto = BlinkenProtoEblp; // get header data height = ntohs(((stBlinkenProtoEblpHdr *) pData)->height); width = ntohs(((stBlinkenProtoEblpHdr *) pData)->width); // check length of packet if (length < (int)sizeof(stBlinkenProtoEblpHdr) + width * height) return NULL; // check header data if (height < BlinkenHeightMin || height > BlinkenHeightMax || width < BlinkenWidthMin || width > BlinkenWidthMax) return NULL; pFrame = BlinkenFrameNew(height, width, 1, 255, 0); // create frame // according to // header data if (pFrame == NULL) return NULL; i = sizeof(stBlinkenProtoEblpHdr); // put data into frame for (y = 0; y < pFrame->height; y++) for (x = 0; x < pFrame->width; x++, i++) pFrame->ppData[y][x] = pData[i]; return pFrame; } if (length >= (int)sizeof(stBlinkenProtoMcufHdr) && ((stBlinkenProtoMcufHdr *) pData)->magic == htonl(BlinkenProtoMcufMagic)) { if (pProto != NULL) // return protocol *pProto = BlinkenProtoMcuf; // get header data height = ntohs(((stBlinkenProtoMcufHdr *) pData)->height); width = ntohs(((stBlinkenProtoMcufHdr *) pData)->width); channels = ntohs(((stBlinkenProtoMcufHdr *) pData)->channels); maxval = ntohs(((stBlinkenProtoMcufHdr *) pData)->maxval); // check length of packet if (length < (int)sizeof(stBlinkenProtoMcufHdr) + height * width * channels) return NULL; // check header data if (height < BlinkenHeightMin || height > BlinkenHeightMax || width < BlinkenWidthMin || width > BlinkenWidthMax || channels < BlinkenChannelsMin || channels > BlinkenChannelsMax || maxval < BlinkenMaxvalMin || maxval > BlinkenMaxvalMax) return NULL; // create frame according to header data pFrame = BlinkenFrameNew(height, width, channels, maxval, 0); if (pFrame == NULL) return NULL; i = sizeof(stBlinkenProtoMcufHdr); // put data into frame for (y = 0; y < pFrame->height; y++) for (x = 0, j = 0; x < pFrame->width; x++) for (c = 0; c < pFrame->channels; c++, i++, j++) pFrame->ppData[y][j] = pData[i]; return pFrame; } if (pProto != NULL) // return protocol *pProto = BlinkenProtoNone; return NULL; }