struct dirent *readdir(DIR *dp)
{
	if (dp->direntry.d_name) {
		MEM_freeN(dp->direntry.d_name);
		dp->direntry.d_name = NULL;
	}
		
	if (dp->handle == INVALID_HANDLE_VALUE) {
		wchar_t *path_16 = alloc_utf16_from_8(dp->path, 0);
		dp->handle = FindFirstFileW(path_16, &(dp->data));
		free(path_16);
		if (dp->handle == INVALID_HANDLE_VALUE)
			return NULL;
			
		dp->direntry.d_name = BLI_alloc_utf_8_from_16(dp->data.cFileName, 0);
		
		return &dp->direntry;
	}
	else if (FindNextFileW(dp->handle, &(dp->data))) {
		dp->direntry.d_name = BLI_alloc_utf_8_from_16(dp->data.cFileName, 0);

		return &dp->direntry;
	}
	else {
		return NULL;
	}
}
Esempio n. 2
0
int BLI_exists(const char *name)
{
#if defined(WIN32) 
#ifndef __MINGW32__
	struct _stat64i32 st;
#else
	struct _stati64 st;
#endif
	/* in Windows stat doesn't recognize dir ending on a slash
	 * To not break code where the ending slash is expected we
	 * don't mess with the argument name directly here - elubie */
	wchar_t * tmp_16 = alloc_utf16_from_8(name, 0);
	int len, res;
	len = wcslen(tmp_16);
	if (len > 3 && ( tmp_16[len-1]==L'\\' || tmp_16[len-1]==L'/') ) tmp_16[len-1] = '\0';
#ifndef __MINGW32__
	res = _wstat(tmp_16, &st);
#else
	res = _wstati64(tmp_16, &st);
#endif
	free(tmp_16);
	if (res == -1) return(0);
#else
	struct stat st;
	if (stat(name, &st)) return(0);
#endif
	return(st.st_mode);
}
Esempio n. 3
0
/**
 * Returns the st_mode from statting the specified path name, or 0 if it couldn't be statted
 * (most likely doesn't exist or no access).
 */
int BLI_exists(const char *name)
{
#if defined(WIN32) 
	BLI_stat_t st;
	wchar_t *tmp_16 = alloc_utf16_from_8(name, 1);
	int len, res;
	unsigned int old_error_mode;

	len = wcslen(tmp_16);
	/* in Windows #stat doesn't recognize dir ending on a slash
	 * so we remove it here */
	if (len > 3 && (tmp_16[len - 1] == L'\\' || tmp_16[len - 1] == L'/')) {
		tmp_16[len - 1] = '\0';
	}
	/* two special cases where the trailing slash is needed:
	 * 1. after the share part of a UNC path
	 * 2. after the C:\ when the path is the volume only
	 */
	if ((len >= 3) && (tmp_16[0] ==  L'\\') && (tmp_16[1] ==  L'\\')) {
		BLI_cleanup_unc_16(tmp_16);
	}

	if ((tmp_16[1] ==  L':') && (tmp_16[2] ==  L'\0')) {
		tmp_16[2] = L'\\';
		tmp_16[3] = L'\0';
	}


	/* change error mode so user does not get a "no disk in drive" popup
	 * when looking for a file on an empty CD/DVD drive */
	old_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);

	res = BLI_wstat(tmp_16, &st);

	SetErrorMode(old_error_mode);

	free(tmp_16);
	if (res == -1) return(0);
#else
	struct stat st;
	BLI_assert(name);
	BLI_assert(!BLI_path_is_rel(name));
	if (stat(name, &st)) return(0);
#endif
	return(st.st_mode);
}
Esempio n. 4
0
/**
 * Returns the st_mode from statting the specified path name, or 0 if it couldn't be statted
 * (most likely doesn't exist or no access).
 */
