How to remove transparency from a TIF and replace with white background

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
Roman80
Posts: 25
Joined: 2017-08-03T21:26:15-07:00
Authentication code: 1151

How to remove transparency from a TIF and replace with white background

Post by Roman80 »

Hello,

i've attached an example file. How can I remove the transparency from a TIF file with ImageMagick C-API?
I already tried to debug with VisualMagick's tool "UTIL_convert" (VisualDynamicMT) with the command line parameter "[TIF_File] [JPG_File]" and this works, but I can't find out why.

Please could someone help?

Best Regards

https://www.dropbox.com/s/6b9khjnh74iauph/test.tif?dl=0
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: How to remove transparency from a TIF and replace with white background

Post by snibgo »

There are two APIs for C. Which one do you use?

What version of IM do you use?
snibgo's IM pages: im.snibgo.com
Roman80
Posts: 25
Joined: 2017-08-03T21:26:15-07:00
Authentication code: 1151

Re: How to remove transparency from a TIF and replace with white background

Post by Roman80 »

Hello,
snibgo wrote: 2018-05-14T07:40:09-07:00 What version of IM do you use?
I use ImageMagick 7.0.7-22 Q16 x64 on Windows 10
snibgo wrote: 2018-05-14T07:40:09-07:00 There are two APIs for C. Which one do you use?
I don't know what you mean exactly, I use MagickCore and MagickWand. Hope this is what you expected.

Regards
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: How to remove transparency from a TIF and replace with white background

Post by snibgo »

The usual way of removing transparency is by flattening against a colour:

Code: Select all

magick in.png -background blue -layers flatten out.png
The MagickCore functions for this are:

Code: Select all

QueryColorCompliance ("blue", AllCompliance, &inImg->background_color, exception);

Image * outImg = MergeImageLayers(inImg, FlattenLayer, exception);
snibgo's IM pages: im.snibgo.com
Roman80
Posts: 25
Joined: 2017-08-03T21:26:15-07:00
Authentication code: 1151

Re: How to remove transparency from a TIF and replace with white background

Post by Roman80 »

But in my case I have already a transparent background and want this to be replaced with a white background.

The following code do not work:

Code: Select all

QueryColorCompliance ("white", AllCompliance, &inImg->background_color, exception);
Image * outImg = MergeImageLayers(inImg, FlattenLayer, exception);
Regards
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: How to remove transparency from a TIF and replace with white background

Post by snibgo »

Roman80 wrote:The following code do not work:
It works fine for me. For you, does it compile? Does it run without error? How do you know it doesn't work?
snibgo's IM pages: im.snibgo.com
Roman80
Posts: 25
Joined: 2017-08-03T21:26:15-07:00
Authentication code: 1151

Re: How to remove transparency from a TIF and replace with white background

Post by Roman80 »

Hi,

i prepared a running example, which demonstrates that it is not working:

Code: Select all

#include <memory>
#include <string>
#include <iostream>

#ifdef _WIN32
#   pragma warning(disable : 5033) // warning C5033: 'register' is no longer a supported storage class
#endif
#include <MagickCore/MagickCore.h>

class MagickUse {
public:
    MagickUse(char **argv) {
        MagickCoreGenesis(*argv, MagickTrue);
    }

    ~MagickUse() {
        MagickCoreTerminus();
    }
};

