NOTES: Porting IIPImage Server to VS2010

by

If you aren’t interesting in porting C\C++ code to VS2010, nor are you interested in Image Processing Servers; you probably want to stop reading right about ….. here.

For the rest of you, this is a rough documentation of what I have done to get IIP to compile under Windows 7 Ultimate (x64) using Visual Studio 2010 (version 10.0.30319.1). There are my notes for getting it to compile, there are still a few issues, but it compiles and it runs under Apache on Windows. Even though this is a x64 OS, we are relentlessly targeting an x32 architecture in the build.

Created an IIP_Port directory structure

image

Using Visual Studio 10

LIBFCGI

  1. Acquired from: http://www.fastcgi.com/dist/fcgi.tar.gz
  2. Open C:\iip_port\fcgi-2.4.0\Win32\libfcgi.dsp in Visual Studio.
  3. Copy fcgi_config_x86.h to fcgi_config.h
  4. Convert and Open Projects (Yes)
  5. Build Debug version (Save Solution Name)
  6. Verify C:\iip_port\fcgi-2.4.0\libfcgi\Debug\libfcgi.dll exists
  7. Build Release version
  8. Verify C:\iip_port\fcgi-2.4.0\libfcgi\Release\libfcgi.dll exists
  9. Verify C:\iip_port\fcgi-2.4.0\libfcgi\Release\libfcgi.lib exists

LIBJPEG

  1. Acquired from: http://www.ijg.org/files/jpegsr8c.zip
  2. Run C:\iip_port\jpeg-8c>NMAKE /f makefile.vc  setup-v10
       This will move jconfig.vc to jconfig.h and makefiles to project files.
       (Note that the renaming is critical!)
  3. Open the solution file C:\iip_port\jpeg-8c\jpeg.sln
  4. Build the Release Version of the library project.
  5. Verify C:\iip_port\jpeg-8c\Release\jpeg.lib exists
  6. Open the solution file C:\iip_port\jpeg-8c\apps.sln
  7. Build the Release Version application projects.
  8. Run C:\iip_port\jpeg-8c>NMAKE /f makefile.vc  test-build
  9. Verify ‘no differences encountered’
  10. Return to the jpeg.sln
  11. Right click on the project, and go to properties
  12. Modify Configuration Type and change to Dynamic Library (.dll), Click OK
  13. Re-Build the Release Version of the library project.
  14. Verify C:\iip_port\jpeg-8c\Release\jpeg.dll exists
  15. Verify C:\iip_port\jpeg-8c\Release\jpeg.lib exists
    1. I had some issues with this, don’t remember precisely what, but had to recompile a couple of different ways to get both the lib and the dll.

LIBTIFF

  1. Acquired from: ftp://ftp.remotesensing.org/pub/libtiff/tiff-3.9.4.zip
  2. C:\iip_port\tiff-3.9.4\libtiff>NMAKE /f makefile.vc
  3. Verify C:\iip_port\tiff-3.9.4\libtiff\libtiff.dll exists
  4. Verify C:\iip_port\tiff-3.9.4\libtiff\libtiff.lib exists
    1. I had some issues with this, don’t remember precisely what, but had to recompile a couple of different ways to get both the lib and the dll.

ZLIB

  1. Acquired from: http://zlib.net/zlib125.zip
  2. Also get http://www.winimage.com/zLibDll/zlib125dll.zip
  3. unzipped both to C:\iip_port\zlib-1.2.5\
  4. Verify C:\iip_port\zlib-1.2.5\dll32\zlibwapi.dll exists
  5. Verify C:\iip_port\zlib-1.2.5\dll32\zlibwapi.lib exists
  6. Verify C:\iip_port\zlib-1.2.5\zlib.h exists

IIPSRV

  1. Open Visual Studio 10
  2. File -> New –> Project
  3. Select Visual C++ -> Win32 Console Application
  4. Name it IIPSRV
  5. Modify Location to: C:\iip_port\iipsrv
  6. OK, then Next
  7. Select Empty Project
  8. Finish
  9. Right click the project, ADD Existing, and select all files in C:\iip_port\iipsrv to add
  10. Right click the project, ADD Existing, and select all files in C:\iip_port\iipsrv\src to add
  11. Right click the project, Open Properties
    1. Under C/C++ -> General We need to add additional Include Directories
      1. C:\iip_port\fcgi-2.4.0\include
      2. C:\iip_port\jpeg-8c
      3. C:\iip_port\tiff-3.9.4\libtiff
      4. C:\iip_port\zlib-1.2.5
      5. After you click apply, wait a second for it to find/recompile the new headers from the path
    2. Under Linker -> General We need to add additional Library Directories
      1. C:\iip_port\fcgi-2.4.0\libfcgi\Release
      2. C:\iip_port\jpeg-8c\Release
      3. C:\iip_port\tiff-3.9.4\libtiff
      4. C:\iip_port\zlib-1.2.5\dll32
      5. After you click apply, wait a second for it to find/recompile the new headers from the path
    3. Under Linker –> Input We need to add additional Dependencies
      1. libfcgi.lib
      2. libtiff.lib
      3. zlibwapi.lib
      4. jpeg.lib
  12. Build Solution (Debug Version)
  13. Should Have 50 Build errors (right click the error list and turn off Show Intellisense Errors)
  14. Right Click KakaduImage.cc and remove from project

