상세 컨텐츠

본문 제목

LCMS2 #6 - jpgicc.c 파일 분석

멀티미디어/이미지(Image)

by cepiloth 2020. 1. 11. 12:55

본문

728x90
반응형

jpgicc.c

해당 파일은 lcms2 에서 JPEG 내부의 MARKER 정보중 Color Profile 을 사용 하여서 만든 이미지면, 해당 마커에 컬러 프로파일러와 LIBJPEG 에서 추출한 색상 데이터를 기반으로 변환 해주는 역할을 한다. 

LCMS2 사용하여 JPEG 내부에 있는 컬러 프로파일러 정보를 확인하고 Color Transform 하는 파일은 jpgicc.c 파일이다.

 

Main Function

Main 함수는 아래와 같이 단순하다. 앱을 초기화하고 명령 인수에서 전달받은 파일명으로 컬러 프로파일을 사용하는 이미지를 RGB 형식으로 변환하여 저장한다.

int main(int argc, char* argv[])
{
    InitUtils("jpgicc"); // App 초기화 ErrorHanlder 등록

    HandleSwitches(argc, argv);

    // 명령인수 관련 에러처리
    if ((argc - xoptind) != 2) {
        Help(0);
    }

    // import, export 될 대상 파일의 경로이다 아래 함수에서는 파일로 로딩하는 역할을 한다.
    OpenInput(argv[xoptind]);
    OpenOutput(argv[xoptind+1]);

    // 실제 Color Profile 을 적용하는 코드
    TransformImage(cInpProf, cOutProf);

    // -v 옵션으로 실행시 진행 상황이나 추가 정보를 출력하는 역할을 한다.
    if (Verbose) { fprintf(stdout, "\n"); fflush(stdout); }

    Done();

    return 0;
}

 

OpenInput Method

LIBJPEG 내에서 사용하는 ErrorHandler를 등록 및 초기화 함수이다. JPEG 이미지의 HEADER의 정보를 읽고 나면 마커에 따라서 jpeg_color_space(실제 색상), out_color_space(출력 색상)을 알 수 있다.

static cmsBool OpenInput(const char* FileName)
{
    int m;

    lIsITUFax = FALSE;
    InFile  = fopen(FileName, "rb");
    if (InFile == NULL) {
        FatalError("Cannot open '%s'", FileName);
    }

    // Now we can initialize the JPEG decompression object.
    Decompressor.err                 = jpeg_std_error(&ErrorHandler.pub);
    ErrorHandler.pub.error_exit      = my_error_exit;
    ErrorHandler.pub.output_message  = my_error_exit;

    jpeg_create_decompress(&Decompressor);
    jpeg_stdio_src(&Decompressor, InFile);

    for (m = 0; m < 16; m++)
        jpeg_save_markers(&Decompressor, JPEG_APP0 + m, 0xFFFF);

    // setup_read_icc_profile(&Decompressor);

    fseek(InFile, 0, SEEK_SET);
    jpeg_read_header(&Decompressor, TRUE);

    return TRUE;
}

 

JPEG APP Marker

종류는 아래와 같다.  Marker에 따라서 ICC Profile를 사용 유무를 결정하기 때문에 아래 정보가 중요하다.

APP0 - JFIF R/W/C JPEG File Interchange Format
APP0 - JFXX R Extended JFIF
APP0 - CIFF R/W Camera Image File Format (used by some Canon models)
APP0 - AVI1 R JPEG AVI information
APP0 - Ocad R Photobucket Ocad segment
APP1 - EXIF R/W/C Exchangeable Image File Format (multi-segment)
APP1 - XMP R/W/C Extensible Metadata Platform (multi-segment)
APP1 - QVCI R Casio QV-7000SX QVCI information
APP1 - FLIR R FLIR thermal imaging data (multi-segment)
APP1 - RawThermalImage R Thermal image from Parrot Bebop-Pro Thermal drone
APP2 - ICC R/W/C International Color Consortium (multi-segment)
APP2 - FPXR R FlashPix Ready (multi-segment)
APP2 - MPF R Multi-Picture Format
APP2 - PreviewImage R Samsung/GE APP2 preview image (multi-segment)
APP3 - Kodak Meta R/W Kodak Meta information (EXIF-like)
APP3 - Stim R Stereo Still Image format
APP3 - PreviewImage R Samsung/HP preview image (multi-segment)
APP4 - Scalado R (presumably written by Scalado mobile software)
APP4 - FPXR R FlashPix Ready in non-standard location (multi-segment)
APP4 - PreviewImage R (continued from APP3)
APP5 - Ricoh RMETA R Ricoh custom fields
APP5 - Samsung UniqueID R Samsung Unique ID
APP5 - PreviewImage R (continued from APP4)
APP6 - EPPIM R Toshiba PrintIM
APP6 - NITF R National Imagery Transmission Format
APP6 - HP TDHD R Hewlett-Packard Photosmart R837 TDHD information
APP6 - GoPro R GoPro Metadata Format (GPMF) information
APP7 - Pentax R Pentax APP7 maker notes
APP7 - Qualcomm R Qualcomm Camera Attributes
APP7 - Huawei R Huawei APP7 maker notes (extract with Unknown option)
APP8 - SPIFF R Still Picture Interchange File Format
APP9 - Media Jukebox R Media Jukebox XML information
APP10 - Comment R PhotoStudio Unicode Comment
APP11 - JPEG-HDR R JPEG-HDR compressed ratio image
APP12 - Picture Info R ASCII-based Picture Information
APP12 - Ducky R/W/C Photoshop "Save for Web"
APP13 - Photoshop IRB R/W/C Image Resource Block (multi-segment, includes IPTC)
APP13 - Adobe CM R Adobe Color Management
APP14 - Adobe R/W/C Adobe DCT filter
APP15 - GraphicConverter R GraphicConverter quality
COM R/W/C JPEG Comment (multi-segment)
DQT R (used to calculate the Extra:JPEGDigest tag value)
SOF R JPEG Start Of Frame

 