int main(int argc, char* argv[]) {
    // Usage: prg [INPUT_FILE] [OUTPUT_FILE]
    const std::string inputFile = argv[argc - 2];
    const std::string outputFile = argv[argc - 1];
    const std::string outputFile2 = [=] { // a lambda because we want a const variable
        const size_t pos = outputFile.rfind('.');
        std::string tmp(outputFile);
        tmp.insert(pos, "_2");
        return tmp;
    }();

    std::unique_ptr<MagickUse> magickUse(new MagickUse(argv));
    std::shared_ptr<ExceptionInfo> exception(AcquireExceptionInfo(), DestroyExceptionInfo);

    std::shared_ptr<ImageInfo> pImageInfoInput(CloneImageInfo((ImageInfo *)NULL), DestroyImageInfo);
    strcpy(pImageInfoInput->filename, inputFile.c_str());

    std::cout << "Input file: " << pImageInfoInput->filename << std::endl;
    std::shared_ptr<Image> inputImage(ReadImage(pImageInfoInput.get(), exception.get()), DestroyImage);
    if (exception->severity != UndefinedException)
        CatchException(exception.get());

    if (!inputImage)
        return 1;

    std::shared_ptr<ImageInfo> pImageInfoOutput(CloneImageInfo((ImageInfo *)NULL), DestroyImageInfo);
    strcpy(pImageInfoOutput->filename, outputFile.c_str());

    std::cout << "Output file (before changes): " << pImageInfoOutput->filename << std::endl;
    MagickBooleanType retVal = WriteImages(pImageInfoOutput.get(), inputImage.get(), outputFile.c_str() , exception.get());

    std::shared_ptr<ImageInfo> pImageInfoOutput2(CloneImageInfo((ImageInfo *)NULL), DestroyImageInfo);
    strcpy(pImageInfoOutput2->filename, outputFile2.c_str());

    std::cout << "Output file (after changes): " << pImageInfoOutput2->filename << std::endl;
    QueryColorCompliance("white", AllCompliance, &inputImage->background_color, exception.get());
    Image *outImg = MergeImageLayers(inputImage.get(), FlattenLayer, exception.get());

    retVal = WriteImages(pImageInfoOutput2.get(), outImg, outputFile.c_str(), exception.get());

    return 0;
}
After compiling, run it like "[output-binary] test.tif test_out.tif"
This will generate a file called "test_out.tif" without the QueryColorCompliance() function called and a file called "test_out_2.tif" which should have the transparency background replaced with a white background.
But the two images are the same and both images have a transparent background

Regards
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: How to remove transparency from a TIF and replace with white background

Post by snibgo »

You asked for the functions in C-API. I gave you the ones for MagickCore, in the C language. Here's a sample progam that reads an input and writes an output flattened against any colour.

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <MagickCore/MagickCore.h>

int main(int argc,char **argv)
{
  if (argc != 4) {
      (void) fprintf(stdout,"Usage: %s input output colour\n",argv[0]);
      exit(0);
  }

  MagickCoreGenesis (*argv, MagickTrue);
  ExceptionInfo *exception = AcquireExceptionInfo();
  ImageInfo *image_info = CloneImageInfo(NULL);
  strcpy (image_info->filename, argv[1]);
  Image * image = ReadImage (image_info, exception);
  if (exception->severity != UndefinedException)
    CatchException(exception);
  if (!image)
    exit(1);

  QueryColorCompliance (argv[3], AllCompliance, &image->background_color, exception);
  if (exception->severity != UndefinedException)
    CatchException(exception);
  Image * ftImg = MergeImageLayers (image, FlattenLayer, exception);
  if (!ftImg)
    MagickError(exception->severity,exception->reason,exception->description);

  strcpy(ftImg->filename,argv[2]);
  WriteImage (image_info, ftImg, exception);

  DestroyImage(ftImg);
  DestroyImage(image);
  image_info=DestroyImageInfo(image_info);
  exception=DestroyExceptionInfo(exception);
  MagickCoreTerminus();
  return(0);
}
But your example program uses C++ (CPP). Sorry, I don't use CPP.

Your C++ program won't compile for me under Gnu CPP compiler. It says:

Code: Select all

snibgo\flatc.cpp:36:56: error: 'strcpy' was not declared in this scope
snibgo's IM pages: im.snibgo.com
Roman80
Posts: 25
Joined: 2017-08-03T21:26:15-07:00
Authentication code: 1151

Re: How to remove transparency from a TIF and replace with white background

Post by Roman80 »

Your C++ program won't compile for me under Gnu CPP compiler
Please, add the additional header "#include <cstring>"

I tried your example, but it gaves me the same result:
I compiled it and run it "[output-binary] test.tif test_out.tif white". The file "test.tif" and the file "test_out.tif" are the same and have both a transparent background.

To see the transparent background, open both files in Photoshop.

Regards
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: How to remove transparency from a TIF and replace with white background

Post by snibgo »

I added the include, and your CPP program compiled and ran but did not make the second file. I added checks for retVal, but the problem seemed to be that the second WriteImages used outputFile.c_str() but needed outputFile2.c_str().

My version of your CPP progam, flatc.cpp, is now:

Code: Select all

#include <memory>
#include <string>
#include <cstring>
#include <iostream>

#ifdef _WIN32
#   pragma warning(disable : 5033) // warning C5033: 'register' is no longer a supported storage class
#endif
#include <MagickCore/MagickCore.h>

class MagickUse {
public:
    MagickUse(char **argv) {
        MagickCoreGenesis(*argv, MagickTrue);
    }

