Пример #1
0
static WebPMux* DuplicateMuxHeader(const WebPMux* const mux) {
  WebPMux* new_mux = WebPMuxNew();
  WebPMuxAnimParams p;
  WebPMuxError err;
  int i;
  int ok = 1;

  if (new_mux == NULL) return NULL;

  err = WebPMuxGetAnimationParams(mux, &p);
  if (err == WEBP_MUX_OK) {
    err = WebPMuxSetAnimationParams(new_mux, &p);
    if (err != WEBP_MUX_OK) {
      ERROR_GOTO2("Error (%s) handling animation params.\n",
                  ErrorString(err), End);
    }
  } else {
    /* it might not be an animation. Just keep moving. */
  }

  for (i = 1; i <= 3; ++i) {
    WebPData metadata;
    err = WebPMuxGetChunk(mux, kFourccList[i], &metadata);
    if (err == WEBP_MUX_OK && metadata.size > 0) {
      err = WebPMuxSetChunk(new_mux, kFourccList[i], &metadata, 1);
      if (err != WEBP_MUX_OK) {
        ERROR_GOTO1("Error transferring metadata in DuplicateMux().", End);
      }
    }
  }

 End:
  if (!ok) {
    WebPMuxDelete(new_mux);
    new_mux = NULL;
  }
  return new_mux;
}
Пример #2
0
static int
read_header( Read *read, VipsImage *out )
{
	vips_image_init_fields( out,
		read->width, read->height,
		read->config.input.has_alpha ? 4 : 3,
		VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
		VIPS_INTERPRETATION_sRGB,
		1.0, 1.0 );

	vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );

