mirror of
https://github.com/pocoproject/poco.git
synced 2024-12-21 05:03:36 +01:00
d75e68c027
windows build only
569 lines
16 KiB
C
569 lines
16 KiB
C
/*
|
|
* << Haru Free PDF Library 2.0.3 >> -- hpdf_image.c
|
|
*
|
|
* Copyright (c) 1999-2006 Takeshi Kanno <takeshi_kanno@est.hi-ho.ne.jp>
|
|
*
|
|
* Permission to use, copy, modify, distribute and sell this software
|
|
* and its documentation for any purpose is hereby granted without fee,
|
|
* provided that the above copyright notice appear in all copies and
|
|
* that both that copyright notice and this permission notice appear
|
|
* in supporting documentation.
|
|
* It is provided "as is" without express or implied warranty.
|
|
*
|
|
* 2006.08.12 modified.
|
|
*/
|
|
|
|
#include "hpdf_conf.h"
|
|
#include "hpdf_utils.h"
|
|
#include "hpdf.h"
|
|
|
|
static const char *COL_CMYK = "DeviceCMYK";
|
|
static const char *COL_RGB = "DeviceRGB";
|
|
static const char *COL_GRAY = "DeviceGray";
|
|
|
|
static HPDF_STATUS
|
|
LoadJpegHeader (HPDF_Image image,
|
|
HPDF_Stream stream);
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static HPDF_STATUS
|
|
LoadJpegHeader (HPDF_Image image,
|
|
HPDF_Stream stream)
|
|
{
|
|
HPDF_UINT16 tag;
|
|
HPDF_UINT16 height;
|
|
HPDF_UINT16 width;
|
|
HPDF_BYTE precision;
|
|
HPDF_BYTE num_components;
|
|
const char *color_space_name;
|
|
HPDF_UINT len;
|
|
HPDF_STATUS ret;
|
|
HPDF_Array array;
|
|
|
|
HPDF_PTRACE ((" HPDF_Image_LoadJpegHeader\n"));
|
|
|
|
len = 2;
|
|
if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&tag, &len) != HPDF_OK)
|
|
return HPDF_Error_GetCode (stream->error);
|
|
|
|
HPDF_UInt16Swap (&tag);
|
|
if (tag != 0xFFD8)
|
|
return HPDF_INVALID_JPEG_DATA;
|
|
|
|
/* find SOF record */
|
|
for (;;) {
|
|
HPDF_UINT16 size;
|
|
|
|
len = 2;
|
|
if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&tag, &len) != HPDF_OK)
|
|
return HPDF_Error_GetCode (stream->error);
|
|
|
|
HPDF_UInt16Swap (&tag);
|
|
|
|
len = 2;
|
|
if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&size, &len) != HPDF_OK)
|
|
return HPDF_Error_GetCode (stream->error);
|
|
|
|
HPDF_UInt16Swap (&size);
|
|
|
|
HPDF_PTRACE (("tag=%04X size=%u\n", tag, size));
|
|
|
|
if (tag == 0xFFC0 || tag == 0xFFC1 ||
|
|
tag == 0xFFC2 || tag == 0xFFC9) {
|
|
|
|
len = 1;
|
|
if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&precision, &len) !=
|
|
HPDF_OK)
|
|
return HPDF_Error_GetCode (stream->error);
|
|
|
|
len = 2;
|
|
if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&height, &len) !=
|
|
HPDF_OK)
|
|
return HPDF_Error_GetCode (stream->error);
|
|
|
|
HPDF_UInt16Swap (&height);
|
|
|
|
len = 2;
|
|
if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&width, &len) != HPDF_OK)
|
|
return HPDF_Error_GetCode (stream->error);
|
|
|
|
HPDF_UInt16Swap (&width);
|
|
|
|
len = 1;
|
|
if (HPDF_Stream_Read (stream, (HPDF_BYTE *)&num_components, &len) !=
|
|
HPDF_OK)
|
|
return HPDF_Error_GetCode (stream->error);
|
|
|
|
break;
|
|
} else if ((tag | 0x00FF) != 0xFFFF)
|
|
/* lost marker */
|
|
return HPDF_SetError (image->error, HPDF_UNSUPPORTED_JPEG_FORMAT,
|
|
0);
|
|
|
|
if (HPDF_Stream_Seek (stream, size - 2, HPDF_SEEK_CUR) != HPDF_OK)
|
|
return HPDF_Error_GetCode (stream->error);
|
|
}
|
|
|
|
if (HPDF_Dict_AddNumber (image, "Height", height) != HPDF_OK)
|
|
return HPDF_Error_GetCode (stream->error);
|
|
|
|
if (HPDF_Dict_AddNumber (image, "Width", width) != HPDF_OK)
|
|
return HPDF_Error_GetCode (stream->error);
|
|
|
|
/* classification of RGB and CMYK is less than perfect
|
|
* YCbCr and YCCK are classified into RGB or CMYK.
|
|
*
|
|
* It is necessary to read APP14 data to distinguish colorspace perfectly.
|
|
|
|
*/
|
|
switch (num_components) {
|
|
case 1:
|
|
color_space_name = COL_GRAY;
|
|
break;
|
|
case 3:
|
|
color_space_name = COL_RGB;
|
|
break;
|
|
case 4:
|
|
array = HPDF_Array_New (image->mmgr);
|
|
if (!array)
|
|
return HPDF_Error_GetCode (stream->error);
|
|
|
|
ret = HPDF_Dict_Add (image, "Decode", array);
|
|
if (ret != HPDF_OK)
|
|
return HPDF_Error_GetCode (stream->error);
|
|
|
|
ret += HPDF_Array_Add (array, HPDF_Number_New (image->mmgr, 1));
|
|
ret += HPDF_Array_Add (array, HPDF_Number_New (image->mmgr, 0));
|
|
ret += HPDF_Array_Add (array, HPDF_Number_New (image->mmgr, 1));
|
|
ret += HPDF_Array_Add (array, HPDF_Number_New (image->mmgr, 0));
|
|
ret += HPDF_Array_Add (array, HPDF_Number_New (image->mmgr, 1));
|
|
ret += HPDF_Array_Add (array, HPDF_Number_New (image->mmgr, 0));
|
|
ret += HPDF_Array_Add (array, HPDF_Number_New (image->mmgr, 1));
|
|
ret += HPDF_Array_Add (array, HPDF_Number_New (image->mmgr, 0));
|
|
|
|
if (ret != HPDF_OK)
|
|
return HPDF_Error_GetCode (stream->error);
|
|
|
|
color_space_name = COL_CMYK;
|
|
|
|
break;
|
|
default:
|
|
return HPDF_SetError (image->error, HPDF_UNSUPPORTED_JPEG_FORMAT,
|
|
0);
|
|
}
|
|
|
|
if (HPDF_Dict_Add (image, "ColorSpace",
|
|
HPDF_Name_New (image->mmgr, color_space_name)) != HPDF_OK)
|
|
return HPDF_Error_GetCode (stream->error);
|
|
|
|
if (HPDF_Dict_Add (image, "BitsPerComponent",
|
|
HPDF_Number_New (image->mmgr, precision)) != HPDF_OK)
|
|
return HPDF_Error_GetCode (stream->error);
|
|
|
|
return HPDF_OK;
|
|
}
|
|
|
|
HPDF_Image
|
|
HPDF_Image_LoadJpegImage (HPDF_MMgr mmgr,
|
|
HPDF_Stream jpeg_data,
|
|
HPDF_Xref xref)
|
|
{
|
|
HPDF_Dict image;
|
|
HPDF_STATUS ret = HPDF_OK;
|
|
|
|
HPDF_PTRACE ((" HPDF_Image_LoadJpegImage\n"));
|
|
|
|
image = HPDF_DictStream_New (mmgr, xref);
|
|
if (!image)
|
|
return NULL;
|
|
|
|
image->header.obj_class |= HPDF_OSUBCLASS_XOBJECT;
|
|
|
|
/* add requiered elements */
|
|
image->filter = HPDF_STREAM_FILTER_DCT_DECODE;
|
|
ret += HPDF_Dict_AddName (image, "Type", "XObject");
|
|
ret += HPDF_Dict_AddName (image, "Subtype", "Image");
|
|
if (ret != HPDF_OK)
|
|
return NULL;
|
|
|
|
if (LoadJpegHeader (image, jpeg_data) != HPDF_OK)
|
|
return NULL;
|
|
|
|
if (HPDF_Stream_Seek (jpeg_data, 0, HPDF_SEEK_SET) != HPDF_OK)
|
|
return NULL;
|
|
|
|
for (;;) {
|
|
HPDF_BYTE buf[HPDF_STREAM_BUF_SIZ];
|
|
HPDF_UINT len = HPDF_STREAM_BUF_SIZ;
|
|
HPDF_STATUS ret = HPDF_Stream_Read (jpeg_data, buf,
|
|
&len);
|
|
|
|
if (ret != HPDF_OK) {
|
|
if (ret == HPDF_STREAM_EOF) {
|
|
if (len > 0) {
|
|
ret = HPDF_Stream_Write (image->stream, buf, len);
|
|
if (ret != HPDF_OK)
|
|
return NULL;
|
|
}
|
|
break;
|
|
} else
|
|
return NULL;
|
|
}
|
|
|
|
if (HPDF_Stream_Write (image->stream, buf, len) != HPDF_OK)
|
|
return NULL;
|
|
}
|
|
|
|
return image;
|
|
}
|
|
|
|
|
|
HPDF_Image
|
|
HPDF_Image_LoadRawImage (HPDF_MMgr mmgr,
|
|
HPDF_Stream raw_data,
|
|
HPDF_Xref xref,
|
|
HPDF_UINT width,
|
|
HPDF_UINT height,
|
|
HPDF_ColorSpace color_space)
|
|
{
|
|
HPDF_Dict image;
|
|
HPDF_STATUS ret = HPDF_OK;
|
|
HPDF_UINT size;
|
|
|
|
HPDF_PTRACE ((" HPDF_Image_LoadRawImage\n"));
|
|
|
|
if (color_space != HPDF_CS_DEVICE_GRAY &&
|
|
color_space != HPDF_CS_DEVICE_RGB &&
|
|
color_space != HPDF_CS_DEVICE_CMYK) {
|
|
HPDF_SetError (mmgr->error, HPDF_INVALID_COLOR_SPACE, 0);
|
|
return NULL;
|
|
}
|
|
|
|
image = HPDF_DictStream_New (mmgr, xref);
|
|
if (!image)
|
|
return NULL;
|
|
|
|
image->header.obj_class |= HPDF_OSUBCLASS_XOBJECT;
|
|
ret += HPDF_Dict_AddName (image, "Type", "XObject");
|
|
ret += HPDF_Dict_AddName (image, "Subtype", "Image");
|
|
if (ret != HPDF_OK)
|
|
return NULL;
|
|
|
|
if (color_space == HPDF_CS_DEVICE_GRAY) {
|
|
size = width * height;
|
|
ret = HPDF_Dict_AddName (image, "ColorSpace", COL_GRAY);
|
|
} else if (color_space == HPDF_CS_DEVICE_CMYK) {
|
|
size = width * height * 4;
|
|
ret = HPDF_Dict_AddName (image, "ColorSpace", COL_CMYK);
|
|
} else {
|
|
size = width * height * 3;
|
|
ret = HPDF_Dict_AddName (image, "ColorSpace", COL_RGB);
|
|
}
|
|
|
|
if (ret != HPDF_OK)
|
|
return NULL;
|
|
|
|
if (HPDF_Dict_AddNumber (image, "Width", width) != HPDF_OK)
|
|
return NULL;
|
|
|
|
if (HPDF_Dict_AddNumber (image, "Height", height) != HPDF_OK)
|
|
return NULL;
|
|
|
|
if (HPDF_Dict_AddNumber (image, "BitsPerComponent", 8) != HPDF_OK)
|
|
return NULL;
|
|
|
|
if (HPDF_Stream_WriteToStream (raw_data, image->stream, 0, NULL) != HPDF_OK)
|
|
return NULL;
|
|
|
|
if (image->stream->size != size) {
|
|
HPDF_SetError (image->error, HPDF_INVALID_IMAGE, 0);
|
|
return NULL;
|
|
}
|
|
|
|
return image;
|
|
}
|
|
|
|
|
|
HPDF_Image
|
|
HPDF_Image_LoadRawImageFromMem (HPDF_MMgr mmgr,
|
|
const HPDF_BYTE *buf,
|
|
HPDF_Xref xref,
|
|
HPDF_UINT width,
|
|
HPDF_UINT height,
|
|
HPDF_ColorSpace color_space,
|
|
HPDF_UINT bits_per_component)
|
|
{
|
|
HPDF_Dict image;
|
|
HPDF_STATUS ret = HPDF_OK;
|
|
HPDF_UINT size;
|
|
|
|
HPDF_PTRACE ((" HPDF_Image_LoadRawImageFromMem\n"));
|
|
|
|
if (color_space != HPDF_CS_DEVICE_GRAY &&
|
|
color_space != HPDF_CS_DEVICE_RGB) {
|
|
HPDF_SetError (mmgr->error, HPDF_INVALID_COLOR_SPACE, 0);
|
|
return NULL;
|
|
}
|
|
|
|
if (bits_per_component != 1 && bits_per_component != 2 &&
|
|
bits_per_component != 4 && bits_per_component != 8) {
|
|
HPDF_SetError (mmgr->error, HPDF_INVALID_IMAGE, 0);
|
|
return NULL;
|
|
}
|
|
|
|
image = HPDF_DictStream_New (mmgr, xref);
|
|
if (!image)
|
|
return NULL;
|
|
|
|
image->header.obj_class |= HPDF_OSUBCLASS_XOBJECT;
|
|
ret += HPDF_Dict_AddName (image, "Type", "XObject");
|
|
ret += HPDF_Dict_AddName (image, "Subtype", "Image");
|
|
if (ret != HPDF_OK)
|
|
return NULL;
|
|
|
|
if (color_space == HPDF_CS_DEVICE_GRAY) {
|
|
size = (HPDF_DOUBLE)width * height / (8 / bits_per_component) + 0.876;
|
|
ret = HPDF_Dict_AddName (image, "ColorSpace", COL_GRAY);
|
|
} else {
|
|
size = (HPDF_DOUBLE)width * height / (8 / bits_per_component) + 0.876;
|
|
size *= 3;
|
|
ret = HPDF_Dict_AddName (image, "ColorSpace", COL_RGB);
|
|
}
|
|
|
|
if (ret != HPDF_OK)
|
|
return NULL;
|
|
|
|
if (HPDF_Dict_AddNumber (image, "Width", width) != HPDF_OK)
|
|
return NULL;
|
|
|
|
if (HPDF_Dict_AddNumber (image, "Height", height) != HPDF_OK)
|
|
return NULL;
|
|
|
|
if (HPDF_Dict_AddNumber (image, "BitsPerComponent", bits_per_component)
|
|
!= HPDF_OK)
|
|
return NULL;
|
|
|
|
if (HPDF_Stream_Write (image->stream, buf, size) != HPDF_OK)
|
|
return NULL;
|
|
|
|
return image;
|
|
}
|
|
|
|
|
|
HPDF_BOOL
|
|
HPDF_Image_Validate (HPDF_Image image)
|
|
{
|
|
HPDF_Name subtype;
|
|
|
|
HPDF_PTRACE ((" HPDF_Image_Validate\n"));
|
|
|
|
if (!image)
|
|
return HPDF_FALSE;
|
|
|
|
if (image->header.obj_class != (HPDF_OSUBCLASS_XOBJECT |
|
|
HPDF_OCLASS_DICT)) {
|
|
HPDF_RaiseError (image->error, HPDF_INVALID_IMAGE, 0);
|
|
return HPDF_FALSE;
|
|
}
|
|
|
|
subtype = HPDF_Dict_GetItem (image, "Subtype", HPDF_OCLASS_NAME);
|
|
if (!subtype || HPDF_StrCmp (subtype->value, "Image") != 0) {
|
|
HPDF_RaiseError (image->error, HPDF_INVALID_IMAGE, 0);
|
|
return HPDF_FALSE;
|
|
}
|
|
|
|
return HPDF_TRUE;
|
|
}
|
|
|
|
|
|
HPDF_EXPORT(HPDF_Point)
|
|
HPDF_Image_GetSize (HPDF_Image image)
|
|
{
|
|
HPDF_Number width;
|
|
HPDF_Number height;
|
|
HPDF_Point ret = {0, 0};
|
|
|
|
HPDF_PTRACE ((" HPDF_Image_GetSize\n"));
|
|
|
|
if (!HPDF_Image_Validate (image))
|
|
return ret;
|
|
|
|
width = HPDF_Dict_GetItem (image, "Width", HPDF_OCLASS_NUMBER);
|
|
height = HPDF_Dict_GetItem (image, "Height", HPDF_OCLASS_NUMBER);
|
|
|
|
if (width && height) {
|
|
ret.x = width->value;
|
|
ret.y = height->value;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
HPDF_EXPORT(HPDF_STATUS)
|
|
HPDF_Image_GetSize2 (HPDF_Image image, HPDF_Point *size)
|
|
{
|
|
HPDF_Number width;
|
|
HPDF_Number height;
|
|
size->x = 0;
|
|
size->y = 0;
|
|
|
|
HPDF_PTRACE ((" HPDF_Image_GetSize\n"));
|
|
|
|
if (!HPDF_Image_Validate (image))
|
|
return HPDF_INVALID_IMAGE;
|
|
|
|
width = HPDF_Dict_GetItem (image, "Width", HPDF_OCLASS_NUMBER);
|
|
height = HPDF_Dict_GetItem (image, "Height", HPDF_OCLASS_NUMBER);
|
|
|
|
if (width && height) {
|
|
size->x = width->value;
|
|
size->y = height->value;
|
|
}
|
|
|
|
return HPDF_OK;
|
|
}
|
|
|
|
HPDF_EXPORT(HPDF_UINT)
|
|
HPDF_Image_GetBitsPerComponent (HPDF_Image image)
|
|
{
|
|
HPDF_Number n;
|
|
|
|
HPDF_PTRACE ((" HPDF_Image_GetBitsPerComponent\n"));
|
|
|
|
if (!HPDF_Image_Validate (image))
|
|
return 0;
|
|
|
|
n = HPDF_Dict_GetItem (image, "BitsPerComponent", HPDF_OCLASS_NUMBER);
|
|
|
|
if (!n)
|
|
return 0;
|
|
|
|
return n->value;
|
|
}
|
|
|
|
HPDF_EXPORT(const char*)
|
|
HPDF_Image_GetColorSpace (HPDF_Image image)
|
|
{
|
|
HPDF_Name n;
|
|
|
|
HPDF_PTRACE ((" HPDF_Image_GetColorSpace\n"));
|
|
|
|
n = HPDF_Dict_GetItem (image, "ColorSpace", HPDF_OCLASS_NAME);
|
|
|
|
if (!n) {
|
|
HPDF_CheckError (image->error);
|
|
return NULL;
|
|
}
|
|
|
|
return n->value;
|
|
}
|
|
|
|
HPDF_EXPORT(HPDF_UINT)
|
|
HPDF_Image_GetWidth (HPDF_Image image)
|
|
{
|
|
return HPDF_Image_GetSize (image).x;
|
|
}
|
|
|
|
HPDF_EXPORT(HPDF_UINT)
|
|
HPDF_Image_GetHeight (HPDF_Image image)
|
|
{
|
|
return HPDF_Image_GetSize (image).y;
|
|
}
|
|
|
|
HPDF_STATUS
|
|
HPDF_Image_SetMask (HPDF_Image image,
|
|
HPDF_BOOL mask)
|
|
{
|
|
HPDF_Boolean image_mask;
|
|
|
|
if (!HPDF_Image_Validate (image))
|
|
return HPDF_INVALID_IMAGE;
|
|
|
|
if (mask && HPDF_Image_GetBitsPerComponent (image) != 1)
|
|
return HPDF_SetError (image->error, HPDF_INVALID_BIT_PER_COMPONENT,
|
|
0);
|
|
|
|
image_mask = HPDF_Dict_GetItem (image, "ImageMask", HPDF_OCLASS_BOOLEAN);
|
|
if (!image_mask) {
|
|
HPDF_STATUS ret;
|
|
image_mask = HPDF_Boolean_New (image->mmgr, HPDF_FALSE);
|
|
|
|
if ((ret = HPDF_Dict_Add (image, "ImageMask", image_mask)) != HPDF_OK)
|
|
return ret;
|
|
}
|
|
|
|
image_mask->value = mask;
|
|
return HPDF_OK;
|
|
}
|
|
|
|
|
|
HPDF_EXPORT(HPDF_STATUS)
|
|
HPDF_Image_SetMaskImage (HPDF_Image image,
|
|
HPDF_Image mask_image)
|
|
{
|
|
if (!HPDF_Image_Validate (image))
|
|
return HPDF_INVALID_IMAGE;
|
|
|
|
if (!HPDF_Image_Validate (mask_image))
|
|
return HPDF_INVALID_IMAGE;
|
|
|
|
if (HPDF_Image_SetMask (mask_image, HPDF_TRUE) != HPDF_OK)
|
|
return HPDF_CheckError (image->error);
|
|
|
|
return HPDF_Dict_Add (image, "Mask", mask_image);
|
|
}
|
|
|
|
|
|
HPDF_EXPORT(HPDF_STATUS)
|
|
HPDF_Image_SetColorMask (HPDF_Image image,
|
|
HPDF_UINT rmin,
|
|
HPDF_UINT rmax,
|
|
HPDF_UINT gmin,
|
|
HPDF_UINT gmax,
|
|
HPDF_UINT bmin,
|
|
HPDF_UINT bmax)
|
|
{
|
|
HPDF_Array array;
|
|
const char *name;
|
|
HPDF_STATUS ret = HPDF_OK;
|
|
|
|
if (!HPDF_Image_Validate (image))
|
|
return HPDF_INVALID_IMAGE;
|
|
|
|
if (HPDF_Dict_GetItem (image, "ImageMask", HPDF_OCLASS_BOOLEAN))
|
|
return HPDF_RaiseError (image->error, HPDF_INVALID_OPERATION, 0);
|
|
|
|
if (HPDF_Image_GetBitsPerComponent (image) != 8)
|
|
return HPDF_RaiseError (image->error, HPDF_INVALID_BIT_PER_COMPONENT,
|
|
0);
|
|
|
|
name = HPDF_Image_GetColorSpace (image);
|
|
if (!name || HPDF_StrCmp (COL_RGB, name) != 0)
|
|
return HPDF_RaiseError (image->error, HPDF_INVALID_COLOR_SPACE, 0);
|
|
|
|
/* Each integer must be in the range 0 to 2^BitsPerComponent - 1 */
|
|
if (rmax > 255 || gmax > 255 || bmax > 255)
|
|
return HPDF_RaiseError (image->error, HPDF_INVALID_PARAMETER, 0);
|
|
|
|
array = HPDF_Array_New (image->mmgr);
|
|
if (!array)
|
|
return HPDF_CheckError (image->error);
|
|
|
|
ret += HPDF_Dict_Add (image, "Mask", array);
|
|
ret += HPDF_Array_AddNumber (array, rmin);
|
|
ret += HPDF_Array_AddNumber (array, rmax);
|
|
ret += HPDF_Array_AddNumber (array, gmin);
|
|
ret += HPDF_Array_AddNumber (array, gmax);
|
|
ret += HPDF_Array_AddNumber (array, bmin);
|
|
ret += HPDF_Array_AddNumber (array, bmax);
|
|
|
|
if (ret != HPDF_OK)
|
|
return HPDF_CheckError (image->error);
|
|
|
|
return HPDF_OK;
|
|
}
|
|
|
|
|