    ~MagickUse() {
        MagickCoreTerminus();
    }
};

int main(int argc, char* argv[]) {
    // Usage: prg [INPUT_FILE] [OUTPUT_FILE]
    const std::string inputFile = argv[argc - 2];
    const std::string outputFile = argv[argc - 1];
    const std::string outputFile2 = [=] { // a lambda because we want a const variable
        const size_t pos = outputFile.rfind('.');
        std::string tmp(outputFile);
        tmp.insert(pos, "_2");
        return tmp;
    }();

    std::unique_ptr<MagickUse> magickUse(new MagickUse(argv));
    std::shared_ptr<ExceptionInfo> exception(AcquireExceptionInfo(), DestroyExceptionInfo);

    std::shared_ptr<ImageInfo> pImageInfoInput(CloneImageInfo((ImageInfo *)NULL), DestroyImageInfo);
    strcpy(pImageInfoInput->filename, inputFile.c_str());

    std::cout << "Input file: " << pImageInfoInput->filename << std::endl;
    std::shared_ptr<Image> inputImage(ReadImage(pImageInfoInput.get(), exception.get()), DestroyImage);
    if (exception->severity != UndefinedException)
        CatchException(exception.get());

    if (!inputImage)
        return 1;

    std::shared_ptr<ImageInfo> pImageInfoOutput(CloneImageInfo((ImageInfo *)NULL), DestroyImageInfo);
    strcpy(pImageInfoOutput->filename, outputFile.c_str());

    std::cout << "Output file (before changes): " << pImageInfoOutput->filename << std::endl;
    MagickBooleanType retVal = WriteImages(pImageInfoOutput.get(), inputImage.get(), outputFile.c_str() , exception.get());
    if (!retVal) {
      std::cout << "Failed to write " << pImageInfoOutput->filename << std::endl;
    }

    std::shared_ptr<ImageInfo> pImageInfoOutput2(CloneImageInfo((ImageInfo *)NULL), DestroyImageInfo);
    strcpy(pImageInfoOutput2->filename, outputFile2.c_str());

    std::cout << "Output file (after changes): " << pImageInfoOutput2->filename << std::endl;
    QueryColorCompliance("white", AllCompliance, &inputImage->background_color, exception.get());
    Image *outImg = MergeImageLayers(inputImage.get(), FlattenLayer, exception.get());

    retVal = WriteImages(pImageInfoOutput2.get(), outImg, outputFile2.c_str(), exception.get());
    if (!retVal) {
      std::cout << "Failed to write " << pImageInfoOutput2->filename << std::endl;
    }

    return 0;
}
It works fine with IM v7.0.7-28.

Code: Select all

flatc toes_holed.png flatc_out.png
toes_holed.png:
Image

flatc_out.png
Image
flatc_out_2.png
Image

The second output is flattened against white.

If you don't get the same result, perhaps there was a bug in IM v7.0.7-22, and upgrading may help.
snibgo's IM pages: im.snibgo.com
Roman80
Posts: 25
Joined: 2017-08-03T21:26:15-07:00
Authentication code: 1151

Re: How to remove transparency from a TIF and replace with white background

Post by Roman80 »

Thanks, but maybe the problem is handling a Photoshop generated TIF with transparency with IM?

Try the TIF file with a TIF file as output, and IMPORTANT: open the generated file with Photoshop

Regards
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: How to remove transparency from a TIF and replace with white background

Post by snibgo »

Photoshop transparency is a different issue. I suggest you first get your program to work with PNG input and output. If it doesn't work with PNG, it won't work with TIFF.

After converting toes_holed.png to a tiff, the program can flatten it, writing to tiff outputs.

I don't use Photoshop. PS has a number of mechanisms for transparency. The tiff you linked to in the OP has no transparency according to ImageMagick, exiftool or Gimp.
snibgo's IM pages: im.snibgo.com
Roman80
Posts: 25
Joined: 2017-08-03T21:26:15-07:00
Authentication code: 1151

Re: How to remove transparency from a TIF and replace with white background

Post by Roman80 »

OK, sorry, maybe I did not exactly describe my problem

1.) I tried it with your and with the corrected version of my program: TIF to PNG works, TIF to JPG works.
Both (PNG and JPG) have a white background regardless of the third parameter. (e.g. If i try "blue" as the third parameter than the background is still white)
Maybe this is also an issue?

