Recent

Author Topic: [SOLVED] Reading black & white TIFF images?  (Read 10107 times)

BigChimp

  • Hero Member
  • *****
  • Posts: 5740
  • Add to the wiki - it's free ;)
    • FPCUp, PaperTiger scanning and other open source projects
[SOLVED] Reading black & white TIFF images?
« on: February 22, 2013, 08:15:22 am »
Hi all,

Busy with my scanning program. It uses the sane scanning program on Linux which outputs lineart/black and white images.

Turns out these can't be read by FPC's fpreadtiff.

Would it be (fairly) easy to patch fpreadtiff to support this format or would it be easiest to use another image library (e.g. imagemagick, vampyre imaging library) to read the file?
I have the feeling it's uncompressed as it zips up nicely :)

Attached an example.
« Last Edit: February 23, 2013, 09:44:33 am by BigChimp »
Want quicker answers to your questions? Read http://wiki.lazarus.freepascal.org/Lazarus_Faq#What_is_the_correct_way_to_ask_questions_in_the_forum.3F

Open source including papertiger OCR/PDF scanning:
https://bitbucket.org/reiniero

Lazarus trunk+FPC trunk x86, Windows x64 unless otherwise specified

theo

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1890
Re: Reading black & white TIFF images?
« Reply #1 on: February 22, 2013, 11:02:44 am »
Afaik, there are so many TIFF variants that only LibTIFF can read them all. ;-)

I would convert it to PNG or BMP using PacalMagick
http://wiki.freepascal.org/PascalMagick

It is a FPC Package "ImageMagick", you don't need to download anything.

uses magick_wand, ImageMagick;         

BigChimp

  • Hero Member
  • *****
  • Posts: 5740
  • Add to the wiki - it's free ;)
    • FPCUp, PaperTiger scanning and other open source projects
Re: Reading black & white TIFF images?
« Reply #2 on: February 22, 2013, 11:06:48 am »
Thanks, theo, that certainly sounds like a good short-term [1] solution ;)

[1] Yes, an euphemism for long-term ;)
Want quicker answers to your questions? Read http://wiki.lazarus.freepascal.org/Lazarus_Faq#What_is_the_correct_way_to_ask_questions_in_the_forum.3F

Open source including papertiger OCR/PDF scanning:
https://bitbucket.org/reiniero

Lazarus trunk+FPC trunk x86, Windows x64 unless otherwise specified

theo

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1890
Re: Reading black & white TIFF images?
« Reply #3 on: February 22, 2013, 04:47:48 pm »
Here is some code to use ImageMagick for Image loading to Bitmap without converting to other format.

Use like

Code: [Select]
if OpenDialog1.Execute then
   LoadMagickBitmap(OpenDialog1.FileName,Image1.Picture.Bitmap);   

Code: [Select]
unit magicklcl;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Graphics;

procedure LoadMagickBitmap(FileName: string; Bmp: TBitmap);

implementation

uses magick_wand, ImageMagick, IntfGraphics, FPimage, LazUTF8;

procedure LoadMagickBitmap(FileName: string; Bmp: TBitmap);
var
  status: MagickBooleanType;
  wand: PMagickWand;
  img: Pimage;
  pack: PPixelPacket;
  limg: TLazIntfImage;
  i, j, wi, he: integer;
  colo: TFPColor;
  description: PChar;
  severity: ExceptionType;
begin
  wand := NewMagickWand;
  try
    status := MagickReadImage(wand, PChar(UTF8ToSys(FileName)));
    if (status = MagickFalse) then
    begin
      description := MagickGetException(wand, @severity);
      raise Exception.Create(Format('An error ocurred. Description: %s',
        [description]));
      description := MagickRelinquishMemory(description);
    end;
    img := GetImageFromMagickWand(wand);
    he := MagickGetImageHeight(wand);
    wi := MagickGetImageWidth(wand);
    limg := TLazIntfImage.Create(0, 0);
    limg.DataDescription := GetDescriptionFromDevice(0, wi, he);
    pack := GetAuthenticPixels(img, 0, 0, wi, he, nil);
    for j := 0 to he - 1 do
      for i := 0 to wi - 1 do
      begin
        colo.red := pack^.red;
        colo.green := pack^.green;
        colo.blue := pack^.blue;
        colo.alpha := pack^.opacity;
        limg.Colors[i, j] := colo;
        Inc(pack);
      end;
    Bmp.LoadFromIntfImage(limg);
  finally
    limg.Free;
    wand := DestroyMagickWand(wand);
  end;
end;

initialization
  MagickWandGenesis;

finalization;
  MagickWandTerminus;

end.

I hope it works.

BigChimp

  • Hero Member
  • *****
  • Posts: 5740
  • Add to the wiki - it's free ;)
    • FPCUp, PaperTiger scanning and other open source projects
