Example #1
0
File: loader.c Project: eXeC64/imv
static void *bg_new_img(void *data)
{
  /* so we can poll for it */
  block_usr1_signal();

  struct imv_loader *ldr = data;
  char path[PATH_MAX] = "-";

  pthread_mutex_lock(&ldr->lock);
  int from_stdin = !strncmp(path, ldr->path, 2);
  if(!from_stdin) {
    (void)snprintf(path, PATH_MAX, "%s", ldr->path);
  }
  pthread_mutex_unlock(&ldr->lock);

  FREE_IMAGE_FORMAT fmt;
  if (from_stdin) {
    pthread_mutex_lock(&ldr->lock);
    ldr->fi_buffer = FreeImage_OpenMemory(ldr->buffer, ldr->buffer_size);
    fmt = FreeImage_GetFileTypeFromMemory(ldr->fi_buffer, 0);
    pthread_mutex_unlock(&ldr->lock);
  } else {
    fmt = FreeImage_GetFileType(path, 0);
  }
  if(fmt == FIF_UNKNOWN) {
    if (from_stdin) {
      pthread_mutex_lock(&ldr->lock);
      FreeImage_CloseMemory(ldr->fi_buffer);
      pthread_mutex_unlock(&ldr->lock);
    }
    error_occurred(ldr);
    return NULL;
  }

  int num_frames = 1;
  FIMULTIBITMAP *mbmp = NULL;
  FIBITMAP *bmp = NULL;
  int width, height;
  int raw_frame_time = 100; /* default to 100 */

  if(fmt == FIF_GIF) {
    if(from_stdin) {
      pthread_mutex_lock(&ldr->lock);
      mbmp = FreeImage_LoadMultiBitmapFromMemory(FIF_GIF, ldr->fi_buffer,
          GIF_LOAD256);
      pthread_mutex_unlock(&ldr->lock);
    } else {
      mbmp = FreeImage_OpenMultiBitmap(FIF_GIF, path,
      /* don't create file */ 0,
      /* read only */ 1,
      /* keep in memory */ 1,
      /* flags */ GIF_LOAD256);
    }
    if(!mbmp) {
      error_occurred(ldr);
      return NULL;
    }

    num_frames = FreeImage_GetPageCount(mbmp);

    FIBITMAP *frame = FreeImage_LockPage(mbmp, 0);
    width = FreeImage_GetWidth(frame);
    height = FreeImage_GetHeight(frame);
    bmp = FreeImage_ConvertTo32Bits(frame);

    /* get duration of first frame */
    FITAG *tag = NULL;
    FreeImage_GetMetadata(FIMD_ANIMATION, frame, "FrameTime", &tag);
    if(FreeImage_GetTagValue(tag)) {
      raw_frame_time = *(int*)FreeImage_GetTagValue(tag);
    }
    FreeImage_UnlockPage(mbmp, frame, 0);

  } else {
    /* Future TODO: If we load image line-by-line we could stop loading large
     * ones before wasting much more time/memory on them. */

    int flags = (fmt == FIF_JPEG) ? JPEG_EXIFROTATE : 0;
    FIBITMAP *image;
    if(from_stdin) {
      pthread_mutex_lock(&ldr->lock);
      image = FreeImage_LoadFromMemory(fmt, ldr->fi_buffer, flags);
      pthread_mutex_unlock(&ldr->lock);
    } else {
      image = FreeImage_Load(fmt, path, flags);
    }
    if(!image) {
      error_occurred(ldr);
      pthread_mutex_lock(&ldr->lock);
      FreeImage_CloseMemory(ldr->fi_buffer);
      ldr->fi_buffer = NULL;
      pthread_mutex_unlock(&ldr->lock);
      return NULL;
    }

    /* Check for cancellation before we convert pixel format */
    if(is_thread_cancelled()) {
      FreeImage_Unload(image);
      return NULL;
    }

    width = FreeImage_GetWidth(bmp);
    height = FreeImage_GetHeight(bmp);
    bmp = FreeImage_ConvertTo32Bits(image);
    FreeImage_Unload(image);
  }

  /* now update the loader */
  pthread_mutex_lock(&ldr->lock);

  /* check for cancellation before finishing */
  if(is_thread_cancelled()) {
    if(mbmp) {
      FreeImage_CloseMultiBitmap(mbmp, 0);
    }
    if(bmp) {
      FreeImage_Unload(bmp);
    }
    pthread_mutex_unlock(&ldr->lock);
    return NULL;
  }

  if(ldr->mbmp) {
    FreeImage_CloseMultiBitmap(ldr->mbmp, 0);
  }

  if(ldr->bmp) {
    FreeImage_Unload(ldr->bmp);
  }

  ldr->mbmp = mbmp;
  ldr->bmp = bmp;
  if(ldr->out_bmp) {
    FreeImage_Unload(ldr->out_bmp);
  }
  ldr->out_bmp = FreeImage_Clone(bmp);
  ldr->out_is_new_image = 1;
  ldr->width = width;
  ldr->height = height;
  ldr->cur_frame = 0;
  ldr->next_frame = 1;
  ldr->num_frames = num_frames;
  ldr->frame_time = (double)raw_frame_time * 0.0001;

  pthread_mutex_unlock(&ldr->lock);
  return NULL;
}
Example #2
0
File: loader.c Project: eXeC64/imv
static void *bg_next_frame(void *data)
{
  struct imv_loader *ldr = data;

  pthread_mutex_lock(&ldr->lock);
  int num_frames = ldr->num_frames;
  if(num_frames < 2) {
    pthread_mutex_unlock(&ldr->lock);
    return NULL;
  }

  FITAG *tag = NULL;
  char disposal_method = 0;
  int frame_time = 0;
  short top = 0;
  short left = 0;

  ldr->cur_frame = ldr->next_frame;
  ldr->next_frame = (ldr->cur_frame + 1) % ldr->num_frames;
  FIBITMAP *frame = FreeImage_LockPage(ldr->mbmp, ldr->cur_frame);
  FIBITMAP *frame32 = FreeImage_ConvertTo32Bits(frame);

  /* First frame is always going to use the raw frame */
  if(ldr->cur_frame > 0) {
    FreeImage_GetMetadata(FIMD_ANIMATION, frame, "DisposalMethod", &tag);
    if(FreeImage_GetTagValue(tag)) {
      disposal_method = *(char*)FreeImage_GetTagValue(tag);
    }
  }

  FreeImage_GetMetadata(FIMD_ANIMATION, frame, "FrameLeft", &tag);
  if(FreeImage_GetTagValue(tag)) {
    left = *(short*)FreeImage_GetTagValue(tag);
  }

  FreeImage_GetMetadata(FIMD_ANIMATION, frame, "FrameTop", &tag);
  if(FreeImage_GetTagValue(tag)) {
    top = *(short*)FreeImage_GetTagValue(tag);
  }

  FreeImage_GetMetadata(FIMD_ANIMATION, frame, "FrameTime", &tag);
  if(FreeImage_GetTagValue(tag)) {
    frame_time = *(int*)FreeImage_GetTagValue(tag);
  }

  /* some gifs don't provide a frame time at all */
  if(frame_time == 0) {
    frame_time = 100;
  }
  ldr->frame_time += frame_time * 0.001;

  FreeImage_UnlockPage(ldr->mbmp, frame, 0);

  /* If this frame is inset, we need to expand it for compositing */
  if(ldr->width != (int)FreeImage_GetWidth(frame32) ||
     ldr->height != (int)FreeImage_GetHeight(frame32)) {
    FIBITMAP *expanded = FreeImage_Allocate(ldr->width, ldr->height, 32, 0,0,0);
    FreeImage_Paste(expanded, frame32, left, top, 255);
    FreeImage_Unload(frame32);
    frame32 = expanded;
  }

  switch(disposal_method) {
    case 0: /* nothing specified, fall through to compositing */
    case 1: /* composite over previous frame */
      if(ldr->bmp && ldr->cur_frame > 0) {
        FIBITMAP *bg_frame = FreeImage_ConvertTo24Bits(ldr->bmp);
        FreeImage_Unload(ldr->bmp);
        FIBITMAP *comp = FreeImage_Composite(frame32, 1, NULL, bg_frame);
        FreeImage_Unload(bg_frame);
        FreeImage_Unload(frame32);
        ldr->bmp = comp;
      } else {
        /* No previous frame, just render directly */
        if(ldr->bmp) {
          FreeImage_Unload(ldr->bmp);
        }
        ldr->bmp = frame32;
      }
      break;
    case 2: /* TODO - set to background, composite over that */
      if(ldr->bmp) {
        FreeImage_Unload(ldr->bmp);
      }
      ldr->bmp = frame32;
      break;
    case 3: /* TODO - restore to previous content */
      if(ldr->bmp) {
        FreeImage_Unload(ldr->bmp);
      }
      ldr->bmp = frame32;
      break;
  }

  if(ldr->out_bmp) {
    FreeImage_Unload(ldr->out_bmp);
  }
  ldr->out_bmp = FreeImage_Clone(ldr->bmp);

  pthread_mutex_unlock(&ldr->lock);
  return NULL;
}
Example #3
0
/**
Convert a tag to a C string
*/
static const char* 
ConvertAnyTag(FITAG *tag) {
	char format[MAX_TEXT_EXTENT];
	static std::string buffer;
	DWORD i;

	if(!tag)
		return NULL;

	buffer.erase();
	
	// convert the tag value to a string buffer

	FREE_IMAGE_MDTYPE tag_type = FreeImage_GetTagType(tag);
	DWORD tag_count = FreeImage_GetTagCount(tag);

	switch(tag_type) {
		case FIDT_BYTE:		// N x 8-bit unsigned integer 
		{
			BYTE *pvalue = (BYTE*)FreeImage_GetTagValue(tag);

			sprintf(format, "%ld",	(LONG) pvalue[0]);
			buffer += format;
			for(i = 1; i < tag_count; i++) {
				sprintf(format, " %ld",	(LONG) pvalue[i]);
				buffer += format;
			}
			break;
		}
		case FIDT_SHORT:	// N x 16-bit unsigned integer 
		{
			unsigned short *pvalue = (unsigned short *)FreeImage_GetTagValue(tag);

			sprintf(format, "%hu", pvalue[0]);
			buffer += format;
			for(i = 1; i < tag_count; i++) {
				sprintf(format, " %hu",	pvalue[i]);
				buffer += format;
			}
			break;
		}
		case FIDT_LONG:		// N x 32-bit unsigned integer 
		{
			DWORD *pvalue = (DWORD *)FreeImage_GetTagValue(tag);

			sprintf(format, "%lu", pvalue[0]);
			buffer += format;
			for(i = 1; i < tag_count; i++) {
				sprintf(format, " %lu",	pvalue[i]);
				buffer += format;
			}
			break;
		}
		case FIDT_RATIONAL: // N x 64-bit unsigned fraction 
		{
			DWORD *pvalue = (DWORD*)FreeImage_GetTagValue(tag);

			sprintf(format, "%ld/%ld", pvalue[0], pvalue[1]);
			buffer += format;
			for(i = 1; i < tag_count; i++) {
				sprintf(format, " %ld/%ld", pvalue[2*i], pvalue[2*i+1]);
				buffer += format;
			}
			break;
		}
		case FIDT_SBYTE:	// N x 8-bit signed integer 
		{
			char *pvalue = (char*)FreeImage_GetTagValue(tag);

			sprintf(format, "%ld",	(LONG) pvalue[0]);
			buffer += format;
			for(i = 1; i < tag_count; i++) {
				sprintf(format, " %ld",	(LONG) pvalue[i]);
				buffer += format;
			}
			break;
		}
		case FIDT_SSHORT:	// N x 16-bit signed integer 
		{
			short *pvalue = (short *)FreeImage_GetTagValue(tag);

			sprintf(format, "%hd", pvalue[0]);
			buffer += format;
			for(i = 1; i < tag_count; i++) {
				sprintf(format, " %hd",	pvalue[i]);
				buffer += format;
			}
			break;
		}
		case FIDT_SLONG:	// N x 32-bit signed integer 
		{
			LONG *pvalue = (LONG *)FreeImage_GetTagValue(tag);

			sprintf(format, "%ld", pvalue[0]);
			buffer += format;
			for(i = 1; i < tag_count; i++) {
				sprintf(format, " %ld",	pvalue[i]);
				buffer += format;
			}
			break;
		}
		case FIDT_SRATIONAL:// N x 64-bit signed fraction 
		{
			LONG *pvalue = (LONG*)FreeImage_GetTagValue(tag);

			sprintf(format, "%ld/%ld", pvalue[0], pvalue[1]);
			buffer += format;
			for(i = 1; i < tag_count; i++) {
				sprintf(format, " %ld/%ld", pvalue[2*i], pvalue[2*i+1]);
				buffer += format;
			}
			break;
		}
		case FIDT_FLOAT:	// N x 32-bit IEEE floating point 
		{
			float *pvalue = (float *)FreeImage_GetTagValue(tag);

			sprintf(format, "%f", (double) pvalue[0]);
			buffer += format;
			for(i = 1; i < tag_count; i++) {
				sprintf(format, "%f", (double) pvalue[i]);
				buffer += format;
			}
			break;
		}
		case FIDT_DOUBLE:	// N x 64-bit IEEE floating point 
		{
			double *pvalue = (double *)FreeImage_GetTagValue(tag);

			sprintf(format, "%f", pvalue[0]);
			buffer += format;
			for(i = 1; i < tag_count; i++) {
				sprintf(format, "%f", pvalue[i]);
				buffer += format;
			}
			break;
		}
		case FIDT_IFD:		// N x 32-bit unsigned integer (offset) 
		{
			DWORD *pvalue = (DWORD *)FreeImage_GetTagValue(tag);

			sprintf(format, "%X", pvalue[0]);
			buffer += format;
			for(i = 1; i < tag_count; i++) {
				sprintf(format, " %X",	pvalue[i]);
				buffer += format;
			}
			break;
		}
		case FIDT_PALETTE:	// N x 32-bit RGBQUAD 
		{
			RGBQUAD *pvalue = (RGBQUAD *)FreeImage_GetTagValue(tag);

			sprintf(format, "(%d,%d,%d,%d)", pvalue[0].rgbRed, pvalue[0].rgbGreen, pvalue[0].rgbBlue, pvalue[0].rgbReserved);
			buffer += format;
			for(i = 1; i < tag_count; i++) {
				sprintf(format, " (%d,%d,%d,%d)", pvalue[i].rgbRed, pvalue[i].rgbGreen, pvalue[i].rgbBlue, pvalue[i].rgbReserved);
				buffer += format;
			}
			break;
		}
		
		case FIDT_LONG8:	// N x 64-bit unsigned integer 
		{
			FIUINT64 *pvalue = (FIUINT64 *)FreeImage_GetTagValue(tag);

			sprintf(format, "%ld", pvalue[0]);
			buffer += format;
			for(i = 1; i < tag_count; i++) {
				sprintf(format, "%ld", pvalue[i]);
				buffer += format;
			}
			break;
		}

		case FIDT_IFD8:		// N x 64-bit unsigned integer (offset)
		{
			FIUINT64 *pvalue = (FIUINT64 *)FreeImage_GetTagValue(tag);

			sprintf(format, "%X", pvalue[0]);
			buffer += format;
			for(i = 1; i < tag_count; i++) {
				sprintf(format, "%X", pvalue[i]);
				buffer += format;
			}
			break;
		}

		case FIDT_SLONG8:	// N x 64-bit signed integer
		{
			FIINT64 *pvalue = (FIINT64 *)FreeImage_GetTagValue(tag);

			sprintf(format, "%ld", pvalue[0]);
			buffer += format;
			for(i = 1; i < tag_count; i++) {
				sprintf(format, "%ld", pvalue[i]);
				buffer += format;
			}
			break;
		}

		case FIDT_ASCII:	// 8-bit bytes w/ last byte null 
		case FIDT_UNDEFINED:// 8-bit untyped data 
		default:
		{
			int max_size = MIN((int)FreeImage_GetTagLength(tag), (int)MAX_TEXT_EXTENT);
			if(max_size == MAX_TEXT_EXTENT)
				max_size--;
			memcpy(format, (char*)FreeImage_GetTagValue(tag), max_size);
			format[max_size] = '\0';
			buffer += format;
			break;
		}
	}

	return buffer.c_str();
}
Example #4
0
/**
Convert a Exif GPS tag to a C string
*/
static const char* 
ConvertExifGPSTag(FITAG *tag) {
	char format[MAX_TEXT_EXTENT];
	static std::string buffer;

	if(!tag)
		return NULL;

	buffer.erase();

	// convert the tag value to a string buffer

	switch(FreeImage_GetTagID(tag)) {
		case TAG_GPS_LATITUDE:
		case TAG_GPS_LONGITUDE:
		case TAG_GPS_TIME_STAMP:
		{
			DWORD *pvalue = (DWORD*)FreeImage_GetTagValue(tag);
			if(FreeImage_GetTagLength(tag) == 24) {
				// dd:mm:ss or hh:mm:ss
				int dd = 0, mm = 0;
				double ss = 0;

				// convert to seconds
				if(pvalue[1])
					ss += ((double)pvalue[0] / (double)pvalue[1]) * 3600;
				if(pvalue[3])
					ss += ((double)pvalue[2] / (double)pvalue[3]) * 60;
				if(pvalue[5])
					ss += ((double)pvalue[4] / (double)pvalue[5]);
				
				// convert to dd:mm:ss.ss
				dd = (int)(ss / 3600);
				mm = (int)(ss / 60) - dd * 60;
				ss = ss - dd * 3600 - mm * 60;

				sprintf(format, "%d:%d:%.2f", dd, mm, ss);
				buffer += format;
				return buffer.c_str();
			}
		}
		break;

		case TAG_GPS_VERSION_ID:
		case TAG_GPS_LATITUDE_REF:
		case TAG_GPS_LONGITUDE_REF:
		case TAG_GPS_ALTITUDE_REF:
		case TAG_GPS_ALTITUDE:
		case TAG_GPS_SATELLITES:
		case TAG_GPS_STATUS:
		case TAG_GPS_MEASURE_MODE:
		case TAG_GPS_DOP:
		case TAG_GPS_SPEED_REF:
		case TAG_GPS_SPEED:
		case TAG_GPS_TRACK_REF:
		case TAG_GPS_TRACK:
		case TAG_GPS_IMG_DIRECTION_REF:
		case TAG_GPS_IMG_DIRECTION:
		case TAG_GPS_MAP_DATUM:
		case TAG_GPS_DEST_LATITUDE_REF:
		case TAG_GPS_DEST_LATITUDE:
		case TAG_GPS_DEST_LONGITUDE_REF:
		case TAG_GPS_DEST_LONGITUDE:
		case TAG_GPS_DEST_BEARING_REF:
		case TAG_GPS_DEST_BEARING:
		case TAG_GPS_DEST_DISTANCE_REF:
		case TAG_GPS_DEST_DISTANCE:
		case TAG_GPS_PROCESSING_METHOD:
		case TAG_GPS_AREA_INFORMATION:
		case TAG_GPS_DATE_STAMP:
		case TAG_GPS_DIFFERENTIAL:
			break;
	}

	return ConvertAnyTag(tag);
}
Example #5
0
FREE_IMAGE_COLOR_TYPE DLL_CALLCONV
FreeImage_GetColorType(FIBITMAP *dib) {
	RGBQUAD *rgb;

	const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);

	// special bitmap type
	if(image_type != FIT_BITMAP) {
		switch(image_type) {
			case FIT_UINT16:
			{
				// 16-bit greyscale TIF can be either FIC_MINISBLACK (the most common case) or FIC_MINISWHITE
				// you can check this using EXIF_MAIN metadata
				FITAG *photometricTag = NULL;
				if(FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "PhotometricInterpretation", &photometricTag)) {
					const short *value = (short*)FreeImage_GetTagValue(photometricTag);
					// PHOTOMETRIC_MINISWHITE = 0 => min value is white
					// PHOTOMETRIC_MINISBLACK = 1 => min value is black
					return (*value == 0) ? FIC_MINISWHITE : FIC_MINISBLACK;
				}
				return FIC_MINISBLACK;
			}
			break;
			case FIT_RGB16:
			case FIT_RGBF:
				return FIC_RGB;
			case FIT_RGBA16:
			case FIT_RGBAF:
				return FIC_RGBALPHA;
		}

		return FIC_MINISBLACK;
	}

	// standard image type
	switch (FreeImage_GetBPP(dib)) {
		case 1:
		{
			rgb = FreeImage_GetPalette(dib);

			if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) {
				rgb++;

				if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) {
					return FIC_MINISBLACK;
				}
			}

			if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) {
				rgb++;

				if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) {
					return FIC_MINISWHITE;
				}
			}

			return FIC_PALETTE;
		}

		case 4:
		case 8:	// Check if the DIB has a color or a greyscale palette
		{
			int ncolors = FreeImage_GetColorsUsed(dib);
		    int minisblack = 1;
			rgb = FreeImage_GetPalette(dib);

			for (int i = 0; i < ncolors; i++) {
				if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue)) {
					return FIC_PALETTE;
				}

				// The DIB has a color palette if the greyscale isn't a linear ramp
				// Take care of reversed grey images
				if (rgb->rgbRed != i) {
					if ((ncolors-i-1) != rgb->rgbRed) {
						return FIC_PALETTE;
					} else {
						minisblack = 0;
					}
				}

				rgb++;
			}

			return minisblack ? FIC_MINISBLACK : FIC_MINISWHITE;
		}

		case 16:
		case 24:
			return FIC_RGB;

		case 32:
		{
			if (FreeImage_GetICCProfile(dib)->flags & FIICC_COLOR_IS_CMYK) {
				return FIC_CMYK;
			}

			if( FreeImage_HasPixels(dib) ) {
				// check for fully opaque alpha layer
				for (unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
					rgb = (RGBQUAD *)FreeImage_GetScanLine(dib, y);

					for (unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
						if (rgb[x].rgbReserved != 0xFF) {
							return FIC_RGBALPHA;
						}
					}
				}
				return FIC_RGB;
			}

			return FIC_RGBALPHA;
		}
				
		default :
			return FIC_MINISBLACK;
	}
}
Example #6
0
/**
Convert a Exif tag to a C string
*/
static const char* 
ConvertExifTag(FITAG *tag) {
	char format[MAX_TEXT_EXTENT];
	static std::string buffer;

	if(!tag)
		return NULL;

	buffer.erase();

	// convert the tag value to a string buffer

	switch(FreeImage_GetTagID(tag)) {
		case TAG_ORIENTATION:
		{
			unsigned short orientation = *((unsigned short *)FreeImage_GetTagValue(tag));
			switch (orientation) {
				case 1:
					return "top, left side";
				case 2:
					return "top, right side";
				case 3:
					return "bottom, right side";
				case 4:
					return "bottom, left side";
				case 5:
					return "left side, top";
				case 6:
					return "right side, top";
				case 7:
					return "right side, bottom";
				case 8:
					return "left side, bottom";
				default:
					break;
			}
		}
		break;

		case TAG_REFERENCE_BLACK_WHITE:
		{
			DWORD *pvalue = (DWORD*)FreeImage_GetTagValue(tag);
			if(FreeImage_GetTagLength(tag) == 48) {
				// reference black point value and reference white point value (ReferenceBlackWhite)
				int blackR = 0, whiteR = 0, blackG = 0, whiteG = 0, blackB = 0, whiteB = 0;
				if(pvalue[1])
					blackR = (int)(pvalue[0] / pvalue[1]);
				if(pvalue[3])
					whiteR = (int)(pvalue[2] / pvalue[3]);
				if(pvalue[5])
					blackG = (int)(pvalue[4] / pvalue[5]);
				if(pvalue[7])
					whiteG = (int)(pvalue[6] / pvalue[7]);
				if(pvalue[9])
					blackB = (int)(pvalue[8] / pvalue[9]);
				if(pvalue[11])
					whiteB = (int)(pvalue[10] / pvalue[11]);

				sprintf(format, "[%d,%d,%d] [%d,%d,%d]", blackR, blackG, blackB, whiteR, whiteG, whiteB);
				buffer += format;
				return buffer.c_str();
			}

		}
		break;

		case TAG_COLOR_SPACE:
		{
			unsigned short colorSpace = *((unsigned short *)FreeImage_GetTagValue(tag));
			if (colorSpace == 1) {
				return "sRGB";
			} else if (colorSpace == 65535) {
				return "Undefined";
			} else {
				return "Unknown";
			}
		}
		break;

		case TAG_COMPONENTS_CONFIGURATION:
		{
			const char *componentStrings[7] = {"", "Y", "Cb", "Cr", "R", "G", "B"};
			BYTE *pvalue = (BYTE*)FreeImage_GetTagValue(tag);
			for(DWORD i = 0; i < MIN((DWORD)4, FreeImage_GetTagCount(tag)); i++) {
				int j = pvalue[i];
				if(j > 0 && j < 7)
					buffer += componentStrings[j];
			}
			return buffer.c_str();
		}
		break;

		case TAG_COMPRESSED_BITS_PER_PIXEL:
		{
			FIRational r(tag);
			buffer = r.toString();
			if(buffer == "1")
				buffer += " bit/pixel";
			else 
				buffer += " bits/pixel";
			return buffer.c_str();
		}
		break;

		case TAG_X_RESOLUTION:
		case TAG_Y_RESOLUTION:
		case TAG_FOCAL_PLANE_X_RES:
		case TAG_FOCAL_PLANE_Y_RES:
		case TAG_BRIGHTNESS_VALUE:
		case TAG_EXPOSURE_BIAS_VALUE:
		{
			FIRational r(tag);
			buffer = r.toString();
			return buffer.c_str();
		}
		break;

		case TAG_RESOLUTION_UNIT:
		case TAG_FOCAL_PLANE_UNIT:
		{
			unsigned short resolutionUnit = *((unsigned short *)FreeImage_GetTagValue(tag));
			switch (resolutionUnit) {
				case 1:
					return "(No unit)";
				case 2:
					return "inches";
				case 3:
					return "cm";
				default:
					break;
			}
		}
		break;

		case TAG_YCBCR_POSITIONING:
		{
			unsigned short yCbCrPosition = *((unsigned short *)FreeImage_GetTagValue(tag));
			switch (yCbCrPosition) {
				case 1:
					return "Center of pixel array";
				case 2:
					return "Datum point";
				default:
					break;
			}
		} 
		break;

		case TAG_EXPOSURE_TIME:
		{
			FIRational r(tag);
			buffer = r.toString();
			buffer += " sec";
			return buffer.c_str();
		}
		break;

		case TAG_SHUTTER_SPEED_VALUE:
		{
			FIRational r(tag);
			LONG apexValue = r.longValue();
			LONG apexPower = 1 << apexValue;
			sprintf(format, "1/%d sec", (int)apexPower);
			buffer += format;
			return buffer.c_str();
		}
		break;

		case TAG_APERTURE_VALUE:
		case TAG_MAX_APERTURE_VALUE:
		{
			FIRational r(tag);
			double apertureApex = r.doubleValue();
	        double rootTwo = sqrt((double)2);
			double fStop = pow(rootTwo, apertureApex);
			sprintf(format, "F%.1f", fStop);
			buffer += format;
			return buffer.c_str();
		}
		break;

		case TAG_FNUMBER:
		{
			FIRational r(tag);
			double fnumber = r.doubleValue();
			sprintf(format, "F%.1f", fnumber);
			buffer += format;
			return buffer.c_str();
		}
		break;

		case TAG_FOCAL_LENGTH:
		{
			FIRational r(tag);
			double focalLength = r.doubleValue();
			sprintf(format, "%.1f mm", focalLength);
			buffer += format;
			return buffer.c_str();
		}
		break;

		case TAG_FOCAL_LENGTH_IN_35MM_FILM:
		{
			unsigned short focalLength = *((unsigned short *)FreeImage_GetTagValue(tag));
			sprintf(format, "%hu mm", focalLength);
			buffer += format;
			return buffer.c_str();
		}
		break;

		case TAG_FLASH:
		{
			unsigned short flash = *((unsigned short *)FreeImage_GetTagValue(tag));
			switch(flash) {
				case 0x0000:
					return "Flash did not fire";
				case 0x0001:
					return "Flash fired";
				case 0x0005:
					return "Strobe return light not detected";
				case 0x0007:
					return "Strobe return light detected";
				case 0x0009:
					return "Flash fired, compulsory flash mode";
				case 0x000D:
					return "Flash fired, compulsory flash mode, return light not detected";
				case 0x000F:
					return "Flash fired, compulsory flash mode, return light detected";
				case 0x0010:
					return "Flash did not fire, compulsory flash mode";
				case 0x0018:
					return "Flash did not fire, auto mode";
				case 0x0019:
					return "Flash fired, auto mode";
				case 0x001D:
					return "Flash fired, auto mode, return light not detected";
				case 0x001F:
					return "Flash fired, auto mode, return light detected";
				case 0x0020:
					return "No flash function";
				case 0x0041:
					return "Flash fired, red-eye reduction mode";
				case 0x0045:
					return "Flash fired, red-eye reduction mode, return light not detected";
				case 0x0047:
					return "Flash fired, red-eye reduction mode, return light detected";
				case 0x0049:
					return "Flash fired, compulsory flash mode, red-eye reduction mode";
				case 0x004D:
					return "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected";
				case 0x004F:
					return "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected";
				case 0x0059:
					return "Flash fired, auto mode, red-eye reduction mode";
				case 0x005D:
					return "Flash fired, auto mode, return light not detected, red-eye reduction mode";
				case 0x005F:
					return "Flash fired, auto mode, return light detected, red-eye reduction mode";
				default:
					sprintf(format, "Unknown (%d)", flash);
					buffer += format;
					return buffer.c_str();
			}
		}
		break;

		case TAG_SCENE_TYPE:
		{
			BYTE sceneType = *((BYTE*)FreeImage_GetTagValue(tag));
			if (sceneType == 1) {
				return "Directly photographed image";
			} else {
				sprintf(format, "Unknown (%d)", sceneType);
				buffer += format;
				return buffer.c_str();
			}
		}
		break;

		case TAG_SUBJECT_DISTANCE:
		{
			FIRational r(tag);
			if(r.getNumerator() == 0xFFFFFFFF) {
				return "Infinity";
			} else if(r.getNumerator() == 0) {
				return "Distance unknown";
			} else {
				double distance = r.doubleValue();
				sprintf(format, "%.3f meters", distance);
				buffer += format;
				return buffer.c_str();
			}
		}
		break;
			
		case TAG_METERING_MODE:
		{
			unsigned short meteringMode = *((unsigned short *)FreeImage_GetTagValue(tag));
			switch (meteringMode) {
				case 0:
					return "Unknown";
				case 1:
					return "Average";
				case 2:
					return "Center weighted average";
				case 3:
					return "Spot";
				case 4:
					return "Multi-spot";
				case 5:
					return "Multi-segment";
				case 6:
					return "Partial";
				case 255:
					return "(Other)";
				default:
					return "";
			}
		}
		break;

		case TAG_LIGHT_SOURCE:
		{
			unsigned short lightSource = *((unsigned short *)FreeImage_GetTagValue(tag));
			switch (lightSource) {
				case 0:
					return "Unknown";
				case 1:
					return "Daylight";
				case 2:
					return "Fluorescent";
				case 3:
					return "Tungsten (incandescent light)";
				case 4:
					return "Flash";
				case 9:
					return "Fine weather";
				case 10:
					return "Cloudy weather";
				case 11:
					return "Shade";
				case 12:
					return "Daylight fluorescent (D 5700 - 7100K)";
				case 13:
					return "Day white fluorescent (N 4600 - 5400K)";
				case 14:
					return "Cool white fluorescent (W 3900 - 4500K)";
				case 15:
					return "White fluorescent (WW 3200 - 3700K)";
				case 17:
					return "Standard light A";
				case 18:
					return "Standard light B";
				case 19:
					return "Standard light C";
				case 20:
					return "D55";
				case 21:
					return "D65";
				case 22:
					return "D75";
				case 23:
					return "D50";
				case 24:
					return "ISO studio tungsten";
				case 255:
					return "(Other)";
				default:
					return "";
			}
		}
		break;

		case TAG_SENSING_METHOD:
		{
			unsigned short sensingMethod = *((unsigned short *)FreeImage_GetTagValue(tag));

			switch (sensingMethod) {
				case 1:
					return "(Not defined)";
				case 2:
					return "One-chip color area sensor";
				case 3:
					return "Two-chip color area sensor";
				case 4:
					return "Three-chip color area sensor";
				case 5:
					return "Color sequential area sensor";
				case 7:
					return "Trilinear sensor";
				case 8:
					return "Color sequential linear sensor";
				default:
					return "";
			}
		}
		break;

		case TAG_FILE_SOURCE:
		{
			BYTE fileSource = *((BYTE*)FreeImage_GetTagValue(tag));
			if (fileSource == 3) {
				return "Digital Still Camera (DSC)";
			} else {
				sprintf(format, "Unknown (%d)", fileSource);
				buffer += format;
				return buffer.c_str();
			}
        }
		break;

		case TAG_EXPOSURE_PROGRAM:
		{
			unsigned short exposureProgram = *((unsigned short *)FreeImage_GetTagValue(tag));

			switch (exposureProgram) {
				case 1:
					return "Manual control";
				case 2:
					return "Program normal";
				case 3:
					return "Aperture priority";
				case 4:
					return "Shutter priority";
				case 5:
					return "Program creative (slow program)";
				case 6:
					return "Program action (high-speed program)";
				case 7:
					return "Portrait mode";
				case 8:
					return "Landscape mode";
				default:
					sprintf(format, "Unknown program (%d)", exposureProgram);
					buffer += format;
					return buffer.c_str();
			}
		}
		break;

		case TAG_CUSTOM_RENDERED:
		{
			unsigned short customRendered = *((unsigned short *)FreeImage_GetTagValue(tag));

			switch (customRendered) {
				case 0:
					return "Normal process";
				case 1:
					return "Custom process";
				default:
					sprintf(format, "Unknown rendering (%d)", customRendered);
					buffer += format;
					return buffer.c_str();
			}
		}
		break;

		case TAG_EXPOSURE_MODE:
		{
			unsigned short exposureMode = *((unsigned short *)FreeImage_GetTagValue(tag));

			switch (exposureMode) {
				case 0:
					return "Auto exposure";
				case 1:
					return "Manual exposure";
				case 2:
					return "Auto bracket";
				default:
					sprintf(format, "Unknown mode (%d)", exposureMode);
					buffer += format;
					return buffer.c_str();
			}
		}
		break;

		case TAG_WHITE_BALANCE:
		{
			unsigned short whiteBalance = *((unsigned short *)FreeImage_GetTagValue(tag));

			switch (whiteBalance) {
				case 0:
					return "Auto white balance";
				case 1:
					return "Manual white balance";
				default:
					sprintf(format, "Unknown (%d)", whiteBalance);
					buffer += format;
					return buffer.c_str();
			}
		}
		break;

		case TAG_SCENE_CAPTURE_TYPE:
		{
			unsigned short sceneType = *((unsigned short *)FreeImage_GetTagValue(tag));

			switch (sceneType) {
				case 0:
					return "Standard";
				case 1:
					return "Landscape";
				case 2:
					return "Portrait";
				case 3:
					return "Night scene";
				default:
					sprintf(format, "Unknown (%d)", sceneType);
					buffer += format;
					return buffer.c_str();
			}
		}
		break;

		case TAG_GAIN_CONTROL:
		{
			unsigned short gainControl = *((unsigned short *)FreeImage_GetTagValue(tag));

			switch (gainControl) {
				case 0:
					return "None";
				case 1:
					return "Low gain up";
				case 2:
					return "High gain up";
				case 3:
					return "Low gain down";
				case 4:
					return "High gain down";
				default:
					sprintf(format, "Unknown (%d)", gainControl);
					buffer += format;
					return buffer.c_str();
			}
		}
		break;

		case TAG_CONTRAST:
		{
			unsigned short contrast = *((unsigned short *)FreeImage_GetTagValue(tag));

			switch (contrast) {
				case 0:
					return "Normal";
				case 1:
					return "Soft";
				case 2:
					return "Hard";
				default:
					sprintf(format, "Unknown (%d)", contrast);
					buffer += format;
					return buffer.c_str();
			}
		}
		break;

		case TAG_SATURATION:
		{
			unsigned short saturation = *((unsigned short *)FreeImage_GetTagValue(tag));

			switch (saturation) {
				case 0:
					return "Normal";
				case 1:
					return "Low saturation";
				case 2:
					return "High saturation";
				default:
					sprintf(format, "Unknown (%d)", saturation);
					buffer += format;
					return buffer.c_str();
			}
		}
		break;

		case TAG_SHARPNESS:
		{
			unsigned short sharpness = *((unsigned short *)FreeImage_GetTagValue(tag));

			switch (sharpness) {
				case 0:
					return "Normal";
				case 1:
					return "Soft";
				case 2:
					return "Hard";
				default:
					sprintf(format, "Unknown (%d)", sharpness);
					buffer += format;
					return buffer.c_str();
			}
		}
		break;

		case TAG_SUBJECT_DISTANCE_RANGE:
		{
			unsigned short distanceRange = *((unsigned short *)FreeImage_GetTagValue(tag));

			switch (distanceRange) {
				case 0:
					return "unknown";
				case 1:
					return "Macro";
				case 2:
					return "Close view";
				case 3:
					return "Distant view";
				default:
					sprintf(format, "Unknown (%d)", distanceRange);
					buffer += format;
					return buffer.c_str();
			}
		}
		break;

		case TAG_ISO_SPEED_RATINGS:
		{
			unsigned short isoEquiv = *((unsigned short *)FreeImage_GetTagValue(tag));
			if (isoEquiv < 50) {
				isoEquiv *= 200;
			}
			sprintf(format, "%d", isoEquiv);
			buffer += format;
			return buffer.c_str();
		}
		break;

		case TAG_USER_COMMENT:
		{
			// first 8 bytes are used to define an ID code
			// we assume this is an ASCII string
			const BYTE *userComment = (BYTE*)FreeImage_GetTagValue(tag);
			for(DWORD i = 8; i < FreeImage_GetTagLength(tag); i++) {
				buffer += userComment[i];
			}
			buffer += '\0';
			return buffer.c_str();
		}
		break;

		case TAG_COMPRESSION:
		{
			WORD compression = *((WORD*)FreeImage_GetTagValue(tag));
			switch(compression) {
				case TAG_COMPRESSION_NONE:
					sprintf(format, "dump mode (%d)", compression);
					break;
				case TAG_COMPRESSION_CCITTRLE:
					sprintf(format, "CCITT modified Huffman RLE (%d)", compression);
					break;
				case TAG_COMPRESSION_CCITTFAX3:
					sprintf(format, "CCITT Group 3 fax encoding (%d)", compression);
					break;
				/*
				case TAG_COMPRESSION_CCITT_T4:
					sprintf(format, "CCITT T.4 (TIFF 6 name) (%d)", compression);
					break;
				*/
				case TAG_COMPRESSION_CCITTFAX4:
					sprintf(format, "CCITT Group 4 fax encoding (%d)", compression);
					break;
				/*
				case TAG_COMPRESSION_CCITT_T6:
					sprintf(format, "CCITT T.6 (TIFF 6 name) (%d)", compression);
					break;
				*/
				case TAG_COMPRESSION_LZW:
					sprintf(format, "LZW (%d)", compression);
					break;
				case TAG_COMPRESSION_OJPEG:
					sprintf(format, "!6.0 JPEG (%d)", compression);
					break;
				case TAG_COMPRESSION_JPEG:
					sprintf(format, "JPEG (%d)", compression);
					break;
				case TAG_COMPRESSION_NEXT:
					sprintf(format, "NeXT 2-bit RLE (%d)", compression);
					break;
				case TAG_COMPRESSION_CCITTRLEW:
					sprintf(format, "CCITTRLEW (%d)", compression);
					break;
				case TAG_COMPRESSION_PACKBITS:
					sprintf(format, "PackBits Macintosh RLE (%d)", compression);
					break;
				case TAG_COMPRESSION_THUNDERSCAN:
					sprintf(format, "ThunderScan RLE (%d)", compression);
					break;
				case TAG_COMPRESSION_PIXARFILM:
					sprintf(format, "Pixar companded 10bit LZW (%d)", compression);
					break;
				case TAG_COMPRESSION_PIXARLOG:
					sprintf(format, "Pixar companded 11bit ZIP (%d)", compression);
					break;
				case TAG_COMPRESSION_DEFLATE:
					sprintf(format, "Deflate compression (%d)", compression);
					break;
				case TAG_COMPRESSION_ADOBE_DEFLATE:
					sprintf(format, "Adobe Deflate compression (%d)", compression);
					break;
				case TAG_COMPRESSION_DCS:
					sprintf(format, "Kodak DCS encoding (%d)", compression);
					break;
				case TAG_COMPRESSION_JBIG:
					sprintf(format, "ISO JBIG (%d)", compression);
					break;
				case TAG_COMPRESSION_SGILOG:
					sprintf(format, "SGI Log Luminance RLE (%d)", compression);
					break;
				case TAG_COMPRESSION_SGILOG24:
					sprintf(format, "SGI Log 24-bit packed (%d)", compression);
					break;
				case TAG_COMPRESSION_JP2000:
					sprintf(format, "Leadtools JPEG2000 (%d)", compression);
					break;
				case TAG_COMPRESSION_LZMA:
					sprintf(format, "LZMA2 (%d)", compression);
					break;
				default:
					sprintf(format, "Unknown type (%d)", compression);
					break;
			}

			buffer += format;
			return buffer.c_str();
		}
		break;
	}

	return ConvertAnyTag(tag);
}
Example #7
0
/**
Process a maker note IFD offset
Returns the offset and the metadata model for this tag
*/
static void
processMakerNote(FIBITMAP *dib, char *pval, BOOL msb_order, DWORD *subdirOffset, TagLib::MDMODEL *md_model) {
    FITAG *tagMake = NULL;

    *subdirOffset = 0;
    *md_model = TagLib::UNKNOWN;

    // Determine the camera model and makernote format
    // WARNING: note that Maker may be NULL sometimes so check its value before using it
    // (NULL pointer checking is done by FreeImage_strnicmp)
    FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "Make", &tagMake);
    const char *Maker = (char*)FreeImage_GetTagValue(tagMake);

    if((memcmp("OLYMP\x00\x01", pval, 7) == 0) || (memcmp("OLYMP\x00\x02", pval, 7) == 0) || (memcmp("EPSON", pval, 5) == 0) || (memcmp("AGFA", pval, 4) == 0)) {
        // Olympus Type 1 Makernote
        // Epson and Agfa use Olympus maker note standard,
        // see: http://www.ozhiker.com/electronics/pjmt/jpeg_info/
        *md_model = TagLib::EXIF_MAKERNOTE_OLYMPUSTYPE1;
        *subdirOffset = 8;
    }
    else if(memcmp("OLYMPUS\x00\x49\x49\x03\x00", pval, 12) == 0) {
        // Olympus Type 2 Makernote
        // !!! NOT YET SUPPORTED !!!
        *subdirOffset = 0;
        *md_model = TagLib::UNKNOWN;
    }
    else if(memcmp("Nikon", pval, 5) == 0) {
        /* There are two scenarios here:
         * Type 1:
         * :0000: 4E 69 6B 6F 6E 00 01 00-05 00 02 00 02 00 06 00 Nikon...........
         * :0010: 00 00 EC 02 00 00 03 00-03 00 01 00 00 00 06 00 ................
         * Type 3:
         * :0000: 4E 69 6B 6F 6E 00 02 00-00 00 4D 4D 00 2A 00 00 Nikon....MM.*...
         * :0010: 00 08 00 1E 00 01 00 07-00 00 00 04 30 32 30 30 ............0200
         */
        if (pval[6] == 1) {
            // Nikon type 1 Makernote
            *md_model = TagLib::EXIF_MAKERNOTE_NIKONTYPE1;
            *subdirOffset = 8;
        } else if (pval[6] == 2) {
            // Nikon type 3 Makernote
            *md_model = TagLib::EXIF_MAKERNOTE_NIKONTYPE3;
            *subdirOffset = 18;
        } else {
            // Unsupported makernote data ignored
            *subdirOffset = 0;
            *md_model = TagLib::UNKNOWN;
        }
    } else if(Maker && (FreeImage_strnicmp("NIKON", Maker, 5) == 0)) {
        // Nikon type 2 Makernote
        *md_model = TagLib::EXIF_MAKERNOTE_NIKONTYPE2;
        *subdirOffset = 0;
    } else if(Maker && (FreeImage_strnicmp("Canon", Maker, 5) == 0)) {
        // Canon Makernote
        *md_model = TagLib::EXIF_MAKERNOTE_CANON;
        *subdirOffset = 0;
    } else if(Maker && (FreeImage_strnicmp("Casio", Maker, 5) == 0)) {
        // Casio Makernote
        if(memcmp("QVC\x00\x00\x00", pval, 6) == 0) {
            // Casio Type 2 Makernote
            *md_model = TagLib::EXIF_MAKERNOTE_CASIOTYPE2;
            *subdirOffset = 6;
        } else {
            // Casio Type 1 Makernote
            *md_model = TagLib::EXIF_MAKERNOTE_CASIOTYPE1;
            *subdirOffset = 0;
        }
    } else if ((memcmp("FUJIFILM", pval, 8) == 0) || (Maker && (FreeImage_strnicmp("Fujifilm", Maker, 8) == 0))) {
        // Fujifile Makernote
        // Fujifilm's Makernote always use Intel order altough the Exif section maybe in Intel order or in Motorola order.
        // If msb_order == TRUE, the Makernote won't be read:
        // the value of ifdStart will be 0x0c000000 instead of 0x0000000c and the MakerNote section will be discarded later
        // in jpeg_read_exif_dir because the IFD is too high
        *md_model = TagLib::EXIF_MAKERNOTE_FUJIFILM;
        DWORD ifdStart = (DWORD) ReadUint32(msb_order, pval + 8);
        *subdirOffset = ifdStart;
    }
    else if(memcmp("KYOCERA\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x00\x00\x00", pval, 22) == 0) {
        *md_model = TagLib::EXIF_MAKERNOTE_KYOCERA;
        *subdirOffset = 22;
    }
    else if(Maker && (FreeImage_strnicmp("Minolta", Maker, 7) == 0)) {
        // Minolta maker note
        *md_model = TagLib::EXIF_MAKERNOTE_MINOLTA;
        *subdirOffset = 0;
    }
    else if(memcmp("Panasonic\x00\x00\x00", pval, 12) == 0) {
        // Panasonic maker note
        *md_model = TagLib::EXIF_MAKERNOTE_PANASONIC;
        *subdirOffset = 12;
    }
    else if(Maker && (FreeImage_strnicmp("LEICA", Maker, 5) == 0)) {
        // Leica maker note
        if(memcmp("LEICA\x00\x00\x00", pval, 8) == 0) {
            // not yet supported makernote data ignored
            *subdirOffset = 0;
            *md_model = TagLib::UNKNOWN;
        }
    }
    else if(Maker && ((FreeImage_strnicmp("Pentax", Maker, 6) == 0) || (FreeImage_strnicmp("Asahi", Maker, 5) == 0))) {
        // Pentax maker note
        if(memcmp("AOC\x00", pval, 4) == 0) {
            // Type 2 Pentax Makernote
            *md_model = TagLib::EXIF_MAKERNOTE_PENTAX;
            *subdirOffset = 6;
        } else {
            // Type 1 Pentax Makernote
            *md_model = TagLib::EXIF_MAKERNOTE_ASAHI;
            *subdirOffset = 0;
        }
    }
    else if((memcmp("SONY CAM\x20\x00\x00\x00", pval, 12) == 0) || (memcmp("SONY DSC\x20\x00\x00\x00", pval, 12) == 0)) {
        *md_model = TagLib::EXIF_MAKERNOTE_SONY;
        *subdirOffset = 12;
    }
    else if((memcmp("SIGMA\x00\x00\x00", pval, 8) == 0) || (memcmp("FOVEON\x00\x00", pval, 8) == 0)) {
        FITAG *tagModel = NULL;
        FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "Model", &tagModel);
        const char *Model = (char*)FreeImage_GetTagValue(tagModel);
        if(Model && (memcmp("SIGMA SD1\x00", Model, 10) == 0)) {
            // Sigma SD1 maker note
            *subdirOffset = 10;
            *md_model = TagLib::EXIF_MAKERNOTE_SIGMA_SD1;
        } else {
            // Sigma / Foveon makernote
            *subdirOffset = 10;
            *md_model = TagLib::EXIF_MAKERNOTE_SIGMA_FOVEON;
        }
    }
}
Example #8
0
/**
Process a Canon maker note tag.
A single Canon tag may contain many other tags within.
*/
static BOOL
processCanonMakerNoteTag(FIBITMAP *dib, FITAG *tag) {
    char defaultKey[16];
    DWORD startIndex = 0;
    TagLib& s = TagLib::instance();

    WORD tag_id = FreeImage_GetTagID(tag);

    int subTagTypeBase = 0;

    switch(tag_id) {
    case TAG_CANON_CAMERA_STATE_0x01:
        subTagTypeBase = 0xC100;
        startIndex = 1;
        break;
    case TAG_CANON_CAMERA_STATE_0x02:
        subTagTypeBase = 0xC200;
        startIndex = 0;
        break;
    case TAG_CANON_CAMERA_STATE_0x04:
        subTagTypeBase = 0xC400;
        startIndex = 1;
        break;
    case TAG_CANON_CAMERA_STATE_0x12:
        subTagTypeBase = 0x1200;
        startIndex = 0;
        break;
    case TAG_CANON_CAMERA_STATE_0xA0:
        subTagTypeBase = 0xCA00;
        startIndex = 1;
        break;
    case TAG_CANON_CAMERA_STATE_0xE0:
        subTagTypeBase = 0xCE00;
        startIndex = 1;
        break;

    default:
    {
        // process as a normal tag

        // get the tag key and description
        const char *key = s.getTagFieldName(TagLib::EXIF_MAKERNOTE_CANON, tag_id, defaultKey);
        FreeImage_SetTagKey(tag, key);
        const char *description = s.getTagDescription(TagLib::EXIF_MAKERNOTE_CANON, tag_id);
        FreeImage_SetTagDescription(tag, description);

        // store the tag
        if(key) {
            FreeImage_SetMetadata(FIMD_EXIF_MAKERNOTE, dib, key, tag);
        }

        return TRUE;
    }
    break;

    }

    WORD *pvalue = (WORD*)FreeImage_GetTagValue(tag);

    // create a tag
    FITAG *canonTag = FreeImage_CreateTag();
    if(!canonTag) return FALSE;

    // we intentionally skip the first array member (if needed)
    for (DWORD i = startIndex; i < FreeImage_GetTagCount(tag); i++) {

        tag_id = (WORD)(subTagTypeBase + i);

        FreeImage_SetTagID(canonTag, tag_id);
        FreeImage_SetTagType(canonTag, FIDT_SHORT);
        FreeImage_SetTagCount(canonTag, 1);
        FreeImage_SetTagLength(canonTag, 2);
        FreeImage_SetTagValue(canonTag, &pvalue[i]);

        // get the tag key and description
        const char *key = s.getTagFieldName(TagLib::EXIF_MAKERNOTE_CANON, tag_id, defaultKey);
        FreeImage_SetTagKey(canonTag, key);
        const char *description = s.getTagDescription(TagLib::EXIF_MAKERNOTE_CANON, tag_id);
        FreeImage_SetTagDescription(canonTag, description);

        // store the tag
        if(key) {
            FreeImage_SetMetadata(FIMD_EXIF_MAKERNOTE, dib, key, canonTag);
        }
    }

    // delete the tag
    FreeImage_DeleteTag(canonTag);

    return TRUE;
}
Example #9
0
/**
Write a metadata model as a TIF IFD to a FIMEMORY handle.
The entries in the TIF IFD are sorted in ascending order by tag id.	
The last entry is written as 0 (4 bytes) which means no more IFD to follow. 
Supported metadata models are
<ul>
<li>FIMD_EXIF_MAIN
<li>FIMD_EXIF_EXIF
<li>FIMD_EXIF_GPS
<li>FIMD_EXIF_INTEROP
</ul>
The end of the buffer is filled with 4 bytes equal to 0 (end of IFD offset)

@param dib Input FIBITMAP
@param md_model Metadata model to write
@param hmem Memory handle
@return Returns TRUE if successful, FALSE otherwise
@see tiff_get_ifd_profile
*/
static BOOL
tiff_write_ifd(FIBITMAP *dib, FREE_IMAGE_MDMODEL md_model, FIMEMORY *hmem) {
	FITAG *tag = NULL;
	FIMETADATA *mdhandle = NULL;
	std::vector<FITAG*> vTagList;
	TagLib::MDMODEL internal_md_model;

	DWORD ifd_offset = 0;	// WORD-aligned IFD value offset

	const BYTE empty_byte = 0;

	// start of the file
	const long start_of_file = FreeImage_TellMemory(hmem);

	// get the metadata count
	unsigned metadata_count = FreeImage_GetMetadataCount(md_model, dib);
	if(metadata_count == 0) {
		return FALSE;
	}

	TagLib& s = TagLib::instance();

	// check for supported metadata models
	switch(md_model) {
		case FIMD_EXIF_MAIN:
			internal_md_model = TagLib::EXIF_MAIN;
			break;
		case FIMD_EXIF_EXIF:
			internal_md_model = TagLib::EXIF_EXIF;
			break;
		case FIMD_EXIF_GPS:
			internal_md_model = TagLib::EXIF_GPS;
			break;
		case FIMD_EXIF_INTEROP:
			internal_md_model = TagLib::EXIF_INTEROP;
			break;
		default:
			return FALSE;
	}

	try {
		// 1) according to the TIFF specifications, 
		// the entries in a TIF IFD must be sorted in ascending order by tag id

		// store the tags into a vector
		vTagList.reserve(metadata_count);
		mdhandle = FreeImage_FindFirstMetadata(md_model, dib, &tag);
		if(mdhandle) {
			// parse the tags and store them inside vTagList
			do {
				// rewrite the tag id using FreeImage internal database
				// (in case the tag id is wrong or missing)
				const char *key = FreeImage_GetTagKey(tag);
				int tag_id = s.getTagID(internal_md_model, key);
				if(tag_id != -1) {
					// this is a known tag, set the tag ID
					FreeImage_SetTagID(tag, (WORD)tag_id);
					// record the tag
					vTagList.push_back(tag);
				}
				// else ignore this tag
			} while(FreeImage_FindNextMetadata(mdhandle, &tag));

			FreeImage_FindCloseMetadata(mdhandle);

			// sort the vector by tag id
			std::sort(vTagList.begin(), vTagList.end(), PredicateTagIDCompare());

			// update the metadata_count
			metadata_count = (unsigned)vTagList.size();

		} else {
			throw(1);
		}

		// 2) prepare the place for each IFD entries.

		/*
		An Image File Directory (IFD) consists of a 2-byte count of the number of directory entries (i.e., the number of fields), 
		followed by a sequence of 12-byte field entries, 
		followed by a 4-byte offset of the next IFD (or 0 if none). Do not forget to write the 4 bytes of 0 after the last IFD.
		*/

		{		
			// prepare place for 2 bytes for number of entries + 12 bytes for each entry
			unsigned ifd_size = 2 + 12 * metadata_count;
			FreeImage_WriteMemory(&empty_byte, 1, ifd_size, hmem);
			// record the offset used to write values > 4-bytes
			ifd_offset = FreeImage_TellMemory(hmem);
			// rewind
			FreeImage_SeekMemory(hmem, start_of_file, SEEK_SET);
		}

		// 3) write each IFD entry in tag id ascending order

		// number of directory entries
		WORD nde = (WORD)metadata_count;
		FreeImage_WriteMemory(&nde, 1, 2, hmem);

		// for each entry ...
		for(unsigned i = 0; i < metadata_count; i++) {
			FITAG *tag = vTagList[i];
			// tag id
			WORD tag_id = FreeImage_GetTagID(tag);
			FreeImage_WriteMemory(&tag_id, 1, 2, hmem);
			// tag type (compliant with TIFF specification)
			WORD tag_type = (WORD)FreeImage_GetTagType(tag);
			FreeImage_WriteMemory(&tag_type, 1, 2, hmem);
			// tag count
			DWORD tag_count = FreeImage_GetTagCount(tag);
			FreeImage_WriteMemory(&tag_count, 1, 4, hmem);
			// tag value or offset (results are in BYTE's units)
			unsigned tag_length = FreeImage_GetTagLength(tag);
			if(tag_length <= 4) {
				// 4 bytes or less, write the value (left justified)
				const BYTE *tag_value = (BYTE*)FreeImage_GetTagValue(tag);
				FreeImage_WriteMemory(tag_value, 1, tag_length, hmem);
				for(unsigned k = tag_length; k < 4; k++) {
					FreeImage_WriteMemory(&empty_byte, 1, 1, hmem);
				}
			} else {
				// write an offset
				FreeImage_WriteMemory(&ifd_offset, 1, 4, hmem);
				// write the value
				long current_position = FreeImage_TellMemory(hmem);
				FreeImage_SeekMemory(hmem, ifd_offset, SEEK_SET);
				FreeImage_WriteMemory(FreeImage_GetTagValue(tag), 1, tag_length, hmem);
				if(tag_length & 1) {
					// align to the next WORD boundary
					FreeImage_WriteMemory(&empty_byte, 1, 1, hmem);
				}
				// next offset to use
				ifd_offset = FreeImage_TellMemory(hmem);
				// rewind
				FreeImage_SeekMemory(hmem, current_position, SEEK_SET);
			}
		}

		// end-of-IFD or next IFD (0 == none)
		FreeImage_SeekMemory(hmem, ifd_offset, SEEK_SET);
		FreeImage_WriteMemory(&empty_byte, 1, 4, hmem);

		return TRUE;
	}
	catch(int) {
		return FALSE;
	}
}
Example #10
0
static BOOL 
WriteMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) {
	// XMP keyword
	const char *g_png_xmp_keyword = "XML:com.adobe.xmp";

	FITAG *tag = NULL;
	FIMETADATA *mdhandle = NULL;
	BOOL bResult = TRUE;

	png_text text_metadata;
	png_time mod_time;

	// set the 'Comments' metadata as iTXt chuncks

	mdhandle = FreeImage_FindFirstMetadata(FIMD_COMMENTS, dib, &tag);

	if(mdhandle) {
		do {
			memset(&text_metadata, 0, sizeof(png_text));
			text_metadata.compression = 1;							// iTXt, none
			text_metadata.key = (char*)FreeImage_GetTagKey(tag);	// keyword, 1-79 character description of "text"
			text_metadata.text = (char*)FreeImage_GetTagValue(tag);	// comment, may be an empty string (ie "")
			text_metadata.text_length = FreeImage_GetTagLength(tag);// length of the text string
			text_metadata.itxt_length = FreeImage_GetTagLength(tag);// length of the itxt string
			text_metadata.lang = 0;		 // language code, 0-79 characters or a NULL pointer
			text_metadata.lang_key = 0;	 // keyword translated UTF-8 string, 0 or more chars or a NULL pointer

			// set the tag 
			png_set_text(png_ptr, info_ptr, &text_metadata, 1);

		} while(FreeImage_FindNextMetadata(mdhandle, &tag));

		FreeImage_FindCloseMetadata(mdhandle);
		bResult &= TRUE;
	}

	// set the 'XMP' metadata as iTXt chuncks
	tag = NULL;
	FreeImage_GetMetadata(FIMD_XMP, dib, g_TagLib_XMPFieldName, &tag);
	if(tag && FreeImage_GetTagLength(tag)) {
		memset(&text_metadata, 0, sizeof(png_text));
		text_metadata.compression = 1;							// iTXt, none
		text_metadata.key = (char*)g_png_xmp_keyword;			// keyword, 1-79 character description of "text"
		text_metadata.text = (char*)FreeImage_GetTagValue(tag);	// comment, may be an empty string (ie "")
		text_metadata.text_length = FreeImage_GetTagLength(tag);// length of the text string
		text_metadata.itxt_length = FreeImage_GetTagLength(tag);// length of the itxt string
		text_metadata.lang = 0;		 // language code, 0-79 characters or a NULL pointer
		text_metadata.lang_key = 0;	 // keyword translated UTF-8 string, 0 or more chars or a NULL pointer

		// set the tag 
		png_set_text(png_ptr, info_ptr, &text_metadata, 1);
		bResult &= TRUE;
	}

	// set the Exif-TIFF 'DateTime' metadata as a tIME chunk
	tag = NULL;
	FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "DateTime", &tag);
	if(tag && FreeImage_GetTagLength(tag)) {
		int year, month, day, hour, minute, second;
		const char *value = (char*)FreeImage_GetTagValue(tag);
		if(sscanf(value, "%4d:%02d:%02d %2d:%02d:%02d", &year, &month, &day, &hour, &minute, &second) == 6) {
			mod_time.year	= (png_uint_16)year;
			mod_time.month	= (png_byte)month;
			mod_time.day	= (png_byte)day;
			mod_time.hour	= (png_byte)hour;
			mod_time.minute	= (png_byte)minute;
			mod_time.second	= (png_byte)second;
			png_set_tIME (png_ptr, info_ptr, &mod_time);
		}
	}

	return bResult;
}
Example #11
0
/**
Process a Canon maker note tag. 
A single Canon tag may contain many other tags within.
*/
static void 
processCanonMakerNoteTag(FIBITMAP *dib, FITAG *tag) {
	char defaultKey[16];
	DWORD startIndex = 0;
	TagLib& s = TagLib::instance();

	WORD tag_id = FreeImage_GetTagID(tag);

	if((tag_id == TAG_CANON_CAMERA_STATE_1) || (tag_id == TAG_CANON_CAMERA_STATE_2) || (tag_id == TAG_CANON_CAMERA_STATE_4)) {
		// this single tag has multiple values within

		int subTagTypeBase = 0;

		switch(tag_id) {
			case TAG_CANON_CAMERA_STATE_1:
				subTagTypeBase = 0xC100;
				startIndex = 1;
				break;
			case TAG_CANON_CAMERA_STATE_2:
				subTagTypeBase = 0xC200;
				startIndex = 0;
				break;
			case TAG_CANON_CAMERA_STATE_4:
				subTagTypeBase = 0xC400;
				startIndex = 2;
				break;
		}

		WORD *pvalue = (WORD*)FreeImage_GetTagValue(tag);

        // we intentionally skip the first array member
        for (DWORD i = startIndex; i < FreeImage_GetTagCount(tag); i++) {
			// create a tag
			FITAG *canonTag = FreeImage_CreateTag();
			if(!canonTag) return;

			tag_id = (WORD)(subTagTypeBase + i);

			FreeImage_SetTagID(canonTag, tag_id);
			FreeImage_SetTagType(canonTag, FIDT_SHORT);
			FreeImage_SetTagCount(canonTag, 1);
			FreeImage_SetTagLength(canonTag, 2);
			FreeImage_SetTagValue(canonTag, &pvalue[i]);

			// get the tag key and description
			const char *key = s.getTagFieldName(TagLib::EXIF_MAKERNOTE_CANON, tag_id, defaultKey);
			FreeImage_SetTagKey(canonTag, key);
			const char *description = s.getTagDescription(TagLib::EXIF_MAKERNOTE_CANON, tag_id);
			FreeImage_SetTagDescription(canonTag, description);

			// store the tag
			if(key) {
				FreeImage_SetMetadata(FIMD_EXIF_MAKERNOTE, dib, key, canonTag);
			}

			// delete the tag
			FreeImage_DeleteTag(canonTag);
        }
	}
	else {
		// process as a normal tag

		// get the tag key and description
		const char *key = s.getTagFieldName(TagLib::EXIF_MAKERNOTE_CANON, tag_id, defaultKey);
		FreeImage_SetTagKey(tag, key);
		const char *description = s.getTagDescription(TagLib::EXIF_MAKERNOTE_CANON, tag_id);
		FreeImage_SetTagDescription(tag, description);

		// store the tag
		if(key) {
			FreeImage_SetMetadata(FIMD_EXIF_MAKERNOTE, dib, key, tag);
		}
	}
}
Example #12
0
static BOOL DLL_CALLCONV
Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
	WebPMux *mux = NULL;
	FIMEMORY *hmem = NULL;
	WebPData webp_image;
	WebPData output_data = { 0 };
	WebPMuxError error_status;

	int copy_data = 1;	// 1 : copy data into the mux, 0 : keep a link to local data

	if(!dib || !handle || !data) {
		return FALSE;
	}

	try {

		// get the MUX object
		mux = (WebPMux*)data;
		if(!mux) {
			return FALSE;
		}

		// --- prepare image data ---

		// encode image as a WebP blob
		hmem = FreeImage_OpenMemory();
		if(!hmem || !EncodeImage(hmem, dib, flags)) {
			throw (1);
		}
		// store the blob into the mux
		BYTE *data = NULL;
		DWORD data_size = 0;
		FreeImage_AcquireMemory(hmem, &data, &data_size);
		webp_image.bytes = data;
		webp_image.size = data_size;
		error_status = WebPMuxSetImage(mux, &webp_image, copy_data);
		// no longer needed since copy_data == 1
		FreeImage_CloseMemory(hmem);
		hmem = NULL;
		if(error_status != WEBP_MUX_OK) {
			throw (1);
		}

		// --- set metadata ---
		
		// set ICC color profile
		{
			FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(dib);
			if (iccProfile->size && iccProfile->data) {
				WebPData icc_profile;
				icc_profile.bytes = (uint8_t*)iccProfile->data;
				icc_profile.size = (size_t)iccProfile->size;
				error_status = WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data);
				if(error_status != WEBP_MUX_OK) {
					throw (1);
				}
			}
		}

		// set XMP metadata
		{
			FITAG *tag = NULL;
			if(FreeImage_GetMetadata(FIMD_XMP, dib, g_TagLib_XMPFieldName, &tag)) {
				WebPData xmp_profile;
				xmp_profile.bytes = (uint8_t*)FreeImage_GetTagValue(tag);
				xmp_profile.size = (size_t)FreeImage_GetTagLength(tag);
				error_status = WebPMuxSetChunk(mux, "XMP ", &xmp_profile, copy_data);
				if(error_status != WEBP_MUX_OK) {
					throw (1);
				}
			}
		}

		// set Exif metadata
		{
			FITAG *tag = NULL;
			if(FreeImage_GetMetadata(FIMD_EXIF_RAW, dib, g_TagLib_ExifRawFieldName, &tag)) {
				WebPData exif_profile;
				exif_profile.bytes = (uint8_t*)FreeImage_GetTagValue(tag);
				exif_profile.size = (size_t)FreeImage_GetTagLength(tag);
				error_status = WebPMuxSetChunk(mux, "EXIF", &exif_profile, copy_data);
				if(error_status != WEBP_MUX_OK) {
					throw (1);
				}
			}
		}
		
		// get data from mux in WebP RIFF format
		error_status = WebPMuxAssemble(mux, &output_data);
		if(error_status != WEBP_MUX_OK) {
			FreeImage_OutputMessageProc(s_format_id, "Failed to create webp output file");
			throw (1);
		}

		// write the file to the output stream
		if(io->write_proc((void*)output_data.bytes, 1, (unsigned)output_data.size, handle) != output_data.size) {
			FreeImage_OutputMessageProc(s_format_id, "Failed to write webp output file");
			throw (1);
		}

		// free WebP output file
		WebPDataClear(&output_data);

		return TRUE;

	} catch(int) {
		if(hmem) {
			FreeImage_CloseMemory(hmem);
		}
		
		WebPDataClear(&output_data);

		return FALSE;
	}
}
Example #13
0
/**
Write ICC, XMP, Exif, Exif-GPS, IPTC, descriptive (i.e. Exif-TIFF) metadata
*/
static ERR
WriteMetadata(PKImageEncode *pIE, FIBITMAP *dib) {
	ERR error_code = 0;		// error code as returned by the interface
	BYTE *profile = NULL;
	unsigned profile_size = 0;
	
	try {
		// write ICC profile
		{
			FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(dib);
			if(iccProfile->data) {
				error_code = pIE->SetColorContext(pIE, (U8*)iccProfile->data, iccProfile->size);
				JXR_CHECK(error_code);
			}
		}
		
		// write descriptive metadata
		if(FreeImage_GetMetadataCount(FIMD_EXIF_MAIN, dib)) {
			error_code = WriteDescriptiveMetadata(pIE, dib);
			JXR_CHECK(error_code);
		}

		// write IPTC metadata
		if(FreeImage_GetMetadataCount(FIMD_IPTC, dib)) {
			// create a binary profile
			if(write_iptc_profile(dib, &profile, &profile_size)) {
				// write the profile
				error_code = PKImageEncode_SetIPTCNAAMetadata_WMP(pIE, profile, profile_size);
				JXR_CHECK(error_code);
				// release profile
				free(profile);
				profile = NULL;
			}
		}

		// write XMP metadata
		{
			FITAG *tag_xmp = NULL;
			if(FreeImage_GetMetadata(FIMD_XMP, dib, g_TagLib_XMPFieldName, &tag_xmp)) {
				error_code = PKImageEncode_SetXMPMetadata_WMP(pIE, (BYTE*)FreeImage_GetTagValue(tag_xmp), FreeImage_GetTagLength(tag_xmp));
				JXR_CHECK(error_code);
			}
		}

		// write Exif metadata
		{
			if(tiff_get_ifd_profile(dib, FIMD_EXIF_EXIF, &profile, &profile_size)) {
				error_code = PKImageEncode_SetEXIFMetadata_WMP(pIE, profile, profile_size);
				JXR_CHECK(error_code);
				// release profile
				free(profile);
				profile = NULL;
			}
		}

		// write Exif GPS metadata
		{
			if(tiff_get_ifd_profile(dib, FIMD_EXIF_GPS, &profile, &profile_size)) {
				error_code = PKImageEncode_SetGPSInfoMetadata_WMP(pIE, profile, profile_size);
				JXR_CHECK(error_code);
				// release profile
				free(profile);
				profile = NULL;
			}
		}

		return WMP_errSuccess;

	} catch(...) {
		free(profile);
		return error_code;
	}
}