int BLI_exists(const char *name)
{
#if defined(WIN32) 
#ifndef __MINGW32__
	struct _stat64i32 st;
#else
	struct _stati64 st;
#endif
	/* in Windows stat doesn't recognize dir ending on a slash
	 * To not break code where the ending slash is expected we
	 * don't mess with the argument name directly here - elubie */
	wchar_t *tmp_16 = alloc_utf16_from_8(name, 0);
	int len, res;
	unsigned int old_error_mode;

	len = wcslen(tmp_16);
	if (len > 3 && (tmp_16[len - 1] == L'\\' || tmp_16[len - 1] == L'/') )
		tmp_16[len - 1] = '\0';

	/* change error mode so user does not get a "no disk in drive" popup
	 * when looking for a file on an empty CD/DVD drive */
	old_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);

#ifndef __MINGW32__
	res = _wstat(tmp_16, &st);
#else
	res = _wstati64(tmp_16, &st);
#endif

	SetErrorMode(old_error_mode);

	free(tmp_16);
	if (res == -1) return(0);
#else
	struct stat st;
	if (stat(name, &st)) return(0);
#endif
	return(st.st_mode);
}
DIR *opendir(const char *path)
{
	wchar_t *path_16 = alloc_utf16_from_8(path, 0);

	if (GetFileAttributesW(path_16) & FILE_ATTRIBUTE_DIRECTORY) {
		DIR *newd = MEM_mallocN(sizeof(DIR), "opendir");

		newd->handle = INVALID_HANDLE_VALUE;
		sprintf(newd->path, "%s\\*", path);
		
		newd->direntry.d_ino = 0;
		newd->direntry.d_off = 0;
		newd->direntry.d_reclen = 0;
		newd->direntry.d_name = NULL;
		
		free(path_16);
		return newd;
	}
	else {
		free(path_16);
		return NULL;
	}
}
Esempio n. 6
0
static void bli_builddir(const char *dirname, const char *relname)
{
	struct dirent *fname;
	struct dirlink *dlink;
	int rellen, newnum = 0;
	char buf[256];
	DIR *dir;

	BLI_strncpy(buf, relname, sizeof(buf));
	rellen=strlen(relname);

	if (rellen) {
		buf[rellen]='/';
		rellen++;
	}
#ifndef WIN32
	if (chdir(dirname) == -1) {
		perror(dirname);
		return;
	}
#else
	UTF16_ENCODE(dirname);
	if (!SetCurrentDirectoryW(dirname_16)) {
		perror(dirname);
		free(dirname_16);
		return;
	}
	UTF16_UN_ENCODE(dirname);

#endif
	if ((dir = (DIR *)opendir("."))) {
		while ((fname = (struct dirent*) readdir(dir)) != NULL) {
			dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
			if (dlink) {
				BLI_strncpy(buf + rellen, fname->d_name, sizeof(buf) - rellen);
				dlink->name = BLI_strdup(buf);
				BLI_addhead(dirbase, dlink);
				newnum++;
			}
		}
		
		if (newnum) {

			if (files) {
				void *tmp = realloc(files, (totnum+newnum) * sizeof(struct direntry));
				if (tmp) {
					files = (struct direntry *)tmp;
				}
				else { /* realloc fail */
					free(files);
					files = NULL;
				}
			}
			
			if (files==NULL)
				files=(struct direntry *)malloc(newnum * sizeof(struct direntry));

			if (files) {
				dlink = (struct dirlink *) dirbase->first;
				while (dlink) {
					memset(&files[actnum], 0, sizeof(struct direntry));
					files[actnum].relname = dlink->name;
					files[actnum].path = BLI_strdupcat(dirname, dlink->name);
// use 64 bit file size, only needed for WIN32 and WIN64. 
// Excluding other than current MSVC compiler until able to test
#ifdef WIN32
					{wchar_t * name_16 = alloc_utf16_from_8(dlink->name, 0);
#if (defined(WIN32) || defined(WIN64)) && (_MSC_VER>=1500)
					_wstat64(name_16, &files[actnum].s);
#elif defined(__MINGW32__)
					_stati64(dlink->name, &files[actnum].s);
#endif
					free(name_16);};

#else
					stat(dlink->name, &files[actnum].s);
#endif
					files[actnum].type=files[actnum].s.st_mode;
					files[actnum].flags = 0;
					totnum++;
					actnum++;
					dlink = dlink->next;
				}
			}
			else {
				printf("Couldn't get memory for dir\n");
				exit(1);
			}

			BLI_freelist(dirbase);
			if (files) qsort(files, actnum, sizeof(struct direntry), (int (*)(const void *, const void*))bli_compare);
		}
		else {
			printf("%s empty directory\n", dirname);
		}

		closedir(dir);
	}
	else {
		printf("%s non-existant directory\n", dirname);
	}
}
Esempio n. 7
0
GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
        const STR_String &title,
        GHOST_TInt32 left,
        GHOST_TInt32 top,
        GHOST_TUns32 width,
        GHOST_TUns32 height,
        GHOST_TWindowState state,
        GHOST_TDrawingContextType type,
        bool wantStereoVisual, bool warnOld,
        GHOST_TUns16 wantNumOfAASamples,
        GHOST_TEmbedderWindowID parentwindowhwnd,
        bool is_debug)
    : GHOST_Window(width, height, state,
                   wantStereoVisual, false, wantNumOfAASamples),
      m_inLiveResize(false),
      m_system(system),
      m_hDC(0),
      m_hasMouseCaptured(false),
      m_hasGrabMouse(false),
      m_nPressedButtons(0),
      m_customCursor(0),
      m_wintab(NULL),
      m_tabletData(NULL),
      m_tablet(0),
      m_maxPressure(0),
      m_normal_state(GHOST_kWindowStateNormal),
      m_parentWindowHwnd(parentwindowhwnd),
      m_debug_context(is_debug)
{
	OSVERSIONINFOEX versionInfo;
	bool hasMinVersionForTaskbar = false;
	
	ZeroMemory(&versionInfo, sizeof(OSVERSIONINFOEX));
	
	versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
	
#if !defined(WITH_GL_EGL)
	if (!warnOld)
		GHOST_ContextWGL::unSetWarningOld();
#else
	(void)(warnOld);
#endif

	if (!GetVersionEx((OSVERSIONINFO *)&versionInfo)) {
		versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
		if (GetVersionEx((OSVERSIONINFO *)&versionInfo)) {
			if ((versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion >= 1) ||
			    (versionInfo.dwMajorVersion >= 7))
			{
				hasMinVersionForTaskbar = true;
			}
		}
	}
	else {
		if ((versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion >= 1) ||
		    (versionInfo.dwMajorVersion >= 7))
		{
			hasMinVersionForTaskbar = true;
		}
	}

	if (state != GHOST_kWindowStateFullScreen) {
		RECT rect;
		MONITORINFO monitor;
		GHOST_TUns32 tw, th; 

#ifndef _MSC_VER
		int cxsizeframe = GetSystemMetrics(SM_CXSIZEFRAME);
		int cysizeframe = GetSystemMetrics(SM_CYSIZEFRAME);
#else
		// MSVC 2012+ returns bogus values from GetSystemMetrics, bug in Windows
		// http://connect.microsoft.com/VisualStudio/feedback/details/753224/regression-getsystemmetrics-delivers-different-values
		RECT cxrect = {0, 0, 0, 0};
		AdjustWindowRectEx(&cxrect, WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_THICKFRAME | WS_DLGFRAME, FALSE, 0);

		int cxsizeframe = abs(cxrect.bottom);
		int cysizeframe = abs(cxrect.left);
#endif

		width += cxsizeframe * 2;
		height += cysizeframe * 2 + GetSystemMetrics(SM_CYCAPTION);

		rect.left = left;
		rect.right = left + width;
		rect.top = top;
		rect.bottom = top + height;

		monitor.cbSize = sizeof(monitor);
		monitor.dwFlags = 0;

		// take taskbar into account
		GetMonitorInfo(MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST), &monitor);

		th = monitor.rcWork.bottom - monitor.rcWork.top;
		tw = monitor.rcWork.right - monitor.rcWork.left;

		if (tw < width) {
			width = tw;
			left = monitor.rcWork.left;
		}
		else if (monitor.rcWork.right < left + (int)width)
			left = monitor.rcWork.right - width;
		else if (left < monitor.rcWork.left)
			left = monitor.rcWork.left;

		if (th < height) {
			height = th;
			top = monitor.rcWork.top;
		}
		else if (monitor.rcWork.bottom < top + (int)height)
			top = monitor.rcWork.bottom - height;
		else if (top < monitor.rcWork.top)
			top = monitor.rcWork.top;

		int wintype = WS_OVERLAPPEDWINDOW;
		if (m_parentWindowHwnd != 0) {
			wintype = WS_CHILD;
			GetWindowRect((HWND)m_parentWindowHwnd, &rect);
			left = 0;
			top = 0;
			width = rect.right - rect.left;
			height = rect.bottom - rect.top;
		}
		
		wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
		m_hWnd = ::CreateWindowW(
		    s_windowClassName,          // pointer to registered class name
		    title_16,                   // pointer to window name
		    wintype,                    // window style
		    left,                       // horizontal position of window
		    top,                        // vertical position of window
		    width,                      // window width
		    height,                     // window height
		    (HWND) m_parentWindowHwnd,  // handle to parent or owner window
		    0,                          // handle to menu or child-window identifier
		    ::GetModuleHandle(0),       // handle to application instance
		    0);                         // pointer to window-creation data
		free(title_16);
	}
	else {
		wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
		m_hWnd = ::CreateWindowW(
		    s_windowClassName,          // pointer to registered class name
		    title_16,                   // pointer to window name
		    WS_POPUP | WS_MAXIMIZE,     // window style
		    left,                       // horizontal position of window
		    top,                        // vertical position of window
		    width,                      // window width
		    height,                     // window height
		    HWND_DESKTOP,               // handle to parent or owner window
		    0,                          // handle to menu or child-window identifier
		    ::GetModuleHandle(0),       // handle to application instance
		    0);                         // pointer to window-creation data
		free(title_16);
	}
	if (m_hWnd) {
		// Register this window as a droptarget. Requires m_hWnd to be valid.
		// Note that OleInitialize(0) has to be called prior to this. Done in GHOST_SystemWin32.
		m_dropTarget = new GHOST_DropTargetWin32(this, m_system);
		if (m_dropTarget) {
			::RegisterDragDrop(m_hWnd, m_dropTarget);
		}

		// Store a pointer to this class in the window structure
		::SetWindowLongPtr(m_hWnd, GWLP_USERDATA, (LONG_PTR) this);

		// Store the device context
		m_hDC = ::GetDC(m_hWnd);

		GHOST_TSuccess success = setDrawingContextType(type);

		if (success) {
			// Show the window
			int nCmdShow;
			switch (state) {
				case GHOST_kWindowStateMaximized:
					nCmdShow = SW_SHOWMAXIMIZED;
					break;
				case GHOST_kWindowStateMinimized:
					nCmdShow = SW_SHOWMINIMIZED;
					break;
				case GHOST_kWindowStateNormal:
				default:
					nCmdShow = SW_SHOWNORMAL;
					break;
			}

			::ShowWindow(m_hWnd, nCmdShow);
			// Force an initial paint of the window
			::UpdateWindow(m_hWnd);
		}
		else {
			//invalidate the window
			::DestroyWindow(m_hWnd);
			m_hWnd = NULL;
		}
	}

	if (parentwindowhwnd != 0) {
		RAWINPUTDEVICE device = {0};
		device.usUsagePage  = 0x01; /* usUsagePage & usUsage for keyboard*/
		device.usUsage      = 0x06; /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */
		device.dwFlags |= RIDEV_INPUTSINK; // makes WM_INPUT is visible for ghost when has parent window
		device.hwndTarget = m_hWnd;
		RegisterRawInputDevices(&device, 1, sizeof(device));
	}

	m_wintab = ::LoadLibrary("Wintab32.dll");
	if (m_wintab) {
		GHOST_WIN32_WTInfo fpWTInfo = (GHOST_WIN32_WTInfo) ::GetProcAddress(m_wintab, "WTInfoA");
		GHOST_WIN32_WTOpen fpWTOpen = (GHOST_WIN32_WTOpen) ::GetProcAddress(m_wintab, "WTOpenA");

		// let's see if we can initialize tablet here
		/* check if WinTab available. */
		if (fpWTInfo && fpWTInfo(0, 0, NULL)) {
			// Now init the tablet
			LOGCONTEXT lc;
			/* The maximum tablet size, pressure and orientation (tilt) */
			AXIS TabletX, TabletY, Pressure, Orientation[3];

			// Open a Wintab context

			// Get default context information
			fpWTInfo(WTI_DEFCONTEXT, 0, &lc);

			// Open the context
			lc.lcPktData = PACKETDATA;
			lc.lcPktMode = PACKETMODE;
			lc.lcOptions |= CXO_MESSAGES | CXO_SYSTEM;

			/* Set the entire tablet as active */
			fpWTInfo(WTI_DEVICES, DVC_X, &TabletX);
			fpWTInfo(WTI_DEVICES, DVC_Y, &TabletY);

			/* get the max pressure, to divide into a float */
			BOOL pressureSupport = fpWTInfo(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
			if (pressureSupport)
				m_maxPressure = Pressure.axMax;
			else
				m_maxPressure = 0;

			/* get the max tilt axes, to divide into floats */
			BOOL tiltSupport = fpWTInfo(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
			if (tiltSupport) {
				/* does the tablet support azimuth ([0]) and altitude ([1]) */
				if (Orientation[0].axResolution && Orientation[1].axResolution) {
					/* all this assumes the minimum is 0 */
					m_maxAzimuth = Orientation[0].axMax;
					m_maxAltitude = Orientation[1].axMax;
				}
				else {  /* no so dont do tilt stuff */
					m_maxAzimuth = m_maxAltitude = 0;
				}
			}

			if (fpWTOpen) {
				m_tablet = fpWTOpen(m_hWnd, &lc, TRUE);
				if (m_tablet) {
					m_tabletData = new GHOST_TabletData();
					m_tabletData->Active = GHOST_kTabletModeNone;
				}
			}
		}
	}

	if (hasMinVersionForTaskbar)
		CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList, (LPVOID *)&m_Bar);
	else
		m_Bar = NULL;
}
Esempio n. 8
0
void GHOST_WindowWin32::setTitle(const STR_String &title)
{
	wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
	::SetWindowTextW(m_hWnd, (wchar_t *)title_16);
	free(title_16);
}
Esempio n. 9
0
/**
 * Scans the directory named *dirname and appends entries for its contents to files.
 */