Re: Reading black & white TIFF images?
« Reply #4 on: February 23, 2013, 09:44:21 am »
Thanks a lot, Theo, seems it works: got an image - just have to start scanning non-empty pages to properly test ;)

As I receive a TMemoryStream from the web server, I adapted the code a bit to eliminate intermediate files:
Code: [Select]
function StreamToMemory(Stream: TStream): Pointer;
begin
  if Assigned(Stream) then
    begin
      Result := AllocMem(Stream.Size);
      Stream.Position := 0;
      Stream.Read(Result^, Stream.Size);
    end
  else
    Result := nil;
end;


procedure LoadMagickBitmap(ImageStream: TStream; Bmp: TBitmap);
// Let imagemagick convert an image and return a bitmap.
// Adapted from code from theo on the Lazarus forum.
var
  ImageBufferPtr: Pointer;
  status: MagickBooleanType;
  wand: PMagickWand;
  img: Pimage;
  pack: PPixelPacket;
  limg: TLazIntfImage;
  i, j, wi, he: integer;
  colo: TFPColor;
  description: PChar;
  severity: ExceptionType;
begin
  wand := NewMagickWand;
  try
    // First convert stream to regular chunk of memory
    ImageBufferPtr:=StreamToMemory(ImageStream);
    if ImageBufferPtr=nil then
    begin
      raise Exception.Create('LoadMagickBitmap: could not read image. Details: stream conversion failed.');
    end
    else
    begin
      try
        status := MagickReadImageBlob(wand, ImageBufferPtr, ImageStream.Size);
      finally
        FreeMem(ImageBufferPtr);
      end;
    end;

    if (status = MagickFalse) then
    begin
      description := MagickGetException(wand, @severity);
      raise Exception.Create(Format('LoadMagickBitmap: an error ocurred. Description: %s',
        [description]));
      description := MagickRelinquishMemory(description);
    end;
    img := GetImageFromMagickWand(wand);
    he := MagickGetImageHeight(wand);
    wi := MagickGetImageWidth(wand);
    limg := TLazIntfImage.Create(0, 0);
    limg.DataDescription := GetDescriptionFromDevice(0, wi, he);
    pack := GetAuthenticPixels(img, 0, 0, wi, he, nil);
    for j := 0 to he - 1 do
      for i := 0 to wi - 1 do
      begin
        colo.red := pack^.red;
        colo.green := pack^.green;
        colo.blue := pack^.blue;
        colo.alpha := pack^.opacity;
        limg.Colors[i, j] := colo;
        Inc(pack);
      end;
    Bmp.LoadFromIntfImage(limg);
  finally
    limg.Free;
    wand := DestroyMagickWand(wand);
  end;
end;
Want quicker answers to your questions? Read http://wiki.lazarus.freepascal.org/Lazarus_Faq#What_is_the_correct_way_to_ask_questions_in_the_forum.3F

Open source including papertiger OCR/PDF scanning:
https://bitbucket.org/reiniero

Lazarus trunk+FPC trunk x86, Windows x64 unless otherwise specified

theo

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1890
Re: [SOLVED] Reading black & white TIFF images?
« Reply #5 on: February 23, 2013, 12:05:08 pm »
Great.
If you would use a TMemoryStream as Parameter,  you could access
  MS.Memory
directly without the StreamToMemory function which doubles memory usage, no?

BigChimp

  • Hero Member
  • *****
  • Posts: 5740
  • Add to the wiki - it's free ;)
    • FPCUp, PaperTiger scanning and other open source projects
Re: [SOLVED] Reading black & white TIFF images?
« Reply #6 on: February 23, 2013, 12:33:13 pm »
Tried that but got an imagemagick error saying the blob could not be read: no decode delegate for this image format.

So I assumed a memorystream must have some extra data in front of it for accounting purposes etc but perhaps :) I'm wrong.

Used this kind of code:
Code: [Select]
procedure LoadMagickBitmap(ImageStream: TMemoryStream; Bmp: TBitmap);
// Let imagemagick convert an image and return a bitmap.
// Adapted from code from theo on the Lazarus forum.
var
....same...
begin
  wand := NewMagickWand;
  try
    ImageStream.Position:=0;
    status := MagickReadImageBlob(wand, @ImageStream, ImageStream.Size);
//passing @ or not doesn't matter, same error message

What am I doing wrong :)
Want quicker answers to your questions? Read http://wiki.lazarus.freepascal.org/Lazarus_Faq#What_is_the_correct_way_to_ask_questions_in_the_forum.3F

Open source including papertiger OCR/PDF scanning:
https://bitbucket.org/reiniero

Lazarus trunk+FPC trunk x86, Windows x64 unless otherwise specified