The MS Compiler doesn’t support snprintf, we need to alias that to _snprintf so it will work.

We will make the following modifications to source files:

IIPResponse.h 

  1: #if _MSC_VER
  2:  #define snprintf _snprintf
  3: #endif

Cache.h

  1: #if _MSC_VER
  2:  #define snprintf _snprintf
  3: #endif

IIPImage.h

  1:     #if _MSC_VER
  2:         #define snprintf _snprintf
  3:         #include <time.h>
  4:         #define S_ISREG(mode)  (((mode) & S_IFMT) == S_IFREG)
  5:     #endif

fif.cc

  1:   #include <algorithm>
  2:   #include <locale>
  3:     #if _MSC_VER
  4: // Implement strptime under windows
  5: static const char* kWeekFull[] = {
  6:   "Sunday", "Monday", "Tuesday", "Wednesday",
  7:   "Thursday", "Friday", "Saturday"
  8: };
  9: 
 10: static const char* kWeekAbbr[] = {
 11:   "Sun", "Mon", "Tue", "Wed",
 12:   "Thu", "Fri", "Sat"
 13: };
 14: 
 15: static const char* kMonthFull[] = {
 16:   "January", "February", "March", "April", "May", "June",
 17:   "July", "August", "September", "October", "November", "December"
 18: };
 19: 
 20: static const char* kMonthAbbr[] = {
 21:   "Jan", "Feb", "Mar", "Apr", "May", "Jun",
 22:   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
 23: };
 24: 
 25: static const char* _parse_num(const char* s, int low, int high, int* value) {
 26:   const char* p = s;
 27:   for (*value = 0; *p != NULL && isdigit(*p); ++p) {
 28:     *value = (*value) * 10 + static_cast<int>(*p) - static_cast<int>('0');
 29:   }
 30: 
 31:   if (p == s || *value < low || *value > high) return NULL;
 32:   return p;
 33: }
 34: 
 35: static char* _strptime(const char *s, const char *format, struct tm *tm) {
 36:   while (*format != NULL && *s != NULL) {
 37:     if (*format != '%') {
 38:       if (*s != *format) return NULL;
 39: 
 40:       ++format;
 41:       ++s;
 42:       continue;
 43:     }
 44: 
 45:     ++format;
 46:     int len = 0;
 47:     switch (*format) {
 48:       // weekday name.
 49:       case 'a':
 50:       case 'A':
 51:         tm->tm_wday = -1;
 52:         for (int i = 0; i < 7; ++i) {
 53:           len = static_cast<int>(strlen(kWeekAbbr[i]));
 54:           if (strnicmp(kWeekAbbr[i], s, len) == 0) {
 55:             tm->tm_wday = i;
 56:             break;
 57:           }
 58: 
 59:           len = static_cast<int>(strlen(kWeekFull[i]));
 60:           if (strnicmp(kWeekFull[i], s, len) == 0) {
 61:             tm->tm_wday = i;
 62:             break;
 63:           }
 64:         }
 65:         if (tm->tm_wday == -1) return NULL;
 66:         s += len;
 67:         break;
 68: 
 69:       // month name.
 70:       case 'b':
 71:       case 'B':
 72:       case 'h':
 73:         tm->tm_mon = -1;
 74:         for (int i = 0; i < 12; ++i) {
 75:           len = static_cast<int>(strlen(kMonthAbbr[i]));
 76:           if (strnicmp(kMonthAbbr[i], s, len) == 0) {
 77:             tm->tm_mon = i;
 78:             break;
 79:           }
 80: 
 81:           len = static_cast<int>(strlen(kMonthFull[i]));
 82:           if (strnicmp(kMonthFull[i], s, len) == 0) {
 83:             tm->tm_mon = i;
 84:             break;
 85:           }
 86:         }
 87:         if (tm->tm_mon == -1) return NULL;
 88:         s += len;
 89:         break;
 90: 
 91:       // month [1, 12].
 92:       case 'm':
 93:         s = _parse_num(s, 1, 12, &tm->tm_mon);
 94:         if (s == NULL) return NULL;
 95:         --tm->tm_mon;
 96:         break;
 97: 
 98:       // day [1, 31].
 99:       case 'd':
100:       case 'e':
101:         s = _parse_num(s, 1, 31, &tm->tm_mday);
102:         if (s == NULL) return NULL;
103:         break;
104: 
105:       // hour [0, 23].
106:       case 'H':
107:         s = _parse_num(s, 0, 23, &tm->tm_hour);
108:         if (s == NULL) return NULL;
109:         break;
110: 
111:       // minute [0, 59]
112:       case 'M':
113:         s = _parse_num(s, 0, 59, &tm->tm_min);
114:         if (s == NULL) return NULL;
115:         break;
116: 
117:       // seconds [0, 60]. 60 is for leap year.
118:       case 'S':
119:         s = _parse_num(s, 0, 60, &tm->tm_sec);
120:         if (s == NULL) return NULL;
121:         break;
122: 
123:       // year [1900, 9999].
124:       case 'Y':
125:         s = _parse_num(s, 1900, 9999, &tm->tm_year);
126:         if (s == NULL) return NULL;
127:         tm->tm_year -= 1900;
128:         break;
129: 
130:       // year [0, 99].
131:       case 'y':
132:         s = _parse_num(s, 0, 99, &tm->tm_year);
133:         if (s == NULL) return NULL;
134:         if (tm->tm_year <= 68) {
135:           tm->tm_year += 100;
136:         }
137:         break;
138: 
139:       // arbitray whitespace.
140:       case 't':
141:       case 'n':
142:         while (isspace(*s)) ++s;
143:         break;
144: 
145:       // '%'.
146:       case '%':
147:         if (*s != '%') return NULL;
148:         ++s;
149:         break;
150: 
151:       // All the other format are not supported.
152:       default:
153:         return NULL;
154:     }
155:     ++format;
156:   }
157: 
158:   if (*format != NULL) {
159:     return NULL;
160:   } else {
161:     return const_cast<char*>(s);
162:   }
163: }
164: 
165: char* strptime(const char *buf, const char *fmt, struct tm *tm) {
166:   return _strptime(buf, fmt, tm);
167: }
168: 
169: 
170: 
171: static time_t timegm(struct tm *tm){
172:   time_t answer;
173:   char *zone;
174: 
175:   zone=getenv("TZ");
176:   putenv("TZ=UTC");
177:   tzset();
178:   answer=mktime(tm);
179:   if(zone)
180:     {
181:       char *old_zone;
182: 
183:       old_zone=(char *)malloc(3+strlen(zone)+1);
184:       if(old_zone)
185:     {
186:       strcpy(old_zone,"TZ=");
187:       strcat(old_zone,zone);
188:       putenv(old_zone);    
189:     }
190:     }
191:   else
192: #ifdef HAVE_UNSETENV
193:     unsetenv("TZ");
194: #else
195:     putenv("TZ");
196: #endif
197: 
198:   tzset();
199:   return answer;
200: }
201: #endif
202: 
203: 

