fsdfds
Dependencies: BLE_API mbed-dev-bin nRF51822
Fork of microbit-dal by
MicroBitImage.cpp
00001 /* 00002 The MIT License (MIT) 00003 00004 Copyright (c) 2016 British Broadcasting Corporation. 00005 This software is provided by Lancaster University by arrangement with the BBC. 00006 00007 Permission is hereby granted, free of charge, to any person obtaining a 00008 copy of this software and associated documentation files (the "Software"), 00009 to deal in the Software without restriction, including without limitation 00010 the rights to use, copy, modify, merge, publish, distribute, sublicense, 00011 and/or sell copies of the Software, and to permit persons to whom the 00012 Software is furnished to do so, subject to the following conditions: 00013 00014 The above copyright notice and this permission notice shall be included in 00015 all copies or substantial portions of the Software. 00016 00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 00020 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00021 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 00022 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 00023 DEALINGS IN THE SOFTWARE. 00024 */ 00025 00026 /** 00027 * Class definition for a MicroBitImage. 00028 * 00029 * An MicroBitImage is a simple bitmap representation of an image. 00030 * n.b. This is a mutable, managed type. 00031 */ 00032 00033 #include "MicroBitConfig.h" 00034 #include "MicroBitImage.h" 00035 #include "MicroBitFont.h" 00036 #include "MicroBitCompat.h" 00037 #include "ManagedString.h" 00038 #include "ErrorNo.h" 00039 00040 00041 /** 00042 * The null image. We actally create a small one byte buffer here, just to keep NULL pointers out of the equation. 00043 */ 00044 static const uint16_t empty[] __attribute__ ((aligned (4))) = { 0xffff, 1, 1, 0, }; 00045 MicroBitImage MicroBitImage::EmptyImage((ImageData*)(void*)empty); 00046 00047 /** 00048 * Default Constructor. 00049 * Creates a new reference to the empty MicroBitImage bitmap 00050 * 00051 * @code 00052 * MicroBitImage i(); //an empty image instance 00053 * @endcode 00054 */ 00055 MicroBitImage::MicroBitImage() 00056 { 00057 // Create new reference to the EmptyImage and we're done. 00058 init_empty(); 00059 } 00060 00061 00062 /** 00063 * Constructor. 00064 * Create a blank bitmap representation of a given size. 00065 * 00066 * @param x the width of the image. 00067 * 00068 * @param y the height of the image. 00069 * 00070 * Bitmap buffer is linear, with 8 bits per pixel, row by row, 00071 * top to bottom with no word alignment. Stride is therefore the image width in pixels. 00072 * in where w and h are width and height respectively, the layout is therefore: 00073 * 00074 * |[0,0]...[w,o][1,0]...[w,1] ... [[w,h] 00075 * 00076 * A copy of the image is made in RAM, as images are mutable. 00077 * 00078 * TODO: Consider an immutable flavour, which might save us RAM for animation spritesheets... 00079 * ...as these could be kept in FLASH. 00080 */ 00081 MicroBitImage::MicroBitImage(const int16_t x, const int16_t y) 00082 { 00083 this->init(x,y,NULL); 00084 } 00085 00086 /** 00087 * Copy Constructor. 00088 * Add ourselves as a reference to an existing MicroBitImage. 00089 * 00090 * @param image The MicroBitImage to reference. 00091 * 00092 * @code 00093 * MicroBitImage i("0,1,0,1,0\n"); 00094 * MicroBitImage i2(i); //points to i 00095 * @endcode 00096 */ 00097 MicroBitImage::MicroBitImage(const MicroBitImage &image) 00098 { 00099 ptr = image.ptr; 00100 ptr->incr(); 00101 } 00102 00103 /** 00104 * Constructor. 00105 * Create a blank bitmap representation of a given size. 00106 * 00107 * @param s A text based representation of the image given whitespace delimited numeric values. 00108 * 00109 * @code 00110 * MicroBitImage i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image 00111 * @endcode 00112 */ 00113 MicroBitImage::MicroBitImage(const char *s) 00114 { 00115 int width = 0; 00116 int height = 0; 00117 int count = 0; 00118 int digit = 0; 00119 00120 char parseBuf[10]; 00121 00122 const char *parseReadPtr; 00123 char *parseWritePtr; 00124 uint8_t *bitmapPtr; 00125 00126 if (s == NULL) 00127 { 00128 init_empty(); 00129 return; 00130 } 00131 00132 // First pass: Parse the string to determine the geometry of the image. 00133 // We do this from first principles to avoid unecessary load of the strtok() libs etc. 00134 parseReadPtr = s; 00135 00136 while (*parseReadPtr) 00137 { 00138 if (isdigit(*parseReadPtr)) 00139 { 00140 // Ignore numbers. 00141 digit = 1; 00142 } 00143 else if (*parseReadPtr =='\n') 00144 { 00145 if (digit) 00146 { 00147 count++; 00148 digit = 0; 00149 } 00150 00151 height++; 00152 00153 width = count > width ? count : width; 00154 count = 0; 00155 } 00156 else 00157 { 00158 if (digit) 00159 { 00160 count++; 00161 digit = 0; 00162 } 00163 } 00164 00165 parseReadPtr++; 00166 } 00167 00168 this->init(width, height, NULL); 00169 00170 // Second pass: collect the data. 00171 parseReadPtr = s; 00172 parseWritePtr = parseBuf; 00173 bitmapPtr = this->getBitmap(); 00174 00175 while (*parseReadPtr) 00176 { 00177 if (isdigit(*parseReadPtr)) 00178 { 00179 *parseWritePtr = *parseReadPtr; 00180 parseWritePtr++; 00181 } 00182 else 00183 { 00184 *parseWritePtr = 0; 00185 if (parseWritePtr > parseBuf) 00186 { 00187 *bitmapPtr = atoi(parseBuf); 00188 bitmapPtr++; 00189 parseWritePtr = parseBuf; 00190 } 00191 } 00192 00193 parseReadPtr++; 00194 } 00195 } 00196 00197 /** 00198 * Constructor. 00199 * Create an image from a specially prepared constant array, with no copying. Will call ptr->incr(). 00200 * 00201 * @param ptr The literal - first two bytes should be 0xff, then width, 0, height, 0, and the bitmap. Width and height are 16 bit. The literal has to be 4-byte aligned. 00202 * 00203 * @code 00204 * static const uint8_t heart[] __attribute__ ((aligned (4))) = { 0xff, 0xff, 10, 0, 5, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart 00205 * MicroBitImage i((ImageData*)(void*)heart); 00206 * @endcode 00207 */ 00208 MicroBitImage::MicroBitImage(ImageData *p) 00209 { 00210 ptr = p; 00211 ptr->incr(); 00212 } 00213 00214 /** 00215 * Get current ptr, do not decr() it, and set the current instance to empty image. 00216 * 00217 * This is to be used by specialized runtimes which pass ImageData around. 00218 */ 00219 ImageData *MicroBitImage::leakData() 00220 { 00221 ImageData* res = ptr; 00222 init_empty(); 00223 return res; 00224 } 00225 00226 00227 /** 00228 * Constructor. 00229 * Create a bitmap representation of a given size, based on a given buffer. 00230 * 00231 * @param x the width of the image. 00232 * 00233 * @param y the height of the image. 00234 * 00235 * @param bitmap a 2D array representing the image. 00236 * 00237 * @code 00238 * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart 00239 * MicroBitImage i(10,5,heart); 00240 * @endcode 00241 */ 00242 MicroBitImage::MicroBitImage(const int16_t x, const int16_t y, const uint8_t *bitmap) 00243 { 00244 this->init(x,y,bitmap); 00245 } 00246 00247 /** 00248 * Destructor. 00249 * 00250 * Removes buffer resources held by the instance. 00251 */ 00252 MicroBitImage::~MicroBitImage() 00253 { 00254 ptr->decr(); 00255 } 00256 00257 /** 00258 * Internal constructor which defaults to the EmptyImage instance variable 00259 */ 00260 void MicroBitImage::init_empty() 00261 { 00262 ptr = (ImageData*)(void*)empty; 00263 } 00264 00265 /** 00266 * Internal constructor which provides sanity checking and initialises class properties. 00267 * 00268 * @param x the width of the image 00269 * 00270 * @param y the height of the image 00271 * 00272 * @param bitmap an array of integers that make up an image. 00273 */ 00274 void MicroBitImage::init(const int16_t x, const int16_t y, const uint8_t *bitmap) 00275 { 00276 //sanity check size of image - you cannot have a negative sizes 00277 if(x < 0 || y < 0) 00278 { 00279 init_empty(); 00280 return; 00281 } 00282 00283 00284 // Create a copy of the array 00285 ptr = (ImageData*)malloc(sizeof(ImageData) + x * y); 00286 ptr->init(); 00287 ptr->width = x; 00288 ptr->height = y; 00289 00290 // create a linear buffer to represent the image. We could use a jagged/2D array here, but experimentation 00291 // showed this had a negative effect on memory management (heap fragmentation etc). 00292 00293 if (bitmap) 00294 this->printImage(x,y,bitmap); 00295 else 00296 this->clear(); 00297 } 00298 00299 /** 00300 * Copy assign operation. 00301 * 00302 * Called when one MicroBitImage is assigned the value of another using the '=' operator. 00303 * 00304 * Decrement our reference count and free up the buffer as necessary. 00305 * 00306 * Then, update our buffer to refer to that of the supplied MicroBitImage, 00307 * and increase its reference count. 00308 * 00309 * @param s The MicroBitImage to reference. 00310 * 00311 * @code 00312 * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart 00313 * MicroBitImage i(10,5,heart); 00314 * MicroBitImage i1(); 00315 * i1 = i; // i1 now references i 00316 * @endcode 00317 */ 00318 MicroBitImage& MicroBitImage::operator = (const MicroBitImage& i) 00319 { 00320 if(ptr == i.ptr) 00321 return *this; 00322 00323 ptr->decr(); 00324 ptr = i.ptr; 00325 ptr->incr(); 00326 00327 return *this; 00328 } 00329 00330 /** 00331 * Equality operation. 00332 * 00333 * Called when one MicroBitImage is tested to be equal to another using the '==' operator. 00334 * 00335 * @param i The MicroBitImage to test ourselves against. 00336 * 00337 * @return true if this MicroBitImage is identical to the one supplied, false otherwise. 00338 * 00339 * @code 00340 * MicroBitDisplay display; 00341 * MicroBitImage i(); 00342 * MicroBitImage i1(); 00343 * 00344 * if(i == i1) //will be true 00345 * display.scroll("true"); 00346 * @endcode 00347 */ 00348 bool MicroBitImage::operator== (const MicroBitImage& i) 00349 { 00350 if (ptr == i.ptr) 00351 return true; 00352 else 00353 return (ptr->width == i.ptr->width && ptr->height == i.ptr->height && (memcmp(getBitmap(), i.ptr->data, getSize())==0)); 00354 } 00355 00356 00357 /** 00358 * Resets all pixels in this image to 0. 00359 * 00360 * @code 00361 * MicroBitImage i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image 00362 * i.clear(); 00363 * @endcode 00364 */ 00365 void MicroBitImage::clear() 00366 { 00367 memclr(getBitmap(), getSize()); 00368 } 00369 00370 /** 00371 * Sets the pixel at the given co-ordinates to a given value. 00372 * 00373 * @param x The co-ordinate of the pixel to change. 00374 * 00375 * @param y The co-ordinate of the pixel to change. 00376 * 00377 * @param value The new value of the pixel (the brightness level 0-255) 00378 * 00379 * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER. 00380 * 00381 * @code 00382 * MicroBitImage i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image 00383 * i.setPixelValue(0,0,255); 00384 * @endcode 00385 * 00386 * @note all coordinates originate from the top left of an image. 00387 */ 00388 int MicroBitImage::setPixelValue(int16_t x , int16_t y, uint8_t value) 00389 { 00390 //sanity check 00391 if(x >= getWidth() || y >= getHeight() || x < 0 || y < 0) 00392 return MICROBIT_INVALID_PARAMETER; 00393 00394 this->getBitmap()[y*getWidth()+x] = value; 00395 return MICROBIT_OK; 00396 } 00397 00398 /** 00399 * Retrieves the value of a given pixel. 00400 * 00401 * @param x The x co-ordinate of the pixel to read. Must be within the dimensions of the image. 00402 * 00403 * @param y The y co-ordinate of the pixel to read. Must be within the dimensions of the image. 00404 * 00405 * @return The value assigned to the given pixel location (the brightness level 0-255), or MICROBIT_INVALID_PARAMETER. 00406 * 00407 * @code 00408 * MicroBitImage i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image 00409 * i.getPixelValue(0,0); //should be 0; 00410 * @endcode 00411 */ 00412 int MicroBitImage::getPixelValue(int16_t x , int16_t y) 00413 { 00414 //sanity check 00415 if(x >= getWidth() || y >= getHeight() || x < 0 || y < 0) 00416 return MICROBIT_INVALID_PARAMETER; 00417 00418 return this->getBitmap()[y*getWidth()+x]; 00419 } 00420 00421 /** 00422 * Replaces the content of this image with that of a given 2D array representing 00423 * the image. 00424 * 00425 * @param x the width of the image. Must be within the dimensions of the image. 00426 * 00427 * @param y the width of the image. Must be within the dimensions of the image. 00428 * 00429 * @param bitmap a 2D array representing the image. 00430 * 00431 * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER. 00432 * 00433 * @code 00434 * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart 00435 * MicroBitImage i(); 00436 * i.printImage(0,0,heart); 00437 * @endcode 00438 * 00439 * @note all coordinates originate from the top left of an image. 00440 */ 00441 int MicroBitImage::printImage(int16_t width, int16_t height, const uint8_t *bitmap) 00442 { 00443 const uint8_t *pIn; 00444 uint8_t *pOut; 00445 int pixelsToCopyX, pixelsToCopyY; 00446 00447 // Sanity check. 00448 if (width <= 0 || width <= 0 || bitmap == NULL) 00449 return MICROBIT_INVALID_PARAMETER; 00450 00451 // Calcualte sane start pointer. 00452 pixelsToCopyX = min(width,this->getWidth()); 00453 pixelsToCopyY = min(height,this->getHeight()); 00454 00455 pIn = bitmap; 00456 pOut = this->getBitmap(); 00457 00458 // Copy the image, stride by stride. 00459 for (int i=0; i<pixelsToCopyY; i++) 00460 { 00461 memcpy(pOut, pIn, pixelsToCopyX); 00462 pIn += width; 00463 pOut += this->getWidth(); 00464 } 00465 00466 return MICROBIT_OK; 00467 } 00468 00469 /** 00470 * Pastes a given bitmap at the given co-ordinates. 00471 * 00472 * Any pixels in the relevant area of this image are replaced. 00473 * 00474 * @param image The MicroBitImage to paste. 00475 * 00476 * @param x The leftmost X co-ordinate in this image where the given image should be pasted. Defaults to 0. 00477 * 00478 * @param y The uppermost Y co-ordinate in this image where the given image should be pasted. Defaults to 0. 00479 * 00480 * @param alpha set to 1 if transparency clear pixels in given image should be treated as transparent. Set to 0 otherwise. Defaults to 0. 00481 * 00482 * @return The number of pixels written. 00483 * 00484 * @code 00485 * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart 00486 * MicroBitImage i(10,5,heart); // a big heart 00487 * i.paste(i, -5, 0); // a small heart 00488 * @endcode 00489 */ 00490 int MicroBitImage::paste(const MicroBitImage &image, int16_t x, int16_t y, uint8_t alpha) 00491 { 00492 uint8_t *pIn, *pOut; 00493 int cx, cy; 00494 int pxWritten = 0; 00495 00496 // Sanity check. 00497 // We permit writes that overlap us, but ones that are clearly out of scope we can filter early. 00498 if (x >= getWidth() || y >= getHeight() || x+image.getWidth() <= 0 || y+image.getHeight() <= 0) 00499 return 0; 00500 00501 //Calculate the number of byte we need to copy in each dimension. 00502 cx = x < 0 ? min(image.getWidth() + x, getWidth()) : min(image.getWidth(), getWidth() - x); 00503 cy = y < 0 ? min(image.getHeight() + y, getHeight()) : min(image.getHeight(), getHeight() - y); 00504 00505 // Calculate sane start pointer. 00506 pIn = image.ptr->data; 00507 pIn += (x < 0) ? -x : 0; 00508 pIn += (y < 0) ? -image.getWidth()*y : 0; 00509 00510 pOut = getBitmap(); 00511 pOut += (x > 0) ? x : 0; 00512 pOut += (y > 0) ? getWidth()*y : 0; 00513 00514 // Copy the image, stride by stride 00515 // If we want primitive transparecy, we do this byte by byte. 00516 // If we don't, use a more efficient block memory copy instead. Every little helps! 00517 00518 if (alpha) 00519 { 00520 for (int i=0; i<cy; i++) 00521 { 00522 for (int j=0; j<cx; j++) 00523 { 00524 // Copy this byte if appropriate. 00525 if (*(pIn+j) != 0){ 00526 *(pOut+j) = *(pIn+j); 00527 pxWritten++; 00528 } 00529 } 00530 00531 pIn += image.getWidth(); 00532 pOut += getWidth(); 00533 } 00534 } 00535 else 00536 { 00537 for (int i=0; i<cy; i++) 00538 { 00539 memcpy(pOut, pIn, cx); 00540 00541 pxWritten += cx; 00542 pIn += image.getWidth(); 00543 pOut += getWidth(); 00544 } 00545 } 00546 00547 return pxWritten; 00548 } 00549 00550 /** 00551 * Prints a character to the display at the given location 00552 * 00553 * @param c The character to display. 00554 * 00555 * @param x The x co-ordinate of on the image to place the top left of the character. Defaults to 0. 00556 * 00557 * @param y The y co-ordinate of on the image to place the top left of the character. Defaults to 0. 00558 * 00559 * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER. 00560 * 00561 * @code 00562 * MicroBitImage i(5,5); 00563 * i.print('a'); 00564 * @endcode 00565 */ 00566 int MicroBitImage::print(char c, int16_t x, int16_t y) 00567 { 00568 unsigned char v; 00569 int x1, y1; 00570 00571 MicroBitFont font = MicroBitFont::getSystemFont(); 00572 00573 // Sanity check. Silently ignore anything out of bounds. 00574 if (x >= getWidth() || y >= getHeight() || c < MICROBIT_FONT_ASCII_START || c > font.asciiEnd) 00575 return MICROBIT_INVALID_PARAMETER; 00576 00577 // Paste. 00578 int offset = (c-MICROBIT_FONT_ASCII_START) * 5; 00579 00580 for (int row=0; row<MICROBIT_FONT_HEIGHT; row++) 00581 { 00582 v = (char)*(font.characters + offset); 00583 00584 offset++; 00585 00586 // Update our Y co-ord write position 00587 y1 = y+row; 00588 00589 for (int col = 0; col < MICROBIT_FONT_WIDTH; col++) 00590 { 00591 // Update our X co-ord write position 00592 x1 = x+col; 00593 00594 if (x1 < getWidth() && y1 < getHeight()) 00595 this->getBitmap()[y1*getWidth()+x1] = (v & (0x10 >> col)) ? 255 : 0; 00596 } 00597 } 00598 00599 return MICROBIT_OK; 00600 } 00601 00602 00603 /** 00604 * Shifts the pixels in this Image a given number of pixels to the left. 00605 * 00606 * @param n The number of pixels to shift. 00607 * 00608 * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER. 00609 * 00610 * @code 00611 * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart 00612 * MicroBitImage i(10,5,heart); // a big heart 00613 * i.shiftLeft(5); // a small heart 00614 * @endcode 00615 */ 00616 int MicroBitImage::shiftLeft(int16_t n) 00617 { 00618 uint8_t *p = getBitmap(); 00619 int pixels = getWidth()-n; 00620 00621 if (n <= 0 ) 00622 return MICROBIT_INVALID_PARAMETER; 00623 00624 if(n >= getWidth()) 00625 { 00626 clear(); 00627 return MICROBIT_OK; 00628 } 00629 00630 for (int y = 0; y < getHeight(); y++) 00631 { 00632 // Copy, and blank fill the rightmost column. 00633 memcpy(p, p+n, pixels); 00634 memclr(p+pixels, n); 00635 p += getWidth(); 00636 } 00637 00638 return MICROBIT_OK; 00639 } 00640 00641 /** 00642 * Shifts the pixels in this Image a given number of pixels to the right. 00643 * 00644 * @param n The number of pixels to shift. 00645 * 00646 * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER. 00647 * 00648 * @code 00649 * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart 00650 * MicroBitImage i(10,5,heart); // a big heart 00651 * i.shiftLeft(5); // a small heart 00652 * i.shiftRight(5); // a big heart 00653 * @endcode 00654 */ 00655 int MicroBitImage::shiftRight(int16_t n) 00656 { 00657 uint8_t *p = getBitmap(); 00658 int pixels = getWidth()-n; 00659 00660 if (n <= 0) 00661 return MICROBIT_INVALID_PARAMETER; 00662 00663 if(n >= getWidth()) 00664 { 00665 clear(); 00666 return MICROBIT_OK; 00667 } 00668 00669 for (int y = 0; y < getHeight(); y++) 00670 { 00671 // Copy, and blank fill the leftmost column. 00672 memmove(p+n, p, pixels); 00673 memclr(p, n); 00674 p += getWidth(); 00675 } 00676 00677 return MICROBIT_OK; 00678 } 00679 00680 00681 /** 00682 * Shifts the pixels in this Image a given number of pixels to upward. 00683 * 00684 * @param n The number of pixels to shift. 00685 * 00686 * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER. 00687 * 00688 * @code 00689 * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart 00690 * MicroBitImage i(10,5,heart); 00691 * i.shiftUp(1); 00692 * @endcode 00693 */ 00694 int MicroBitImage::shiftUp(int16_t n) 00695 { 00696 uint8_t *pOut, *pIn; 00697 00698 if (n <= 0 ) 00699 return MICROBIT_INVALID_PARAMETER; 00700 00701 if(n >= getHeight()) 00702 { 00703 clear(); 00704 return MICROBIT_OK; 00705 } 00706 00707 pOut = getBitmap(); 00708 pIn = getBitmap()+getWidth()*n; 00709 00710 for (int y = 0; y < getHeight(); y++) 00711 { 00712 // Copy, and blank fill the leftmost column. 00713 if (y < getHeight()-n) 00714 memcpy(pOut, pIn, getWidth()); 00715 else 00716 memclr(pOut, getWidth()); 00717 00718 pIn += getWidth(); 00719 pOut += getWidth(); 00720 } 00721 00722 return MICROBIT_OK; 00723 } 00724 00725 00726 /** 00727 * Shifts the pixels in this Image a given number of pixels to downward. 00728 * 00729 * @param n The number of pixels to shift. 00730 * 00731 * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER. 00732 * 00733 * @code 00734 * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart 00735 * MicroBitImage i(10,5,heart); 00736 * i.shiftDown(1); 00737 * @endcode 00738 */ 00739 int MicroBitImage::shiftDown(int16_t n) 00740 { 00741 uint8_t *pOut, *pIn; 00742 00743 if (n <= 0 ) 00744 return MICROBIT_INVALID_PARAMETER; 00745 00746 if(n >= getHeight()) 00747 { 00748 clear(); 00749 return MICROBIT_OK; 00750 } 00751 00752 pOut = getBitmap() + getWidth()*(getHeight()-1); 00753 pIn = pOut - getWidth()*n; 00754 00755 for (int y = 0; y < getHeight(); y++) 00756 { 00757 // Copy, and blank fill the leftmost column. 00758 if (y < getHeight()-n) 00759 memcpy(pOut, pIn, getWidth()); 00760 else 00761 memclr(pOut, getWidth()); 00762 00763 pIn -= getWidth(); 00764 pOut -= getWidth(); 00765 } 00766 00767 return MICROBIT_OK; 00768 } 00769 00770 00771 /** 00772 * Converts the bitmap to a csv ManagedString. 00773 * 00774 * @code 00775 * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart 00776 * MicroBitImage i(10,5,heart); 00777 * uBit.serial.printString(i.toString()); // "0,1,0,1,0,0,0,0,0,0\n..." 00778 * @endcode 00779 */ 00780 ManagedString MicroBitImage::toString() 00781 { 00782 //width including commans and \n * height 00783 int stringSize = getSize() * 2; 00784 00785 //plus one for string terminator 00786 char parseBuffer[stringSize + 1]; 00787 00788 parseBuffer[stringSize] = '\0'; 00789 00790 uint8_t *bitmapPtr = getBitmap(); 00791 00792 int parseIndex = 0; 00793 int widthCount = 0; 00794 00795 while (parseIndex < stringSize) 00796 { 00797 if(*bitmapPtr) 00798 parseBuffer[parseIndex] = '1'; 00799 else 00800 parseBuffer[parseIndex] = '0'; 00801 00802 parseIndex++; 00803 00804 if(widthCount == getWidth()-1) 00805 { 00806 parseBuffer[parseIndex] = '\n'; 00807 widthCount = 0; 00808 } 00809 else 00810 { 00811 parseBuffer[parseIndex] = ','; 00812 widthCount++; 00813 } 00814 00815 parseIndex++; 00816 bitmapPtr++; 00817 } 00818 00819 return ManagedString(parseBuffer); 00820 } 00821 00822 /** 00823 * Crops the image to the given dimensions. 00824 * 00825 * @param startx the location to start the crop in the x-axis 00826 * 00827 * @param starty the location to start the crop in the y-axis 00828 * 00829 * @param width the width of the desired cropped region 00830 * 00831 * @param height the height of the desired cropped region 00832 * 00833 * @code 00834 * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart 00835 * MicroBitImage i(10,5,heart); 00836 * i.crop(0,0,2,2).toString() // "0,1\n1,1\n" 00837 * @endcode 00838 */ 00839 MicroBitImage MicroBitImage::crop(int startx, int starty, int cropWidth, int cropHeight) 00840 { 00841 int newWidth = startx + cropWidth; 00842 int newHeight = starty + cropHeight; 00843 00844 if (newWidth >= getWidth() || newWidth <=0) 00845 newWidth = getWidth(); 00846 00847 if (newHeight >= getHeight() || newHeight <= 0) 00848 newHeight = getHeight(); 00849 00850 //allocate our storage. 00851 uint8_t cropped[newWidth * newHeight]; 00852 00853 //calculate the pointer to where we want to begin cropping 00854 uint8_t *copyPointer = getBitmap() + (getWidth() * starty) + startx; 00855 00856 //get a reference to our storage 00857 uint8_t *pastePointer = cropped; 00858 00859 //go through row by row and select our image. 00860 for (int i = starty; i < newHeight; i++) 00861 { 00862 memcpy(pastePointer, copyPointer, newWidth); 00863 00864 copyPointer += getWidth(); 00865 pastePointer += newHeight; 00866 } 00867 00868 return MicroBitImage(newWidth, newHeight, cropped); 00869 } 00870 00871 /** 00872 * Check if image is read-only (i.e., residing in flash). 00873 */ 00874 bool MicroBitImage::isReadOnly() 00875 { 00876 return ptr->isReadOnly(); 00877 } 00878 00879 /** 00880 * Create a copy of the image bitmap. Used particularly, when isReadOnly() is true. 00881 * 00882 * @return an instance of MicroBitImage which can be modified independently of the current instance 00883 */ 00884 MicroBitImage MicroBitImage::clone() 00885 { 00886 return MicroBitImage(getWidth(), getHeight(), getBitmap()); 00887 }
Generated on Wed Jul 13 2022 00:58:03 by 1.7.2