OpenOutput Method

출력용 jpeg 이미지를 설정하는 메서드이다. 컬러 색상 정보를 설정하고 compress 파라미터를 초기화하는 역할을 하며 해당 함수에서는 아직 초기화 상태이기 때문에 UNKNOWN 데이터를 채워져 있다.

static cmsBool OpenOutput(const char* FileName)
{

    OutFile = fopen(FileName, "wb");
    if (OutFile == NULL) {
        FatalError("Cannot create '%s'", FileName);

    }

    Compressor.err                   = jpeg_std_error(&ErrorHandler.pub);
    ErrorHandler.pub.error_exit      = my_error_exit;
    ErrorHandler.pub.output_message  = my_error_exit;

    Compressor.input_components = Compressor.num_components = 4;

    jpeg_create_compress(&Compressor);
    jpeg_stdio_dest(&Compressor, OutFile);
    return TRUE;
}

 

TransformImage Method

실제 색상 프로파일을 이용하여 로딩하는 함수이다. 코드의 양이 길어서 LCMS2에서 제공하는 함수들을 하나하나 확인하면서 다음 글에 포스팅하도록 하겠다.

static int TransformImage(char *cDefInpProf, char *cOutputProf)
{
       cmsHPROFILE hIn, hOut, hProof;
       cmsHTRANSFORM xform;
       cmsUInt32Number wInput, wOutput;
       int OutputColorSpace;
       cmsUInt32Number dwFlags = 0;
       cmsUInt32Number EmbedLen;
       cmsUInt8Number* EmbedBuffer;


       cmsSetAdaptationState(ObserverAdaptationState);

       if (BlackPointCompensation) {

            dwFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
       }


       switch (PrecalcMode) {

       case 0: dwFlags |= cmsFLAGS_NOOPTIMIZE; break;
       case 2: dwFlags |= cmsFLAGS_HIGHRESPRECALC; break;
       case 3: dwFlags |= cmsFLAGS_LOWRESPRECALC; break;
       default:;
       }


       if (GamutCheck) {
            dwFlags |= cmsFLAGS_GAMUTCHECK;
            cmsSetAlarmCodes(Alarm);
       }

       // Take input color space
       wInput = GetInputPixelType();

        if (lIsDeviceLink) {

            hIn = cmsOpenProfileFromFile(cDefInpProf, "r");
            hOut = NULL;
            hProof = NULL;
       }
        else {

        if (!IgnoreEmbedded && read_icc_profile(&Decompressor, &EmbedBuffer, &EmbedLen))
        {
              hIn = cmsOpenProfileFromMem(EmbedBuffer, EmbedLen);

               if (Verbose) {

                  fprintf(stdout, " (Embedded profile found)\n");
                  PrintProfileInformation(hIn);
                  fflush(stdout);
              }

               if (hIn != NULL && SaveEmbedded != NULL)
                          SaveMemoryBlock(EmbedBuffer, EmbedLen, SaveEmbedded);

              free(EmbedBuffer);
        }
        else
        {
            // Default for ITU/Fax
            if (cDefInpProf == NULL && T_COLORSPACE(wInput) == PT_Lab)
                cDefInpProf = "*Lab";

            if (cDefInpProf != NULL && cmsstrcasecmp(cDefInpProf, "*lab") == 0)
                hIn = CreateITU2PCS_ICC();
            else
                hIn = OpenStockProfile(0, cDefInpProf);
       }

        if (cOutputProf != NULL && cmsstrcasecmp(cOutputProf, "*lab") == 0)
            hOut = CreatePCS2ITU_ICC();
        else
        hOut = OpenStockProfile(0, cOutputProf);

       hProof = NULL;
       if (cProofing != NULL) {

           hProof = OpenStockProfile(0, cProofing);
           if (hProof == NULL) {
            FatalError("Proofing profile couldn't be read.");
           }
           dwFlags |= cmsFLAGS_SOFTPROOFING;
          }
       }

        if (!hIn)
            FatalError("Input profile couldn't be read.");
        if (!lIsDeviceLink && !hOut)
            FatalError("Output profile couldn't be read.");

       // Assure both, input profile and input JPEG are on same colorspace
       if (cmsGetColorSpace(hIn) != _cmsICCcolorSpace(T_COLORSPACE(wInput)))
              FatalError("Input profile is not operating in proper color space");


       // Output colorspace is given by output profile

        if (lIsDeviceLink) {
            OutputColorSpace = GetDevicelinkColorSpace(hIn);
        }
        else {
            OutputColorSpace = GetProfileColorSpace(hOut);
        }

       jpeg_copy_critical_parameters(&Decompressor, &Compressor);

       WriteOutputFields(OutputColorSpace);

       wOutput      = ComputeOutputFormatDescriptor(wInput, OutputColorSpace);


       xform = cmsCreateProofingTransform(hIn, wInput,
                                          hOut, wOutput,
                                          hProof, Intent,
                                          ProofingIntent, dwFlags);
       if (xform == NULL)
                 FatalError("Cannot transform by using the profiles");

       DoTransform(xform, OutputColorSpace);


       jcopy_markers_execute(&Decompressor, &Compressor);

       cmsDeleteTransform(xform);
       cmsCloseProfile(hIn);
       cmsCloseProfile(hOut);
       if (hProof) cmsCloseProfile(hProof);

       return 1;
}

 