2.)
Photoshop transparency is a different issue
This is my main issue at the moment for TIF files. Here I only want to replace the transparent background from a Photoshop generated TIF with a white background, but that do not work.

Best Regards
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: How to remove transparency from a TIF and replace with white background

Post by snibgo »

JPG can't record transparency, so a JPG image is always fully opaque.

The C program that I showed (flatcol.c) uses argv[3] as the colour:

Code: Select all

flatcol toes_holed.png flatcol_out.png Blue
flatcol_out.png is:
Image

Hacking flat.cpp to use a third parameter:

Code: Select all

#include <memory>
#include <string>
#include <cstring>
#include <iostream>

#ifdef _WIN32
#   pragma warning(disable : 5033) // warning C5033: 'register' is no longer a supported storage class
#endif
#include <MagickCore/MagickCore.h>

class MagickUse {
public:
    MagickUse(char **argv) {
        MagickCoreGenesis(*argv, MagickTrue);
    }

    ~MagickUse() {
        MagickCoreTerminus();
    }
};

int main(int argc, char* argv[]) {
    // Usage: prg [INPUT_FILE] [OUTPUT_FILE]
    const std::string inputFile = argv[argc - 3];
    const std::string outputFile = argv[argc - 2];
    const std::string flatcol = argv[argc - 1];
    const std::string outputFile2 = [=] { // a lambda because we want a const variable
        const size_t pos = outputFile.rfind('.');
        std::string tmp(outputFile);
        tmp.insert(pos, "_2");
        return tmp;
    }();

    std::unique_ptr<MagickUse> magickUse(new MagickUse(argv));
    std::shared_ptr<ExceptionInfo> exception(AcquireExceptionInfo(), DestroyExceptionInfo);

    std::shared_ptr<ImageInfo> pImageInfoInput(CloneImageInfo((ImageInfo *)NULL), DestroyImageInfo);
    strcpy(pImageInfoInput->filename, inputFile.c_str());

    std::cout << "Input file: " << pImageInfoInput->filename << std::endl;
    std::shared_ptr<Image> inputImage(ReadImage(pImageInfoInput.get(), exception.get()), DestroyImage);
    if (exception->severity != UndefinedException)
        CatchException(exception.get());

    if (!inputImage)
        return 1;

    std::shared_ptr<ImageInfo> pImageInfoOutput(CloneImageInfo((ImageInfo *)NULL), DestroyImageInfo);
    strcpy(pImageInfoOutput->filename, outputFile.c_str());

    std::cout << "Output file (before changes): " << pImageInfoOutput->filename << std::endl;
    MagickBooleanType retVal = WriteImages(pImageInfoOutput.get(), inputImage.get(), outputFile.c_str() , exception.get());
    if (!retVal) {
      std::cout << "Failed to write " << pImageInfoOutput->filename << std::endl;
    }

    std::shared_ptr<ImageInfo> pImageInfoOutput2(CloneImageInfo((ImageInfo *)NULL), DestroyImageInfo);
    strcpy(pImageInfoOutput2->filename, outputFile2.c_str());

    std::cout << "Output file (after changes): " << pImageInfoOutput2->filename << std::endl;
    QueryColorCompliance(flatcol.c_str(), AllCompliance, &inputImage->background_color, exception.get());
    Image *outImg = MergeImageLayers(inputImage.get(), FlattenLayer, exception.get());

    retVal = WriteImages(pImageInfoOutput2.get(), outImg, outputFile2.c_str(), exception.get());
    if (!retVal) {
      std::cout << "Failed to write " << pImageInfoOutput2->filename << std::endl;
    }

    return 0;
}

Code: Select all

c:\cygwin64\home\Alan\ImageMagick-7.0.7-28\ImageMagick>%IM7DEV%flatc f:\web\im\t
oes_holed.png flatc_pink_out.png pink
Image

So, your CPP program can flatten against any colour, using QueryColorCompliance() and MergeImageLayers().


I don't use Photoshop. Perhaps there is a setting to make it save to TIFF with an alpha channel.
snibgo's IM pages: im.snibgo.com
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: How to remove transparency from a TIF and replace with white background

Post by fmw42 »

Your original test.tif file does indeed open in Photoshop with transparency. But none of my other tools such as Mac Preview and GraphicsConverter and GIMP show the transparency. Even EXIFTOOL shows

258 BitsPerSample : 8 8 8

So the transparency is there in some hidden way that only Photoshop can read, perhaps in the XMP profile.
Post Reply