#ifdef HAVE_LIBWEBPMUX
{
	WebPData bitstream;
	WebPMux *mux;
	int i;

	/* We have to parse the whole file again to get the metadata out.
	 *
	 * Don't make parse failure an error. We don't want to refuse to read
	 * any pixels because of some malformed metadata.
	 */
	bitstream.bytes = read->data;
	bitstream.size = read->length;
	if( !(mux = WebPMuxCreate( &bitstream, 0 )) ) {
		vips_warn( "webp", "%s", _( "unable to read image metadata" ) ); 
		return( 0 ); 
	}

	for( i = 0; i < vips__n_webp_names; i++ ) { 
		const char *vips = vips__webp_names[i].vips;
		const char *webp = vips__webp_names[i].webp;

		WebPData data;

		if( WebPMuxGetChunk( mux, webp, &data ) == WEBP_MUX_OK ) { 
			void *blob;

			if( !(blob = vips_malloc( NULL, data.size )) ) {
				WebPMuxDelete( mux ); 
				return( -1 ); 
			}

			memcpy( blob, data.bytes, data.size );
			vips_image_set_blob( out, vips, 
				(VipsCallbackFn) vips_free, blob, data.size );
		}
	}

	WebPMuxDelete( mux ); 

	/* We may have read some exif ... parse into the header.
	 */
	if( vips__exif_parse( out ) )
		return( -1 ); 
}
#endif /*HAVE_LIBWEBPMUX*/

	return( 0 );
}
Пример #3
0
static WebPMuxError DisplayInfo(const WebPMux* mux) {
  int width, height;
  uint32_t flag;

  WebPMuxError err = WebPMuxGetCanvasSize(mux, &width, &height);
  assert(err == WEBP_MUX_OK);  // As WebPMuxCreate() was successful earlier.
  printf("Canvas size: %d x %d\n", width, height);

  err = WebPMuxGetFeatures(mux, &flag);
  if (flag & FRAGMENTS_FLAG) err = WEBP_MUX_INVALID_ARGUMENT;
  RETURN_IF_ERROR("Failed to retrieve features\n");

  if (flag == 0) {
    fprintf(stderr, "No features present.\n");
    return err;
  }

  // Print the features present.
  printf("Features present:");
  if (flag & ANIMATION_FLAG) printf(" animation");
  if (flag & FRAGMENTS_FLAG) printf(" image fragments");
  if (flag & ICCP_FLAG)      printf(" ICC profile");
  if (flag & EXIF_FLAG)      printf(" EXIF metadata");
  if (flag & XMP_FLAG)       printf(" XMP metadata");
  if (flag & ALPHA_FLAG)     printf(" transparency");
  printf("\n");

  if ((flag & ANIMATION_FLAG) || (flag & FRAGMENTS_FLAG)) {
    const int is_anim = !!(flag & ANIMATION_FLAG);
    const WebPChunkId id = is_anim ? WEBP_CHUNK_ANMF : WEBP_CHUNK_FRGM;
    const char* const type_str = is_anim ? "frame" : "fragment";
    int nFrames;

    if (is_anim) {
      WebPMuxAnimParams params;
      err = WebPMuxGetAnimationParams(mux, &params);
      assert(err == WEBP_MUX_OK);
      printf("Background color : 0x%.8X  Loop Count : %d\n",
             params.bgcolor, params.loop_count);
    }

    err = WebPMuxNumChunks(mux, id, &nFrames);
    assert(err == WEBP_MUX_OK);

    printf("Number of %ss: %d\n", type_str, nFrames);
    if (nFrames > 0) {
      int i;
      printf("No.: width height alpha x_offset y_offset ");
      if (is_anim) printf("duration   dispose blend ");
      printf("image_size\n");
      for (i = 1; i <= nFrames; i++) {
        WebPMuxFrameInfo frame;
        err = WebPMuxGetFrame(mux, i, &frame);
        if (err == WEBP_MUX_OK) {
          WebPBitstreamFeatures features;
          const VP8StatusCode status = WebPGetFeatures(
              frame.bitstream.bytes, frame.bitstream.size, &features);
          assert(status == VP8_STATUS_OK);  // Checked by WebPMuxCreate().
          (void)status;
          printf("%3d: %5d %5d %5s %8d %8d ", i, features.width,
                 features.height, features.has_alpha ? "yes" : "no",
                 frame.x_offset, frame.y_offset);
          if (is_anim) {
            const char* const dispose =
                (frame.dispose_method == WEBP_MUX_DISPOSE_NONE) ? "none"
                                                                : "background";
            const char* const blend =
                (frame.blend_method == WEBP_MUX_BLEND) ? "yes" : "no";
            printf("%8d %10s %5s ", frame.duration, dispose, blend);
          }
          printf("%10d\n", (int)frame.bitstream.size);
        }
        WebPDataClear(&frame.bitstream);
        RETURN_IF_ERROR3("Failed to retrieve %s#%d\n", type_str, i);
      }
    }
  }

  if (flag & ICCP_FLAG) {
    WebPData icc_profile;
    err = WebPMuxGetChunk(mux, "ICCP", &icc_profile);
    assert(err == WEBP_MUX_OK);
    printf("Size of the ICC profile data: %d\n", (int)icc_profile.size);
  }

  if (flag & EXIF_FLAG) {
    WebPData exif;
    err = WebPMuxGetChunk(mux, "EXIF", &exif);
    assert(err == WEBP_MUX_OK);
    printf("Size of the EXIF metadata: %d\n", (int)exif.size);
  }

  if (flag & XMP_FLAG) {
    WebPData xmp;
    err = WebPMuxGetChunk(mux, "XMP ", &xmp);
    assert(err == WEBP_MUX_OK);
    printf("Size of the XMP metadata: %d\n", (int)xmp.size);
  }

  if ((flag & ALPHA_FLAG) && !(flag & (ANIMATION_FLAG | FRAGMENTS_FLAG))) {
    WebPMuxFrameInfo image;
    err = WebPMuxGetFrame(mux, 1, &image);
    if (err == WEBP_MUX_OK) {
      printf("Size of the image (with alpha): %d\n", (int)image.bitstream.size);
    }
    WebPDataClear(&image.bitstream);
    RETURN_IF_ERROR("Failed to retrieve the image\n");
  }

  return WEBP_MUX_OK;
}
Пример #4
0
static WebPMuxError DisplayInfo(const WebPMux* mux) {
  uint32_t flag;

  WebPMuxError err = WebPMuxGetFeatures(mux, &flag);
#ifndef WEBP_EXPERIMENTAL_FEATURES
  if (flag & FRAGMENTS_FLAG) err = WEBP_MUX_INVALID_ARGUMENT;
#endif
  RETURN_IF_ERROR("Failed to retrieve features\n");

  if (flag == 0) {
    fprintf(stderr, "No features present.\n");
    return err;
  }

  // Print the features present.
  printf("Features present:");
  if (flag & ANIMATION_FLAG) printf(" animation");
  if (flag & FRAGMENTS_FLAG) printf(" image fragments");
  if (flag & ICCP_FLAG)      printf(" ICC profile");
  if (flag & EXIF_FLAG)      printf(" EXIF metadata");
  if (flag & XMP_FLAG)       printf(" XMP metadata");
  if (flag & ALPHA_FLAG)     printf(" transparency");
  printf("\n");

  if ((flag & ANIMATION_FLAG) || (flag & FRAGMENTS_FLAG)) {
    const int is_anim = !!(flag & ANIMATION_FLAG);
    const WebPChunkId id = is_anim ? WEBP_CHUNK_ANMF : WEBP_CHUNK_FRGM;
    const char* const type_str = is_anim ? "frame" : "fragment";
    int nFrames;

    if (is_anim) {
      WebPMuxAnimParams params;
      err = WebPMuxGetAnimationParams(mux, &params);
      RETURN_IF_ERROR("Failed to retrieve animation parameters\n");
      printf("Background color : 0x%.8X  Loop Count : %d\n",
             params.bgcolor, params.loop_count);
    }

    err = WebPMuxNumChunks(mux, id, &nFrames);
    RETURN_IF_ERROR2("Failed to retrieve number of %ss\n", type_str);

    printf("Number of %ss: %d\n", type_str, nFrames);
    if (nFrames > 0) {
      int i;
      printf("No.: x_offset y_offset ");
      if (is_anim) printf("duration dispose ");
      printf("image_size\n");
      for (i = 1; i <= nFrames; i++) {
        WebPMuxFrameInfo frame;
        err = WebPMuxGetFrame(mux, i, &frame);
        if (err == WEBP_MUX_OK) {
          printf("%3d: %8d %8d ", i, frame.x_offset, frame.y_offset);
          if (is_anim) printf("%8d %7d ", frame.duration, frame.dispose_method);
          printf("%10d\n", (int)frame.bitstream.size);
        }
        WebPDataClear(&frame.bitstream);
        RETURN_IF_ERROR3("Failed to retrieve %s#%d\n", type_str, i);
      }
    }
  }

  if (flag & ICCP_FLAG) {
    WebPData icc_profile;
    err = WebPMuxGetChunk(mux, "ICCP", &icc_profile);
    RETURN_IF_ERROR("Failed to retrieve the ICC profile\n");
    printf("Size of the ICC profile data: %d\n", (int)icc_profile.size);
  }

  if (flag & EXIF_FLAG) {
    WebPData exif;
    err = WebPMuxGetChunk(mux, "EXIF", &exif);
    RETURN_IF_ERROR("Failed to retrieve the EXIF metadata\n");
    printf("Size of the EXIF metadata: %d\n", (int)exif.size);
  }

  if (flag & XMP_FLAG) {
    WebPData xmp;
    err = WebPMuxGetChunk(mux, "XMP ", &xmp);
    RETURN_IF_ERROR("Failed to retrieve the XMP metadata\n");
    printf("Size of the XMP metadata: %d\n", (int)xmp.size);
  }

  if ((flag & ALPHA_FLAG) && !(flag & (ANIMATION_FLAG | FRAGMENTS_FLAG))) {
    WebPMuxFrameInfo image;
    err = WebPMuxGetFrame(mux, 1, &image);
    if (err == WEBP_MUX_OK) {
      printf("Size of the image (with alpha): %d\n", (int)image.bitstream.size);
    }
    WebPDataClear(&image.bitstream);
    RETURN_IF_ERROR("Failed to retrieve the image\n");
  }

  return WEBP_MUX_OK;
}
Пример #5
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	WebPMux *mux = NULL;
	WebPMuxFrameInfo webp_frame = { 0 };	// raw image
	WebPData color_profile;	// ICC raw data
	WebPData xmp_metadata;	// XMP raw data
	WebPData exif_metadata;	// EXIF raw data
	FIBITMAP *dib = NULL;
	WebPMuxError error_status;

	if(!handle) {
		return NULL;
	}

	try {
		// get the MUX object
		mux = (WebPMux*)data;
		if(!mux) {
			throw (1);
		}
		
		// gets the feature flags from the mux object
		uint32_t webp_flags = 0;
		error_status = WebPMuxGetFeatures(mux, &webp_flags);
		if(error_status != WEBP_MUX_OK) {
			throw (1);
		}

		// get image data
		error_status = WebPMuxGetFrame(mux, 1, &webp_frame);

		if(error_status == WEBP_MUX_OK) {
			// decode the data (can be limited to the header if flags uses FIF_LOAD_NOPIXELS)
			dib = DecodeImage(&webp_frame.bitstream, flags);
			if(!dib) {
				throw (1);
			}
			
			// get ICC profile
			if(webp_flags & ICCP_FLAG) {
				error_status = WebPMuxGetChunk(mux, "ICCP", &color_profile);
				if(error_status == WEBP_MUX_OK) {
					FreeImage_CreateICCProfile(dib, (void*)color_profile.bytes, (long)color_profile.size);
				}
			}

			// get XMP metadata
			if(webp_flags & XMP_FLAG) {
				error_status = WebPMuxGetChunk(mux, "XMP ", &xmp_metadata);
				if(error_status == WEBP_MUX_OK) {
					// create a tag
					FITAG *tag = FreeImage_CreateTag();
					if(tag) {
						FreeImage_SetTagKey(tag, g_TagLib_XMPFieldName);
						FreeImage_SetTagLength(tag, (DWORD)xmp_metadata.size);
						FreeImage_SetTagCount(tag, (DWORD)xmp_metadata.size);
						FreeImage_SetTagType(tag, FIDT_ASCII);
						FreeImage_SetTagValue(tag, xmp_metadata.bytes);
						
						// store the tag
						FreeImage_SetMetadata(FIMD_XMP, dib, FreeImage_GetTagKey(tag), tag);

						// destroy the tag
						FreeImage_DeleteTag(tag);
					}
				}
			}

			// get Exif metadata
			if(webp_flags & EXIF_FLAG) {
				error_status = WebPMuxGetChunk(mux, "EXIF", &exif_metadata);
				if(error_status == WEBP_MUX_OK) {
					// read the Exif raw data as a blob
					jpeg_read_exif_profile_raw(dib, exif_metadata.bytes, (unsigned)exif_metadata.size);
					// read and decode the Exif data
					jpeg_read_exif_profile(dib, exif_metadata.bytes, (unsigned)exif_metadata.size);
				}
			}
		}

		WebPDataClear(&webp_frame.bitstream);

		return dib;

	} catch(int) {
		WebPDataClear(&webp_frame.bitstream);
		return NULL;
	}
}
Пример #6
0
PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args)
{
    PyBytesObject *webp_string;
    uint8_t *webp;
    Py_ssize_t size;
    PyObject *ret, *bytes, *pymode, *icc_profile = Py_None, *exif = Py_None;
    WebPDecoderConfig config;
    VP8StatusCode vp8_status_code = VP8_STATUS_OK;
    char* mode = "RGB";

    if (!PyArg_ParseTuple(args, "S", &webp_string)) {
        Py_RETURN_NONE;
    }

    if (!WebPInitDecoderConfig(&config)) {
        Py_RETURN_NONE;
    }

    PyBytes_AsStringAndSize((PyObject *) webp_string, (char**)&webp, &size);

    vp8_status_code = WebPGetFeatures(webp, size, &config.input);
    if (vp8_status_code == VP8_STATUS_OK) {
        // If we don't set it, we don't get alpha.
        // Initialized to MODE_RGB
        if (config.input.has_alpha) {
            config.output.colorspace = MODE_RGBA;
            mode = "RGBA";
        }

#ifndef HAVE_WEBPMUX
        vp8_status_code = WebPDecode(webp, size, &config);
#else
       {
        int copy_data = 0;
        WebPData data = { webp, size };
        WebPMuxFrameInfo image;
        WebPData icc_profile_data = {0};
        WebPData exif_data = {0};

        WebPMux* mux = WebPMuxCreate(&data, copy_data);
        WebPMuxGetFrame(mux, 1, &image);
        webp = (uint8_t*)image.bitstream.bytes;
        size = image.bitstream.size;

        vp8_status_code = WebPDecode(webp, size, &config);

        WebPMuxGetChunk(mux, "ICCP", &icc_profile_data);
        if (icc_profile_data.size > 0) {
            icc_profile = PyBytes_FromStringAndSize((const char*)icc_profile_data.bytes, icc_profile_data.size);
        }

        WebPMuxGetChunk(mux, "EXIF", &exif_data);
        if (exif_data.size > 0) {
            exif = PyBytes_FromStringAndSize((const char*)exif_data.bytes, exif_data.size);
        }

        WebPMuxDelete(mux);
        }
#endif
    }

    if (vp8_status_code != VP8_STATUS_OK) {
        WebPFreeDecBuffer(&config.output);
        Py_RETURN_NONE;
    }

    if (config.output.colorspace < MODE_YUV) {
        bytes = PyBytes_FromStringAndSize((char *)config.output.u.RGBA.rgba,
                                          config.output.u.RGBA.size);
    } else {
        // Skipping YUV for now. Need Test Images.
        // UNDONE -- unclear if we'll ever get here if we set mode_rgb*
        bytes = PyBytes_FromStringAndSize((char *)config.output.u.YUVA.y,
                                          config.output.u.YUVA.y_size);
    }

#if PY_VERSION_HEX >= 0x03000000
    pymode = PyUnicode_FromString(mode);
#else
    pymode = PyString_FromString(mode);
#endif
    ret = Py_BuildValue("SiiSSS", bytes, config.output.width,
                        config.output.height, pymode, icc_profile, exif);
    WebPFreeDecBuffer(&config.output);
    return ret;
}
Пример #7
0
gboolean load_image(const gchar *filename,
                    gint32      *image_ID,
                    GError     **error)
{
    gboolean              status      = FALSE;
    gchar                *indata      = NULL;
    gsize                 indatalen;
    gint                  width;
    gint                  height;
    WebPMux              *mux         = NULL;
    WebPData              wp_data;
    uint32_t              flags;
    uint8_t              *outdata     = NULL;

#ifdef GIMP_2_9
    /* Initialize GEGL */
    gegl_init(NULL, NULL);
#endif

    do {

        /* Attempt to read the file contents from disk */
        if (g_file_get_contents(filename,
                                &indata,
                                &indatalen,
                                error) == FALSE) {
            break;
        }

        /* Validate WebP data, grabbing the width and height */
        if (!WebPGetInfo(indata, indatalen, &width, &height)) {
            break;
        }

        /* Create a WebPMux from the contents of the file */
        wp_data.bytes = (uint8_t*)indata;
        wp_data.size = indatalen;

        mux = WebPMuxCreate(&wp_data, 1);
        if (mux == NULL) {
            break;
        }

        /* Retrieve the features present */
        if (WebPMuxGetFeatures(mux, &flags) != WEBP_MUX_OK) {
            break;
        }

        /* TODO: decode the image in "chunks" or "tiles" */
        /* TODO: check if an alpha channel is present */

        /* Create the new image and associated layer */
        *image_ID = gimp_image_new(width, height, GIMP_RGB);

#ifdef WEBP_0_5
        if (flags & ANIMATION_FLAG) {
            int frames, i;

            /* Retrieve the number of frames */
            WebPMuxNumChunks(mux, WEBP_CHUNK_ANMF, &frames);

            /* Loop over each of the frames */
            for (i = 0; i < frames; ++i) {
                WebPMuxFrameInfo frame = {0};

                /* Retrieve the data for the frame */
                if (WebPMuxGetFrame(mux, i, &frame) != WEBP_MUX_OK) {
                    goto error;
                }

                /* Decode the frame */
                outdata = WebPDecodeRGBA(frame.bitstream.bytes,
                                         frame.bitstream.size,
                                         &width, &height);

                /* Free the compressed data */
                WebPDataClear(&frame.bitstream);

                if (!outdata) {
                    goto error;
                }

                /* Create a layer for the frame */
                char name[255];
                snprintf(name, 255, "Frame %d", (i + 1));

                if (create_layer(*image_ID,
                                 outdata,
                                 0,
                                 (gchar*)name,
                                 width, height,
                                 frame.x_offset,
                                 frame.y_offset) == FALSE) {
                    goto error;
                }
            }

            /* If all is well, jump *over* the error label - otherwise
               leave the loop and begin cleaning things up */

            goto success;

        error:
            break;

        success: ;

        } else {
#endif

            /* Attempt to decode the data as a WebP image */
            outdata = WebPDecodeRGBA(indata, indatalen, &width, &height);
            if (!outdata) {
                break;
            }

            /* Create a single layer */
            status = create_layer(*image_ID,
                                  outdata,
                                  0,
                                  "Background",
                                  width, height,
                                  0, 0);

#ifdef WEBP_0_5
        }

#ifdef GIMP_2_9
        /* Load a color profile if one was provided */
        if (flags & ICCP_FLAG) {
            WebPData          icc_profile;
            GimpColorProfile *profile;

            /* Load the ICC profile from the file */
            WebPMuxGetChunk(mux, "ICCP", &icc_profile);

            /* Have Gimp load the color profile */
            profile = gimp_color_profile_new_from_icc_profile(
                        icc_profile.bytes, icc_profile.size, NULL);
            if (profile) {
                gimp_image_set_color_profile(image_ID, profile);
                g_object_unref(profile);
            }
        }
#endif
#endif
        /* Set the filename for the image */
        gimp_image_set_filename(*image_ID, filename);

    } while(0);

    /* Delete the mux object */
    if (mux) {
        WebPMuxDelete(mux);
    }

    /* Free the data read from disk */
    if (indata) {
        g_free(indata);
    }

    return status;
}