mbed.org local branch of microbit-dal. The real version lives in git at https://github.com/lancaster-university/microbit-dal

Dependencies:   BLE_API nRF51822 mbed-dev-bin

Dependents:   microbit Microbit IoTChallenge1 microbit ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MicroBitImage.cpp Source File

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 }