theo

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1890
Re: [SOLVED] Reading black & white TIFF images?
« Reply #7 on: February 23, 2013, 12:35:44 pm »
I wrote above pass

ImageStream.Memory

to the function. It's already a pointer.

BigChimp

  • Hero Member
  • *****
  • Posts: 5740
  • Add to the wiki - it's free ;)
    • FPCUp, PaperTiger scanning and other open source projects
Re: [SOLVED] Reading black & white TIFF images?
« Reply #8 on: February 23, 2013, 01:18:27 pm »
Argh. Sorry. Yep, that works.
« Last Edit: February 23, 2013, 01:20:42 pm by BigChimp »
Want quicker answers to your questions? Read http://wiki.lazarus.freepascal.org/Lazarus_Faq#What_is_the_correct_way_to_ask_questions_in_the_forum.3F

Open source including papertiger OCR/PDF scanning:
https://bitbucket.org/reiniero

Lazarus trunk+FPC trunk x86, Windows x64 unless otherwise specified

theo

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1890
Re: [SOLVED] Reading black & white TIFF images?
« Reply #9 on: February 23, 2013, 01:19:41 pm »
The next version below. Please test.

Code: [Select]
unit magicklcl;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Graphics;

procedure LoadMagickBitmap(FileName: string; Bmp: TBitmap); overload;
procedure LoadMagickBitmap(Strm: TMemoryStream; Bmp: TBitmap); overload;

implementation

uses magick_wand, ImageMagick, IntfGraphics, FPimage, LazUTF8;

procedure LoadMagickBitmapWand(Wand: PMagickWand; Bmp: TBitmap);
var
  img: Pimage;
  pack: PPixelPacket;
  limg: TLazIntfImage;
  i, j, wi, he: integer;
  colo: TFPColor;
begin
  img := GetImageFromMagickWand(wand);
  he := MagickGetImageHeight(wand);
  wi := MagickGetImageWidth(wand);
  limg := TLazIntfImage.Create(0, 0);
  try
    limg.DataDescription := GetDescriptionFromDevice(0, wi, he);
    pack := GetAuthenticPixels(img, 0, 0, wi, he, nil);
    for j := 0 to he - 1 do
      for i := 0 to wi - 1 do
      begin
        colo.red := pack^.red;
        colo.green := pack^.green;
        colo.blue := pack^.blue;
        colo.alpha := pack^.opacity;
        limg.Colors[i, j] := colo;
        Inc(pack);
      end;
    Bmp.LoadFromIntfImage(limg);
  finally
    limg.Free;
  end;
end;

procedure LoadMagickBitmap(FileName: string; Bmp: TBitmap);
var
  wand: PMagickWand;
  status: MagickBooleanType;
  description: PChar;
  severity: ExceptionType;
begin
  wand := NewMagickWand;
  try
    status := MagickReadImage(wand, PChar(UTF8ToSys(FileName)));
    if (status = MagickFalse) then
    begin
      description := MagickGetException(wand, @severity);
      raise Exception.Create(Format('An error ocurred. Description: %s',
        [description]));
      description := MagickRelinquishMemory(description);
    end else LoadMagickBitmapWand(wand, Bmp);
  finally
    wand := DestroyMagickWand(wand);
  end;
end;

procedure LoadMagickBitmap(Strm: TMemoryStream; Bmp: TBitmap);
var
  wand: PMagickWand;
  status: MagickBooleanType;
  description: PChar;
  severity: ExceptionType;
begin
  wand := NewMagickWand;
  try
    Strm.Position := 0;
    status := MagickReadImageBlob(wand, Strm.Memory, Strm.Size);
    if (status = MagickFalse) then
    begin
      description := MagickGetException(wand, @severity);
      raise Exception.Create(Format('An error ocurred. Description: %s',
        [description]));
      description := MagickRelinquishMemory(description);
    end else LoadMagickBitmapWand(wand, Bmp);
  finally
    wand := DestroyMagickWand(wand);
  end;
end;

initialization
  MagickWandGenesis;

finalization;
  MagickWandTerminus;

end.

BigChimp

  • Hero Member
  • *****
  • Posts: 5740
  • Add to the wiki - it's free ;)
    • FPCUp, PaperTiger scanning and other open source projects
Re: [SOLVED] Reading black & white TIFF images?
« Reply #10 on: March 11, 2013, 10:44:46 am »
FYI, FPC trunk has support for 1 bit TIFF images (uncompressed and some compressions. Missing are CCIT Group 3/4 fax compression)
Want quicker answers to your questions? Read http://wiki.lazarus.freepascal.org/Lazarus_Faq#What_is_the_correct_way_to_ask_questions_in_the_forum.3F

Open source including papertiger OCR/PDF scanning:
https://bitbucket.org/reiniero

Lazarus trunk+FPC trunk x86, Windows x64 unless otherwise specified