DoTransform Method

TransformImage 메소드에서 최종적으로 호출하는 메서드로 색상프로파일러를 읽어 OUTPUT 파일을 생성 할때 COLOR PROFILE 의 생상 정보로 RGB 형식으로 변환해 주는 소스이다. cmsDoTransform 메소드를 통하여 COLOR_PROFILE 의 적용된 픽셀의 SCANELINE 단위로 읽으면서 RGB 로 변환하고 jpeg_write_scanlines 메소드로 COLOR_PROFILE을 사용하지 않은 RGB 형태의 JPEG 이미지를 만들어 준다.

static int DoTransform(cmsHTRANSFORM hXForm, int OutputColorSpace)
{
	JSAMPROW ScanLineIn;
	JSAMPROW ScanLineOut;

	//Preserve resolution values from the original
	// (Thanks to Robert Bergs for finding out this bug)
	Compressor.density_unit = Decompressor.density_unit;
	Compressor.X_density    = Decompressor.X_density;
	Compressor.Y_density    = Decompressor.Y_density;

	//  Compressor.write_JFIF_header = 1;

	jpeg_start_decompress(&Decompressor);
	jpeg_start_compress(&Compressor, TRUE);

	if (OutputColorSpace == PT_Lab)
		SetITUFax(&Compressor);

	// Embed the profile if needed
	if (EmbedProfile && cOutProf)
	   DoEmbedProfile(cOutProf);

	ScanLineIn  = (JSAMPROW) malloc(Decompressor.output_width * Decompressor.num_components);
	ScanLineOut = (JSAMPROW) malloc(Compressor.image_width * Compressor.num_components);

	while (Decompressor.output_scanline < Decompressor.output_height) {
		jpeg_read_scanlines(&Decompressor, &ScanLineIn, 1);
		cmsDoTransform(hXForm, ScanLineIn, ScanLineOut, Decompressor.output_width);
		jpeg_write_scanlines(&Compressor, &ScanLineOut, 1);
	}

	free(ScanLineIn);
	free(ScanLineOut);

	jpeg_finish_decompress(&Decompressor);
	jpeg_finish_compress(&Compressor);

	return TRUE;
}
728x90
반응형

'멀티미디어 > 이미지(Image)' 카테고리의 다른 글

LCMS2 #8 - 색상 변경 예제  (0) 2020.01.21
LCMS2 #7 - jpgicc.c  (0) 2020.01.20
LCMS2 #5 - Github Contributor 승인  (0) 2020.01.09
LCMS2 #4 - Pull Request Github  (1) 2020.01.09
LCMS2 #3 - Fork Github VS2019 환경 설정(2)  (0) 2020.01.08

관련글 더보기

댓글 영역