near line 75 replace
 
  std::isxdigit(*(iter + 1)) && std::isxdigit(*(iter + 2)) ){
 
with

  1:   #if _MSC_VER
  2:     isxdigit(*(iter + 1)) && isxdigit(*(iter + 2)) ){
  3:   #else
  4:     std::isxdigit(*(iter + 1)) && std::isxdigit(*(iter + 2)) ){
  5:   #endif

CVT.cc

  1:   #if _MSC_VER
  2:   #include <algorithm>
  3:   #include <locale>
  4:   #endif

DeepZoom.cc

Near the top add (because microsoft doesn’t provide the log2 function for us)

  1: #if _MSC_VER
  2: double log2(double max){
  3:     return log((double)max)/log((double)2);
  4: }
  5: #endif

IIPImage.cc

  1:     #if _MSC_VER
  2:         #define snprintf _snprintf
  3:         #include <time.h>
  4:         #define S_ISREG(mode)  (((mode) & S_IFMT) == S_IFREG)
  5:     #endif

FIF.cc

  1: #include <time.h>

JPEGCompressor.cc

around line 388 Replace:
  unsigned char t[width*height*channels+1024]; // Add an extra 1k for extra buffering
with

  1:   unsigned char * t;
  2:   t = new unsigned char[width*height*channels+1024]; // Add an extra 1k for extra buffering

Watermark.cc

around line 47 Replace:
  uint32 buffer[_width*_height];
with

  1:   uint32 * buffer;
  2:   buffer = new uint32[_width*_height];

  1. Build the solution.
  2. Stop Apache
  3. Copy
    1. jpeg.dll
    2. libfcgi.dll
    3. libtiff.dll
    4. zlibwapi.dll
    5. IIPSRV.exe
  4. Into your fcgi-bin directory
  5. Restart Apache
  6. Test
share

Recommended Posts

Leave a Reply

Your email address will not be published. Required fields are marked *