static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
{
	struct ListBase dirbase = {NULL, NULL};
	int newnum = 0;
	DIR *dir;

	if ((dir = opendir(dirname)) != NULL) {

		const struct dirent *fname;
		while ((fname = readdir(dir)) != NULL) {
			struct dirlink * const dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
			if (dlink != NULL) {
				dlink->name = BLI_strdup(fname->d_name);
				BLI_addhead(&dirbase, dlink);
				newnum++;
			}
		}

		if (newnum) {

			if (dir_ctx->files) {
				void * const tmp = realloc(dir_ctx->files, (dir_ctx->nrfiles + newnum) * sizeof(struct direntry));
				if (tmp) {
					dir_ctx->files = (struct direntry *)tmp;
				}
				else { /* realloc fail */
					free(dir_ctx->files);
					dir_ctx->files = NULL;
				}
			}
			
			if (dir_ctx->files == NULL)
				dir_ctx->files = (struct direntry *)malloc(newnum * sizeof(struct direntry));

			if (dir_ctx->files) {
				struct dirlink * dlink = (struct dirlink *) dirbase.first;
				struct direntry *file = &dir_ctx->files[dir_ctx->nrfiles];
				while (dlink) {
					char fullname[PATH_MAX];
					memset(file, 0, sizeof(struct direntry));
					file->relname = dlink->name;
					file->path = BLI_strdupcat(dirname, dlink->name);
					BLI_join_dirfile(fullname, sizeof(fullname), dirname, dlink->name);
// use 64 bit file size, only needed for WIN32 and WIN64. 
// Excluding other than current MSVC compiler until able to test
#ifdef WIN32
					{
						wchar_t *name_16 = alloc_utf16_from_8(fullname, 0);
#if defined(_MSC_VER) && (_MSC_VER >= 1500)
						_wstat64(name_16, &file->s);
#elif defined(__MINGW32__)
						_stati64(fullname, &file->s);
#endif
						free(name_16);
					}

#else
					stat(fullname, &file->s);
#endif
					file->type = file->s.st_mode;
					file->flags = 0;
					dir_ctx->nrfiles++;
					file++;
					dlink = dlink->next;
				}
			}
			else {
				printf("Couldn't get memory for dir\n");
				exit(1);
			}

			BLI_freelist(&dirbase);
			if (dir_ctx->files) {
				qsort(dir_ctx->files, dir_ctx->nrfiles, sizeof(struct direntry), (int (*)(const void *, const void *))bli_compare);
			}
		}
		else {
			printf("%s empty directory\n", dirname);
		}

		closedir(dir);
	}
	else {
		printf("%s non-existant directory\n", dirname);
	}
}
Esempio n. 10
0
int imb_savetiff(ImBuf *ibuf, const char *name, int flags)
{
	TIFF *image = NULL;
	uint16 samplesperpixel, bitspersample;
	size_t npixels;
	unsigned char *pixels = NULL;
	unsigned char *from = NULL, *to = NULL;
	unsigned short *pixels16 = NULL, *to16 = NULL;
	float *fromf = NULL;
	float xres, yres;
	int x, y, from_i, to_i, i;

	/* check for a valid number of bytes per pixel.  Like the PNG writer,
	 * the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding
	 * to gray, RGB, RGBA respectively. */
	samplesperpixel = (uint16)((ibuf->planes + 7) >> 3);
	if ((samplesperpixel > 4) || (samplesperpixel == 2)) {
		fprintf(stderr,
		        "imb_savetiff: unsupported number of bytes per "
		        "pixel: %d\n", samplesperpixel);
		return (0);
	}

	if ((ibuf->ftype & TIF_16BIT) && ibuf->rect_float)
		bitspersample = 16;
	else
		bitspersample = 8;

	/* open TIFF file for writing */
	if (flags & IB_mem) {
		/* bork at the creation of a TIFF in memory */
		fprintf(stderr,
		        "imb_savetiff: creation of in-memory TIFF files is "
		        "not yet supported.\n");
		return (0);
	}
	else {
		/* create image as a file */
#ifdef WIN32
		wchar_t *wname = alloc_utf16_from_8(name, 0);
		image = TIFFOpenW(wname, "w");
		free(wname);
#else
		image = TIFFOpen(name, "w");
#endif
	}
	if (image == NULL) {
		fprintf(stderr,
		        "imb_savetiff: could not open TIFF for writing.\n");
		return (0);
	}

	/* allocate array for pixel data */
	npixels = ibuf->x * ibuf->y;
	if (bitspersample == 16)
		pixels16 = (unsigned short *)_TIFFmalloc(npixels *
		                                         samplesperpixel * sizeof(unsigned short));
	else
		pixels = (unsigned char *)_TIFFmalloc(npixels *
		                                      samplesperpixel * sizeof(unsigned char));

	if (pixels == NULL && pixels16 == NULL) {
		fprintf(stderr,
		        "imb_savetiff: could not allocate pixels array.\n");
		TIFFClose(image);
		return (0);
	}

	/* setup pointers */
	if (bitspersample == 16) {
		fromf = ibuf->rect_float;
		to16   = pixels16;
	}
	else {
		from = (unsigned char *)ibuf->rect;
		to   = pixels;
	}

	/* setup samples per pixel */
	TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, bitspersample);
	TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);

	if (samplesperpixel == 4) {
		unsigned short extraSampleTypes[1];

		if (bitspersample == 16)
			extraSampleTypes[0] = EXTRASAMPLE_ASSOCALPHA;
		else
			extraSampleTypes[0] = EXTRASAMPLE_UNASSALPHA;

		/* RGBA images */
		TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1,
		             extraSampleTypes);
		TIFFSetField(image, TIFFTAG_PHOTOMETRIC, 
		             PHOTOMETRIC_RGB);
	}
	else if (samplesperpixel == 3) {
		/* RGB images */
		TIFFSetField(image, TIFFTAG_PHOTOMETRIC,
		             PHOTOMETRIC_RGB);
	}
	else if (samplesperpixel == 1) {
		/* grayscale images, 1 channel */
		TIFFSetField(image, TIFFTAG_PHOTOMETRIC,
		             PHOTOMETRIC_MINISBLACK);
	}

	/* copy pixel data.  While copying, we flip the image vertically. */
	for (x = 0; x < ibuf->x; x++) {
		for (y = 0; y < ibuf->y; y++) {
			from_i = 4 * (y * ibuf->x + x);
			to_i   = samplesperpixel * ((ibuf->y - y - 1) * ibuf->x + x);

			if (pixels16) {
				/* convert from float source */
				float rgb[4];
				
				if (ibuf->float_colorspace) {
					/* float buffer was managed already, no need in color space conversion */
					copy_v3_v3(rgb, &fromf[from_i]);
				}
				else {
					/* standard linear-to-srgb conversion if float buffer wasn't managed */
					linearrgb_to_srgb_v3_v3(rgb, &fromf[from_i]);
				}

				rgb[3] = fromf[from_i + 3];

				for (i = 0; i < samplesperpixel; i++, to_i++)
					to16[to_i] = FTOUSHORT(rgb[i]);
			}
			else {
				for (i = 0; i < samplesperpixel; i++, to_i++, from_i++)
					to[to_i] = from[from_i];
			}
		}
	}

	/* write the actual TIFF file */
	TIFFSetField(image, TIFFTAG_IMAGEWIDTH,      ibuf->x);
	TIFFSetField(image, TIFFTAG_IMAGELENGTH,     ibuf->y);
	TIFFSetField(image, TIFFTAG_ROWSPERSTRIP,    ibuf->y);
	TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
	TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
	TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);


	if (ibuf->ppm[0] > 0.0 && ibuf->ppm[1] > 0.0) {
		xres = (float)(ibuf->ppm[0] * 0.0254);
		yres = (float)(ibuf->ppm[1] * 0.0254);
	}
	else {
		xres = yres = IMB_DPI_DEFAULT;
	}

	TIFFSetField(image, TIFFTAG_XRESOLUTION,     xres);
	TIFFSetField(image, TIFFTAG_YRESOLUTION,     yres);
	TIFFSetField(image, TIFFTAG_RESOLUTIONUNIT,  RESUNIT_INCH);
	if (TIFFWriteEncodedStrip(image, 0,
	                          (bitspersample == 16) ? (unsigned char *)pixels16 : pixels,
	                          ibuf->x * ibuf->y * samplesperpixel * bitspersample / 8) == -1)
	{
		fprintf(stderr,
		        "imb_savetiff: Could not write encoded TIFF.\n");
		TIFFClose(image);
		if (pixels) _TIFFfree(pixels);
		if (pixels16) _TIFFfree(pixels16);
		return (1);
	}

	/* close the TIFF file */
	TIFFClose(image);
	if (pixels) _TIFFfree(pixels);
	if (pixels16) _TIFFfree(pixels16);
	return (1);
}