00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include "cxutils/images/image.h"
00042 #include "cxutils/fileio.h"
00043 #include <assert.h>
00044 #include <string.h>
00045 #include <cstdio>
00046
00047 using namespace CxUtils;
00048
00054 Image::Image()
00055 {
00056 mpImage = NULL;
00057 mDataSize = 0;
00058 mWidth = 0;
00059 mHeight = 0;
00060 mChannels = 0;
00061 }
00062
00068 Image::Image(const Image& img)
00069 {
00070 mpImage = NULL;
00071 mDataSize = 0;
00072 mWidth = 0;
00073 mHeight = 0;
00074 mChannels = 0;
00075 *this = img;
00076 }
00077
00078
00085 Image::~Image()
00086 {
00087 Destroy();
00088 }
00089
00090
00106 int Image::Create(const unsigned short width,
00107 const unsigned short height,
00108 const unsigned char channels,
00109 const unsigned char* rawImage,
00110 const bool verticalFlip)
00111 {
00112 if(width == 0 || height == 0 || !(channels == 1 || channels == 3 || channels == 4) )
00113 {
00114 return 0;
00115 }
00116
00117 if (mHeight != height || mWidth != width || mChannels != channels)
00118 {
00119 Destroy();
00120 mHeight = height;
00121 mWidth = width;
00122 mChannels = channels;
00123 mDataSize = mHeight*mWidth*mChannels*sizeof(unsigned char);
00124 mpImage = new unsigned char[mDataSize + 100];
00125 assert(mpImage);
00126 }
00127
00128 if (rawImage != NULL)
00129 {
00130 if(verticalFlip)
00131 {
00132 unsigned int widthStep = width*channels;
00133 for(unsigned int row1 = 0, row2 = height - 1;
00134 row1 < height;
00135 row1++, row2--)
00136 {
00137 memcpy(&mpImage[row1*widthStep], &rawImage[row2*widthStep], widthStep);
00138 }
00139 }
00140 else
00141 {
00142 memcpy(mpImage, rawImage, mDataSize);
00143 }
00144 }
00145
00146 return 1;
00147 }
00148
00149
00166 int Image::Create(const unsigned short width,
00167 const unsigned short height,
00168 const unsigned char channels,
00169 const unsigned char* rawImage,
00170 const double scale,
00171 const bool verticalFlip)
00172 {
00173
00174 if(rawImage == NULL)
00175 {
00176 return 0;
00177 }
00178
00179 if(scale >= 0.99 && scale <= 1.01)
00180 {
00181 return Create(width, height, channels, rawImage, verticalFlip);
00182 }
00183
00184 unsigned short newHeight, newWidth;
00185 double magnitude;
00186 newHeight = (unsigned short)(height*scale);
00187 newWidth = (unsigned short)(width*scale);
00188
00189 if(newHeight == 0 || newWidth == 0) { return 0; }
00190
00191 if(scale < 1.0)
00192 {
00193 magnitude = (double)(height)/newHeight;
00194 }
00195 else
00196 {
00197 magnitude = (double)(newHeight)/height;
00198 }
00199
00200
00201 Create(newWidth, newHeight, channels, NULL, false);
00202 unsigned short x, y;
00203 if(scale < 1)
00204 {
00205 for(unsigned short i = 0; i < newHeight; i++)
00206 {
00207 if(verticalFlip)
00208 {
00209 y = (unsigned short)((newHeight - i - 1)*magnitude);
00210 }
00211 else
00212 {
00213 y = (unsigned short)(i*magnitude);
00214 }
00215 for(unsigned short j = 0; j < newWidth; j++)
00216 {
00217 if(channels == 1)
00218 {
00219 x = (unsigned short)(j*magnitude);
00220 mpImage[i*newWidth + j] = rawImage[y*width + x];
00221 }
00222 else if(channels == 3)
00223 {
00224 x = (unsigned short)(j*magnitude);
00225 mpImage[i*newWidth*3 + j*3] = rawImage[y*width*3 + x*3];
00226 mpImage[i*newWidth*3 + j*3 + 1] = rawImage[y*width*3 + x*3 + 1];
00227 mpImage[i*newWidth*3 + j*3 + 2] = rawImage[y*width*3 + x*3 + 2];
00228 }
00229 else
00230 {
00231 x = (unsigned short)(j*magnitude);
00232 for(unsigned short k = 0; k < channels; k++)
00233 {
00234 mpImage[i*newWidth*channels + j*channels + k] = rawImage[y*width*channels + x*channels + k];
00235 }
00236 }
00237 }
00238 }
00239 }
00240 else
00241 {
00242 for(unsigned short i = 0; i < height; i++)
00243 {
00244 if(verticalFlip)
00245 {
00246 y = (height - i - 1);
00247 }
00248 else
00249 {
00250 y = i;
00251 }
00252 for(unsigned short j = 0; j < width; j++)
00253 {
00254
00255
00256 for(unsigned short m = (unsigned short)(i*magnitude); m < (unsigned short)((i+1)*magnitude); m++)
00257 {
00258 for(unsigned short n = (unsigned short)(j*magnitude); n < (unsigned short)((j+1)*magnitude); n++)
00259 {
00260 if(channels == 1)
00261 {
00262 mpImage[m*newWidth + n] = rawImage[y*width + j];
00263 }
00264 else if(channels == 3)
00265 {
00266 mpImage[m*newWidth*3 + n*3] = rawImage[y*width*3 + j*3];
00267 mpImage[m*newWidth*3 + n*3 + 1] = rawImage[y*width*3 + j*3 + 1];
00268 mpImage[m*newWidth*3 + n*3 + 2] = rawImage[y*width*3 + j*3 + 2];
00269 }
00270 else
00271 {
00272 for(unsigned short k = 0; k < channels; k++)
00273 {
00274 mpImage[m*newWidth*channels + n*channels + k] = rawImage[y*width*channels + j*channels + k];
00275 }
00276 }
00277 }
00278 }
00279 }
00280 }
00281 }
00282 return 1;
00283 }
00284
00285
00303 int Image::Create(const unsigned short width,
00304 const unsigned short height,
00305 const unsigned char channels,
00306 const unsigned char* rawImage,
00307 const unsigned short maxWidth,
00308 const unsigned short maxHeight,
00309 const bool verticalFlip)
00310 {
00311 Image temp;
00312
00313 double scaleFactor1 = 1.0, scaleFactor2 = 1.0;
00314
00315 if(maxWidth == 0 || maxHeight == 0)
00316 {
00317 return Create(width, height, channels, rawImage, verticalFlip);
00318 }
00319
00320 if(maxWidth > width && maxHeight > height)
00321 {
00322 return 0;
00323 }
00324 scaleFactor1 = (double)(maxWidth)/width;
00325 scaleFactor2 = (double)(maxHeight)/height;
00326 if(scaleFactor2 < scaleFactor1)
00327 {
00328 scaleFactor1 = scaleFactor2;
00329 }
00330
00331 if(temp.Create(width, height, channels, rawImage, scaleFactor1, verticalFlip) == 0)
00332 {
00333 return 0;
00334 }
00335
00336
00337 Create(maxWidth, maxHeight, channels, NULL, false);
00338 memset(mpImage, 0, maxWidth*maxHeight*channels*sizeof(unsigned char));
00339 unsigned char* ptr1, *ptr2;
00340 int startRow, startCol;
00341 ptr1 = mpImage;
00342 ptr2 = temp.mpImage;
00343
00344
00345
00346 startRow = ((int)(maxHeight) - 1)/2 - ((int)(temp.mHeight) - 1)/2;
00347 startCol = ((int)(maxWidth) - 1)/2 - ((int)(temp.mWidth) - 1)/2;
00348 if(startRow < 0)
00349 startRow = 0;
00350 if(startCol < 0)
00351 startCol = 0;
00352
00353 for(int i = startRow, m = 0; i < maxHeight && m < temp.mHeight; i++, m++)
00354 {
00355 for(int j = startCol, n = 0; j < maxWidth && n < temp.mWidth; j++, n++)
00356 {
00357 if(channels == 1)
00358 {
00359 mpImage[i*maxWidth*channels + j*channels] = temp.mpImage[m*temp.mWidth*channels + n*channels];
00360 }
00361 else if(channels == 3)
00362 {
00363 mpImage[i*maxWidth*channels + j*channels] = temp.mpImage[m*temp.mWidth*channels + n*channels];
00364 mpImage[i*maxWidth*channels + j*channels + 1] = temp.mpImage[m*temp.mWidth*channels + n*channels + 1];
00365 mpImage[i*maxWidth*channels + j*channels + 2] = temp.mpImage[m*temp.mWidth*channels + n*channels + 2];
00366 }
00367 else
00368 {
00369 for(int k = 0; k < channels; k++)
00370 {
00371 mpImage[i*maxWidth*channels + j*channels + k] = temp.mpImage[m*temp.mWidth*channels + n*channels + k];
00372 }
00373 }
00374 }
00375 }
00376 return 1;
00377 }
00378
00379
00380
00400 int Image::Compress(unsigned char** buffer,
00401 unsigned int* len,
00402 unsigned int* clen,
00403 const Format format,
00404 void* args) const
00405 {
00406 return Compress(mpImage, mWidth, mHeight, mChannels, buffer, len, clen, format, args);
00407 }
00408
00409
00433 int Image::Compress(unsigned char* image,
00434 unsigned int width,
00435 unsigned int height,
00436 unsigned char channels,
00437 unsigned char** buffer,
00438 unsigned int* len,
00439 unsigned int* clen,
00440 const Format format,
00441 void* args)
00442 {
00443 int result = 0;
00444
00445 switch (format)
00446 {
00447 case PNG:
00448 result = PNG::CompressImage(width, height, channels, image, buffer, len, clen);
00449 break;
00450 case JPEG:
00451 {
00452 int quality = -1;
00453 if(args)
00454 {
00455 quality = *((int *)(args));
00456 }
00457 result = JPEG::CompressImage(width, height, channels, image, buffer, len, clen, quality);
00458 }
00459 break;
00460 case MJPEG:
00461 {
00462 int quality = -1;
00463 if(args)
00464 {
00465 quality = *((int *)(args));
00466 }
00467 result = JPEG::CompressImage(width, height, channels, image, buffer, len, clen, quality);
00468 }
00469 break;
00470 default:
00471 result = 0;
00472 break;
00473 }
00474
00475 return 1;
00476 }
00477
00478
00491 int Image::Decompress(const unsigned char* compressed,
00492 const unsigned int len,
00493 const Format format)
00494 {
00495 int result = 0;
00496
00497 switch (format)
00498 {
00499 case PNG:
00500 result = PNG::DecompressImage(compressed, len, &mpImage, &mWidth, &mHeight, &mChannels);
00501 break;
00502 case JPEG:
00503 result = JPEG::DecompressImage(compressed, len, &mpImage, &mWidth, &mHeight, &mChannels);
00504 break;
00505 case MJPEG:
00506 result = JPEG::DecompressImage(compressed, len, &mpImage, &mWidth, &mHeight, &mChannels);
00507 break;
00508 default:
00509 result = 0;
00510 break;
00511 }
00512
00513 return result;
00514 }
00515
00516
00524 int Image::Destroy()
00525 {
00526 if( mpImage )
00527 {
00528 delete[] mpImage;
00529 mpImage = NULL;
00530 }
00531 mDataSize = 0;
00532 mWidth = 0;
00533 mHeight = 0;
00534 mChannels = 0;
00535 return 1;
00536 }
00537
00538
00549 int Image::Save(const std::string& file) const
00550 {
00551 int result = 0;
00552 FILE *fp = NULL;
00553 Format format = GetFormat(file);
00554 unsigned char *buffer = NULL;
00555 unsigned len = 0;
00556 unsigned int clen = 0;
00557
00558 if( format == Invalid )
00559 {
00560 return 0;
00561 }
00562 int quality = 100;
00563 if( Compress(&buffer, &len, &clen, format, &quality ) )
00564 {
00565 fp = fopen( file.c_str() , "wb");
00566 if( fp && fwrite(buffer, clen, 1, fp) )
00567 {
00568 result = 1;
00569 }
00570 }
00571
00572 if(fp)
00573 {
00574 fclose(fp);
00575 if(result == 0)
00576 {
00577 FileIO::DeleteFiles(file);
00578 }
00579 }
00580 if( buffer )
00581 delete[] buffer;
00582
00583 return result;
00584 }
00585
00586
00599 int Image::SaveCompressedImage(const std::string& name,
00600 const unsigned char* data,
00601 const unsigned int size,
00602 const Format format)
00603 {
00604 int result = 0;
00605 FILE *fp = NULL;
00606
00607 std::string file = name;
00608 switch(format)
00609 {
00610 case JPEG:
00611 file += ".jpg";
00612 break;
00613 case PNG:
00614 file += ".png";
00615 break;
00616 case MJPEG:
00617 file += ".jpg";
00618 break;
00619 case BMP:
00620 file += ".bmp";
00621 break;
00622 case TIFF:
00623 file += ".tiff";
00624 break;
00625 case GIF:
00626 file += ".gif";
00627 break;
00628 case PPM:
00629 file += ".ppm";
00630 break;
00631 case PGM:
00632 file += ".pgm";
00633 break;
00634 default:
00635 file += ".jpg";
00636 break;
00637 };
00638
00639 if( data && size > 0 )
00640 {
00641 fp = fopen( file.c_str() , "w+b");
00642 if( fp && fwrite(data, size, 1, fp) )
00643 {
00644 result = 1;
00645 }
00646 }
00647
00648 if(fp)
00649 {
00650 fclose(fp);
00651 if(result == 0)
00652 {
00653 FileIO::DeleteFiles(file);
00654 }
00655 }
00656
00657 return result;
00658 }
00659
00660
00668 void Image::ApplyTile(const Image& tile)
00669 {
00670 if(tile.mChannels == mChannels && mWidth > 0 && mHeight > 0 && tile.mWidth > 0 && tile.mHeight > 0)
00671 {
00672 double w, h;
00673 w = mWidth*1.0/tile.mWidth;
00674 h = mHeight*1.0/tile.mHeight;
00675 for(double r = 0; r < h; r++)
00676 {
00677 for(double c = 0; c < w; c++)
00678 {
00679 unsigned char* d = tile.mpImage;
00680 for(unsigned short int i = 0; i < tile.mHeight; i++)
00681 {
00682 for(unsigned short int j = 0; j < tile.mWidth; j++)
00683 {
00684 unsigned short int xOffset = (unsigned short int)(c*tile.mWidth);
00685 unsigned short int yOffset = (unsigned short int)(r*tile.mHeight);
00686
00687 for(unsigned char ch = 0; ch < mChannels; ch++)
00688 {
00689 unsigned int oPosition = (yOffset + i)*mWidth*mChannels + (xOffset + j)*mChannels + ch;
00690 if(oPosition < mDataSize)
00691 {
00692 mpImage[oPosition] = d[i*tile.mWidth*tile.mChannels + j*tile.mChannels + ch];
00693 }
00694 }
00695
00696 }
00697 }
00698 }
00699 }
00700 }
00701 }
00702
00703
00714 int Image::Load(const std::string& file)
00715 {
00716 Format format = GetFormat(file);
00717 int result = 0;
00718 unsigned int len = 0;
00719 unsigned char* buffer = NULL;
00720
00721
00722 if( format == Invalid)
00723 {
00724
00725 return 0;
00726 }
00727
00728 FILE *fp = fopen(file.c_str(), "r+b");
00729 if( fp )
00730 {
00731
00732
00733 while( !feof(fp))
00734 {
00735 fgetc(fp);
00736 len++;
00737 }
00738 --len;
00739 if( len > 0 )
00740 {
00741 buffer = new unsigned char[len + 1];
00742 rewind(fp);
00743 if( fread( buffer, len, 1, fp) )
00744 {
00745 result = Decompress(buffer, len, format);
00746 if(result > 0)
00747 {
00748 mDataSize = mWidth*mHeight*mChannels;
00749 }
00750 }
00751 }
00752 }
00753 if(fp)
00754 {
00755 fclose(fp);
00756 }
00757 if( buffer )
00758 {
00759 delete[] buffer;
00760 }
00761
00762 return result;
00763 }
00764
00765
00776 Image::Format Image::GetFormat(const std::string& file)
00777 {
00778 if ( strstr(file.c_str(), ".png") || strstr(file.c_str(), ".PNG") )
00779 {
00780 return PNG;
00781 }
00782 else if ( strstr(file.c_str(), ".jpeg") || strstr(file.c_str(),".JPEG") ||
00783 strstr(file.c_str(), ".JPG") || strstr(file.c_str(), ".jpg") )
00784 {
00785 return JPEG;
00786 }
00787
00788 return Invalid;
00789 }
00790
00791
00797 Image& Image::operator=(const Image& img)
00798 {
00799 if(this != &img)
00800 {
00801 if (mHeight != img.mHeight || mWidth != img.mWidth || mChannels != img.mChannels)
00802 {
00803 Destroy();
00804 }
00805 if (img.mpImage != NULL)
00806 {
00807 if(mpImage == NULL)
00808 {
00809 Create(img.mWidth, img.mHeight, img.mChannels, img.mpImage);
00810 }
00811 else
00812 {
00813 memcpy(mpImage, img.mpImage, mDataSize);
00814 }
00815 }
00816 }
00817 return *this;
00818 }
00819
00820
00821