summaryrefslogtreecommitdiffstats
path: root/filters
diff options
context:
space:
mode:
Diffstat (limited to 'filters')
-rw-r--r--filters/Makefile.am2
-rw-r--r--filters/chalk/Makefile.am34
-rw-r--r--filters/chalk/configure.in.in66
-rw-r--r--filters/chalk/gmagick/Makefile.am44
-rw-r--r--filters/chalk/gmagick/chalk_magick.desktop57
-rw-r--r--filters/chalk/gmagick/chalk_magick_export.desktop55
-rw-r--r--filters/chalk/gmagick/chalk_magick_import.desktop61
-rw-r--r--filters/chalk/gmagick/configure.in.bot23
-rw-r--r--filters/chalk/gmagick/kis_image_magick_converter.cc1142
-rw-r--r--filters/chalk/gmagick/kis_image_magick_converter.h104
-rw-r--r--filters/chalk/gmagick/magickexport.cpp78
-rw-r--r--filters/chalk/gmagick/magickexport.h37
-rw-r--r--filters/chalk/gmagick/magickimport.cpp105
-rw-r--r--filters/chalk/gmagick/magickimport.h37
-rw-r--r--filters/chalk/jpeg/Makefile.am51
-rw-r--r--filters/chalk/jpeg/chalk_jpeg.desktop58
-rw-r--r--filters/chalk/jpeg/chalk_jpeg_export.desktop52
-rw-r--r--filters/chalk/jpeg/chalk_jpeg_import.desktop52
-rw-r--r--filters/chalk/jpeg/configure.in.bot7
-rw-r--r--filters/chalk/jpeg/iccjpeg.c270
-rw-r--r--filters/chalk/jpeg/iccjpeg.h99
-rw-r--r--filters/chalk/jpeg/kis_jpeg_converter.cc542
-rw-r--r--filters/chalk/jpeg/kis_jpeg_converter.h91
-rw-r--r--filters/chalk/jpeg/kis_jpeg_export.cc152
-rw-r--r--filters/chalk/jpeg/kis_jpeg_export.h35
-rw-r--r--filters/chalk/jpeg/kis_jpeg_import.cc105
-rw-r--r--filters/chalk/jpeg/kis_jpeg_import.h34
-rw-r--r--filters/chalk/jpeg/kis_wdg_options_jpeg.ui149
-rw-r--r--filters/chalk/libkisexif/Makefile.am20
-rw-r--r--filters/chalk/libkisexif/kis_exif_io.cpp177
-rw-r--r--filters/chalk/libkisexif/kis_exif_io.h45
-rw-r--r--filters/chalk/magick/Makefile.am44
-rw-r--r--filters/chalk/magick/chalk_magick.desktop58
-rw-r--r--filters/chalk/magick/chalk_magick_export.desktop55
-rw-r--r--filters/chalk/magick/chalk_magick_import.desktop61
-rw-r--r--filters/chalk/magick/configure.in.bot15
-rw-r--r--filters/chalk/magick/kis_image_magick_converter.cc1087
-rw-r--r--filters/chalk/magick/kis_image_magick_converter.h104
-rw-r--r--filters/chalk/magick/magickexport.cpp78
-rw-r--r--filters/chalk/magick/magickexport.h37
-rw-r--r--filters/chalk/magick/magickimport.cpp105
-rw-r--r--filters/chalk/magick/magickimport.h37
-rw-r--r--filters/chalk/openexr/Makefile.am51
-rw-r--r--filters/chalk/openexr/chalk_openexr.desktop57
-rw-r--r--filters/chalk/openexr/chalk_openexr_export.desktop52
-rw-r--r--filters/chalk/openexr/chalk_openexr_import.desktop52
-rw-r--r--filters/chalk/openexr/configure.in.bot9
-rw-r--r--filters/chalk/openexr/kis_openexr_export.cpp155
-rw-r--r--filters/chalk/openexr/kis_openexr_export.h38
-rw-r--r--filters/chalk/openexr/kis_openexr_import.cpp160
-rw-r--r--filters/chalk/openexr/kis_openexr_import.h38
-rw-r--r--filters/chalk/pdf/Makefile.am30
-rw-r--r--filters/chalk/pdf/chalk_pdf.desktop63
-rw-r--r--filters/chalk/pdf/chalk_pdf_import.desktop51
-rw-r--r--filters/chalk/pdf/configure.in.bot7
-rw-r--r--filters/chalk/pdf/configure.in.in4
-rw-r--r--filters/chalk/pdf/kis_pdf_import.cpp158
-rw-r--r--filters/chalk/pdf/kis_pdf_import.h35
-rw-r--r--filters/chalk/pdf/kis_pdf_import_widget.cpp147
-rw-r--r--filters/chalk/pdf/kis_pdf_import_widget.h55
-rw-r--r--filters/chalk/pdf/pdfimportwidgetbase.ui321
-rw-r--r--filters/chalk/png/Makefile.am44
-rw-r--r--filters/chalk/png/chalk_png.desktop57
-rw-r--r--filters/chalk/png/chalk_png_export.desktop51
-rw-r--r--filters/chalk/png/chalk_png_import.desktop51
-rw-r--r--filters/chalk/png/configure.in.bot8
-rw-r--r--filters/chalk/png/kis_png_converter.cc794
-rw-r--r--filters/chalk/png/kis_png_converter.h82
-rw-r--r--filters/chalk/png/kis_png_export.cc124
-rw-r--r--filters/chalk/png/kis_png_export.h35
-rw-r--r--filters/chalk/png/kis_png_import.cc105
-rw-r--r--filters/chalk/png/kis_png_import.h34
-rw-r--r--filters/chalk/png/kis_wdg_options_png.ui183
-rw-r--r--filters/chalk/raw/Makefile.am35
-rw-r--r--filters/chalk/raw/chalk_raw.desktop57
-rw-r--r--filters/chalk/raw/chalk_raw_import.desktop51
-rw-r--r--filters/chalk/raw/dcraw.1182
-rw-r--r--filters/chalk/raw/dcraw.c5999
-rw-r--r--filters/chalk/raw/kis_raw_import.cpp630
-rw-r--r--filters/chalk/raw/kis_raw_import.h71
-rw-r--r--filters/chalk/raw/wdgrawimport.ui496
-rw-r--r--filters/chalk/tiff/Makefile.am55
-rw-r--r--filters/chalk/tiff/chalk_tiff.desktop63
-rw-r--r--filters/chalk/tiff/chalk_tiff_export.desktop52
-rw-r--r--filters/chalk/tiff/chalk_tiff_import.desktop52
-rw-r--r--filters/chalk/tiff/configure.in.bot7
-rw-r--r--filters/chalk/tiff/kis_dlg_options_tiff.cpp134
-rw-r--r--filters/chalk/tiff/kis_dlg_options_tiff.h45
-rw-r--r--filters/chalk/tiff/kis_tiff_converter.cc677
-rw-r--r--filters/chalk/tiff/kis_tiff_converter.h94
-rw-r--r--filters/chalk/tiff/kis_tiff_export.cc123
-rw-r--r--filters/chalk/tiff/kis_tiff_export.h35
-rw-r--r--filters/chalk/tiff/kis_tiff_import.cc105
-rw-r--r--filters/chalk/tiff/kis_tiff_import.h34
-rw-r--r--filters/chalk/tiff/kis_tiff_reader.cc121
-rw-r--r--filters/chalk/tiff/kis_tiff_reader.h206
-rw-r--r--filters/chalk/tiff/kis_tiff_stream.cc164
-rw-r--r--filters/chalk/tiff/kis_tiff_stream.h81
-rw-r--r--filters/chalk/tiff/kis_tiff_writer_visitor.cpp237
-rw-r--r--filters/chalk/tiff/kis_tiff_writer_visitor.h53
-rw-r--r--filters/chalk/tiff/kis_tiff_ycbcr_reader.cc170
-rw-r--r--filters/chalk/tiff/kis_tiff_ycbcr_reader.h73
-rw-r--r--filters/chalk/tiff/kis_wdg_options_tiff.ui741
-rw-r--r--filters/chalk/tiff/kis_ycbcr_colorspace.h27
-rw-r--r--filters/chalk/xcf/Makefile.am42
-rw-r--r--filters/chalk/xcf/chalk_xcf_export.desktop52
-rw-r--r--filters/chalk/xcf/chalk_xcf_import.desktop52
-rw-r--r--filters/chalk/xcf/xcf/README2
-rw-r--r--filters/chalk/xcf/xcf/xcf-load.cc1740
-rw-r--r--filters/chalk/xcf/xcf/xcf-load.h27
-rw-r--r--filters/chalk/xcf/xcf/xcf-private.h95
-rw-r--r--filters/chalk/xcf/xcf/xcf-read.cc118
-rw-r--r--filters/chalk/xcf/xcf/xcf-read.h37
-rw-r--r--filters/chalk/xcf/xcf/xcf-save.cc1826
-rw-r--r--filters/chalk/xcf/xcf/xcf-save.h29
-rw-r--r--filters/chalk/xcf/xcf/xcf-seek.cc79
-rw-r--r--filters/chalk/xcf/xcf/xcf-seek.h30
-rw-r--r--filters/chalk/xcf/xcf/xcf-write.cc104
-rw-r--r--filters/chalk/xcf/xcf/xcf-write.h39
-rw-r--r--filters/chalk/xcf/xcfexport.cpp78
-rw-r--r--filters/chalk/xcf/xcfexport.h37
-rw-r--r--filters/chalk/xcf/xcfimport.cpp99
-rw-r--r--filters/chalk/xcf/xcfimport.h37
-rw-r--r--filters/configure.in.mid4
-rw-r--r--filters/filterstatus.xml36
-rw-r--r--filters/kspread/gnumeric/gnumericimport.cc6
-rwxr-xr-xfilters/tests/global-filter-test.sh8
127 files changed, 23935 insertions, 28 deletions
diff --git a/filters/Makefile.am b/filters/Makefile.am
index 4e18acc7..e8473741 100644
--- a/filters/Makefile.am
+++ b/filters/Makefile.am
@@ -32,7 +32,7 @@ KUGARDIR = kugar
endif
if compile_filter_KRITA
-KRITADIR = krita
+KRITADIR = chalk
endif
if compile_filter_KIVIO
diff --git a/filters/chalk/Makefile.am b/filters/chalk/Makefile.am
new file mode 100644
index 00000000..0d8732eb
--- /dev/null
+++ b/filters/chalk/Makefile.am
@@ -0,0 +1,34 @@
+if have_openexr
+OPENEXR_SUBDIR=openexr
+endif
+
+if include_imagemagick_filter
+IMAGEMAGICK_SUBDIR=magick
+endif
+
+if include_graphicsmagick_filter
+GRAPHICSMAGICK_SUBDIR=gmagick
+endif
+
+if have_png
+PNG_SUBDIR=png
+endif
+
+if include_jpeg_filter
+JPEG_SUBDIR=jpeg
+endif
+
+if include_tiff_filter
+TIFF_SUBDIR=tiff
+endif
+
+if have_exif
+LIBKISEXIF=libkisexif
+endif
+
+if include_PDF
+PDF_SUBDIR=pdf
+endif
+
+SUBDIRS = $(IMAGEMAGICK_SUBDIR) $(OPENEXR_SUBDIR) $(PNG_SUBDIR) $(LIBKISEXIF) \
+ $(JPEG_SUBDIR) $(TIFF_SUBDIR) raw $(PDF_SUBDIR) $(GRAPHICSMAGICK_SUBDIR)
diff --git a/filters/chalk/configure.in.in b/filters/chalk/configure.in.in
new file mode 100644
index 00000000..6eb8d91e
--- /dev/null
+++ b/filters/chalk/configure.in.in
@@ -0,0 +1,66 @@
+# Check if the tiff lib is available
+AC_FIND_TIFF
+AM_CONDITIONAL(have_tiff, test -n "$LIBTIFF")
+
+AC_FIND_PNG
+AM_CONDITIONAL(have_png, test -n "$LIBPNG")
+
+AC_FIND_JPEG
+AM_CONDITIONAL(have_jpeg, test -n "$LIBJPEG")
+
+#---------------------------------------------------------
+# libexif detection
+# taken from libkexif's configure.in.in
+#---------------------------------------------------------
+
+LIBEXIF=no
+
+#PKG_CHECK_MODULES(LIBEXIF, libexif >= 0.5.7, ,
+# [ AC_MSG_WARN([libexif >= 0.5.7 not found.])
+# LIBEXIF=yes ])
+
+
+#PKG_CHECK_MODULES(LIBEXIF06, libexif >= 0.6.9,
+# AC_DEFINE(HAVE_EXIF06,1,[check for libexif > 0.6]),
+# AC_MSG_WARN([Using old version of libexif.]))
+
+PKG_CHECK_MODULES(LIBEXIF, libexif >= 0.6.12 , ,
+ [ AC_MSG_WARN([libexif >= 0.6.12 not found.])
+ LIBEXIF=yes ])
+
+AC_SUBST(LIBEXIF_LIBS)
+AC_SUBST(LIBEXIF_CFLAGS)
+
+#---------------------------------------------------------
+# libexif detection
+#---------------------------------------------------------
+AC_MSG_CHECKING([if C++ program with exif can be compiled])
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+ac_save_CXXFLAGS="$CXXFLAGS"
+CXXFLAGS="$CXXFLAGS $LIBEXIF_CFLAGS"
+AC_CACHE_VAL(exif_build,
+[
+ AC_TRY_COMPILE([
+ extern "C" {
+#include <libexif/exif-loader.h>
+#include <libexif/exif-utils.h>
+}
+ ],[
+ ExifLoader *l = exif_loader_new ();
+ exif_loader_write_file (l,"kikoo");
+ return 0;
+ ], exif_build=yes,
+ exif_build=no)
+])
+AC_MSG_RESULT($exif_build)
+if test "$exif_build" = "no"; then
+ LIBEXIF=""
+fi
+CXXFLAGS="$ac_save_CXXFLAGS"
+AC_LANG_RESTORE
+
+
+AM_CONDITIONAL(have_exif, test -n "$LIBEXIF")
+AM_CONDITIONAL(include_jpeg_filter, test -n "$LIBJPEG" -a -n "$LIBEXIF")
+AM_CONDITIONAL(include_tiff_filter, test -n "$LIBTIFF" -a -n "$LIBEXIF")
diff --git a/filters/chalk/gmagick/Makefile.am b/filters/chalk/gmagick/Makefile.am
new file mode 100644
index 00000000..4d74db2a
--- /dev/null
+++ b/filters/chalk/gmagick/Makefile.am
@@ -0,0 +1,44 @@
+kde_module_LTLIBRARIES = libchalkgmagickimport.la libchalkgmagickexport.la
+
+libchalkgmagickexport_la_LDFLAGS = $(KDE_PLUGIN) $(LIBGMAGICK_LDFLAGS) $(KDE_RPATH) $(LIBGMAGICK_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalkgmagickexport_la_LIBADD = \
+ $(KOFFICE_LIBS) \
+ $(LIBGMAGICK_LIBS) \
+ $(top_builddir)/chalk/libchalkcommon.la
+
+libchalkgmagickimport_la_LDFLAGS = $(KDE_PLUGIN) $(LIBGMAGICK_LDFLAGS) $(KDE_RPATH) $(LIBGMAGICK_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalkgmagickimport_la_LIBADD = \
+ $(KOFFICE_LIBS) \
+ $(LIBGMAGICK_LIBS) \
+ $(top_builddir)/chalk/libchalkcommon.la
+
+INCLUDES= \
+ -I$(srcdir) \
+ $(KOFFICE_INCLUDES) \
+ -I$(top_srcdir)/chalk \
+ -I$(top_srcdir)/chalk/core \
+ -I$(top_srcdir)/chalk/sdk \
+ -I$(top_srcdir)/chalk/core/tiles \
+ -I$(top_srcdir)/chalk/chalkcolor \
+ -I$(top_srcdir)/chalk/ui \
+ $(KOFFICE_INCLUDES) -I$(interfacedir) \
+ $(KOPAINTER_INCLUDES) $(LIBGMAGICK_CPPFLAGS) \
+ $(all_includes)
+
+service_DATA = chalk_magick_import.desktop chalk_magick_export.desktop
+servicedir = $(kde_servicesdir)
+
+kdelnk_DATA = chalk_magick.desktop
+kdelnkdir = $(kde_appsdir)/.hidden
+
+libchalkgmagickimport_la_SOURCES = magickimport.cpp kis_image_magick_converter.cc
+libchalkgmagickexport_la_SOURCES = magickexport.cpp kis_image_magick_converter.cc
+
+METASOURCES = AUTO
+
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
diff --git a/filters/chalk/gmagick/chalk_magick.desktop b/filters/chalk/gmagick/chalk_magick.desktop
new file mode 100644
index 00000000..171834ef
--- /dev/null
+++ b/filters/chalk/gmagick/chalk_magick.desktop
@@ -0,0 +1,57 @@
+[Desktop Entry]
+Name=Chalk
+Name[hi]=के-रिता
+Name[km]= Chalk
+Name[lo]=ກຣິຕາ
+Name[ne]=क्रिता
+Exec=chalk %u
+GenericName=Painting and Image Editing Application
+GenericName[bg]=Редактор на графични изображения
+GenericName[ca]=Programa de dibuix i manipulació d'imatges
+GenericName[cs]=Malování a úpravy obrázků
+GenericName[cy]=Cymhwysiad Peintio Golygu Delweddau
+GenericName[da]=Male- og billedredigeringsprogram
+GenericName[de]=Mal- und Bildbearbeitungsprogramm
+GenericName[el]=Εφαρμογή επεξεργασίας εικόνων
+GenericName[eo]=Aplikaĵo por Pentrado kaj Bildredaktado
+GenericName[es]=Aplicación de pintura y de edición de imágenes
+GenericName[et]=Joonistamise ja pilditöötluse rakendus
+GenericName[eu]=Irudien marrazketa eta ediziorako aplikazioa
+GenericName[fa]=کاربرد ویرایش تصویر و نقاشی
+GenericName[fi]=Maalaus- ja kuvankäsitelyohjelma
+GenericName[fr]=Application de dessin et de manipulation d'images
+GenericName[fy]=Ofbyldingsmanipulaasje
+GenericName[gl]=Aplicación de Pintura e Manipulación de Imaxes
+GenericName[he]=יישום לציור ועריכת תמונות
+GenericName[hr]=Aplikacija za obradu slika i fotografija
+GenericName[hu]=Képszerkesztő
+GenericName[is]=Málun og myndritill
+GenericName[it]=Applicazione di disegno e di modifica delle immagini
+GenericName[ja]=描画と画像編集のためのアプリケーション
+GenericName[km]=កម្មវិធី​គូរ​គំនូរ និង​កែសម្រួល​រូបភាព
+GenericName[lv]=Zīmēšanas un attēlu apstrādes programma
+GenericName[nb]=Program for tegning og bilderedigering
+GenericName[nds]=Programm för't Malen un Bildbewerken
+GenericName[ne]=पेन्टीङ्ग र छवि सम्पादन अनुप्रयोग
+GenericName[nl]=Afbeeldingsmanipulatie
+GenericName[pl]=Program do edycji zdjęć oraz rysunków
+GenericName[pt]=Aplicação de Pintura e Edição de Imagens
+GenericName[pt_BR]=Aplicação de Pintura e Edição de Imagens
+GenericName[ru]=Растровые изображения
+GenericName[se]=Málen- ja govvagieđahallanprográmma
+GenericName[sk]=Program pre tvorbu a úpravu obrázkov
+GenericName[sl]=Program za risanje in obdelavo slik
+GenericName[sr]=Програм за цртање и уређивање слика
+GenericName[sr@Latn]=Program za crtanje i uređivanje slika
+GenericName[sv]=Målnings- och bildredigeringsprogram
+GenericName[uk]=Програма для малювання і редагування зображень
+GenericName[uz]=Rasmlar bilan ishlaydigan dastur
+GenericName[uz@cyrillic]=Расмлар билан ишлайдиган дастур
+GenericName[zh_CN]=绘图和图像编辑应用程序
+GenericName[zh_TW]=繪圖與影像處理程式
+MimeType=image/x-xcf-gimp;image/gif;image/cgm;image/x-bmp;image/x-ico;image/x-pcx;image/x-portable-pixmap;image/x-targa;image/x-xbm;image/x-xcf;image/x-xpm;image/x-vnd.adobe.photoshop;image/x-rgb
+Type=Application
+Icon=chalk
+Categories=
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Multi
diff --git a/filters/chalk/gmagick/chalk_magick_export.desktop b/filters/chalk/gmagick/chalk_magick_export.desktop
new file mode 100644
index 00000000..5021233a
--- /dev/null
+++ b/filters/chalk/gmagick/chalk_magick_export.desktop
@@ -0,0 +1,55 @@
+[Desktop Entry]
+Name=Chalk Magick Export Filter
+Name[bg]=Филтър за експортиране от Chalk в Magick
+Name[br]=Sil ezporzh Magick evit Chalk
+Name[ca]=Filtre d'exportació Magick per a Chalk
+Name[cy]=Hidl Allforio Magick Chalk
+Name[da]=Chalk Magick-eksportfilter
+Name[de]=Chalk Magick-Exportfilter
+Name[el]=Φίλτρο εξαγωγής Magick του Chalk
+Name[eo]=Chalk Magick-eksportfiltrilo
+Name[es]=Filtro de exportación a Magick de Chalk
+Name[et]=Chalk Magick'i ekspordifilter
+Name[eu]=Chalk-ren Magick esportaziorako iragazkia
+Name[fa]=پالایۀ صادرات Chalk Magick
+Name[fi]=Chalk Magick -vientisuodin
+Name[fr]=Filtre d'exportation Magick de Chalk
+Name[fy]=Chalk Magick Eksportfilter
+Name[ga]=Scagaire Easpórtála Magick Chalk
+Name[gl]=Filtro de Exportación de Magick para Chalk
+Name[he]=מסנן יצוא מ־Chalk ל־Magick
+Name[hr]=Chalk Magick filtar izvoza
+Name[hu]=Chalk Magick exportszűrő
+Name[is]=Chalk Magick útflutningssía
+Name[it]=Filtro di esportazione Magick per Chalk
+Name[ja]=Chalk Magick エクスポートフィルタ
+Name[km]=តម្រង​នាំចេញ Magick សម្រាប់ Chalk
+Name[lt]=Chalk Magick eksportavimo filtras
+Name[lv]=Chalk Magick eksporta filtrs
+Name[ms]=Penapis Eksport Chalk Magick
+Name[nb]=Magick-eksportfilter for Chalk
+Name[nds]=Magick-Exportfilter för Chalk
+Name[ne]=क्रिता म्याजिक निर्यात फिल्टर
+Name[nl]=Chalk Magick Exportfilter
+Name[nn]=Magick-eksportfilter for Chalk
+Name[pl]=Filtr eksportu do formatu Magick z Chalk
+Name[pt]=Filtro de Exportação de Magick para o Chalk
+Name[pt_BR]=Filtro de exportação Magick para o Chalk
+Name[ru]=Фильтр экспорта рисунков Chalk в Magick
+Name[se]=Chalk Magick-olggosfievrridansilli
+Name[sk]=Magick filter pre export do Chalk
+Name[sl]=Izvozni filter Magick za Krito
+Name[sr]=Chalk-ин филтер за извоз у Magick
+Name[sr@Latn]=Chalk-in filter za izvoz u Magick
+Name[sv]=Chalk Magick-exportfilter
+Name[uk]=Фільтр експорту Magick для Chalk
+Name[uz]=Chalk Magick eksport filteri
+Name[uz@cyrillic]=Chalk Magick экспорт филтери
+Name[zh_CN]=Chalk Magick 导出过滤器
+Name[zh_TW]=Chalk Magick 匯出過濾程式
+X-KDE-Export=image/gif,image/cgm,image/x-pcx,image/x-portable-pixmap,image/x-targa,image/x-xbm,image/x-xpm,image/x-rgb,image/x-eps
+ServiceTypes=KOfficeFilter
+Type=Service
+X-KDE-Import=application/x-chalk
+X-KDE-Weight=1
+X-KDE-Library=libchalkgmagickexport
diff --git a/filters/chalk/gmagick/chalk_magick_import.desktop b/filters/chalk/gmagick/chalk_magick_import.desktop
new file mode 100644
index 00000000..c487f0c4
--- /dev/null
+++ b/filters/chalk/gmagick/chalk_magick_import.desktop
@@ -0,0 +1,61 @@
+[Desktop Entry]
+Type=Service
+Name=Chalk Magick Import Filter
+Name[bg]=Филтър за импортиране от Magick в Chalk
+Name[br]=Sil enporzh Magick evit Chalk
+Name[ca]=Filtre d'importació Magick per a Chalk
+Name[cs]=Importní filtr formátu Magick pro Kritu
+Name[cy]=Hidl Mewnforio Chalk Magick
+Name[da]=Chalk Magick-importfilter
+Name[de]=Chalk Magick-Importfilter
+Name[el]=Φίλτρο εισαγωγής Magick του Chalk
+Name[eo]=Chalk Magick-importfiltrilo
+Name[es]=Filtro de importación a Magick de Chalk
+Name[et]=Chalk Magick'i impordifilter
+Name[eu]=Chalk-ren Magick inportaziorako iragazkia
+Name[fa]=پالایۀ واردات Chalk Magick
+Name[fi]=Chalk Magick-tuontisuodin
+Name[fr]=Filtre d'importation Magick de Chalk
+Name[fy]=Chalk Magick Ymportfilter
+Name[ga]=Scagaire Iompórtála Magick Chalk
+Name[gl]=Filtro de Importación de Magick para Chalk
+Name[he]=מסנן יבוא מ־Magick ל־Chalk
+Name[hi]=के-रीता मैजिक आयात फ़िल्टर
+Name[hr]=Chalk Magick filtar uvoza
+Name[hu]=Chalk Magick importszűrő
+Name[is]=Chalk Magick innflutningssía
+Name[it]=Filtro di importazione Magick per Chalk
+Name[ja]=Chalk Magick インポートフィルタ
+Name[km]=តម្រង​នាំចូល Magick សម្រាប់ Chalk
+Name[lo]= ຕົວຕອງການນຳເຂົ້າ WML ຂອງເອກະສານຂໍ້ຄວາມ K
+Name[lt]=Chalk Magick importavimo filtras
+Name[lv]=Chalk Magick importa filtrs
+Name[ms]=Penapis Import Chalk Magick
+Name[nb]=Magick-importfilter for Chalk
+Name[nds]=Magick-Importfilter för Chalk
+Name[ne]=क्रिता म्याजिक आयात फिल्टर
+Name[nl]=Chalk Magick Importfilter
+Name[nn]=Magick-importfilter for Chalk
+Name[pl]=Filtr importu formatu Magick do Chalk
+Name[pt]=Filtro de Importação de Magick para o Chalk
+Name[pt_BR]=Filtro de importação Magick para o Chalk
+Name[ru]=Фильтр импорта рисунков Magick в Chalk
+Name[se]=Chalk Magick-sisafievrridansilli
+Name[sk]=Magick filter pre import do Chalk
+Name[sl]=Uvozni filter Magick za Krito
+Name[sr]=Chalk-ин филтер за увоз из Magick-а
+Name[sr@Latn]=Chalk-in filter za uvoz iz Magick-a
+Name[sv]=Chalk Magick-importfilter
+Name[ta]=Chalk மாயk இறக்குமதி வடிகட்டி
+Name[tg]=Филтри Воридоти Chalk Magick
+Name[tr]=Chalk Magick Alma Filtresi
+Name[uk]=Фільтр імпорту Magick для Chalk
+Name[uz]=Chalk Magick import filteri
+Name[uz@cyrillic]=Chalk Magick импорт филтери
+Name[zh_CN]=Chalk Magick 导入过滤器
+Name[zh_TW]=Chalk Magick 匯入過濾程式
+X-KDE-Export=application/x-chalk
+X-KDE-Import=image/x-xcf-gimp,image/gif,image/cgm,image/x-bmp,image/x-ico,image/x-pcx,image/x-portable-pixmap,image/x-targa,image/x-xbm,image/x-xcf,image/x-xpm,image/x-vnd.adobe.photoshop,image/x-rgb,image/x-eps
+X-KDE-Weight=1
+X-KDE-Library=libchalkgmagickimport
+ServiceTypes=KOfficeFilter
diff --git a/filters/chalk/gmagick/configure.in.bot b/filters/chalk/gmagick/configure.in.bot
new file mode 100644
index 00000000..0f05276f
--- /dev/null
+++ b/filters/chalk/gmagick/configure.in.bot
@@ -0,0 +1,23 @@
+if test -z "$LIBGMAGICK_LIBS" -a -z "$LIBMAGICK_LIBS"; then
+ echo ""
+ echo "You're missing GraphicsMagick (>=1.1.7). chalk's GraphicsMagick import/export"
+ echo "filter will not be compiled. You can download GraphicsMagick from"
+ echo "http://www.graphicsmagick.org/. The GraphicsMagick filter allows chalk to"
+ echo "read and write XCF, PSD, GIF, BMP, and many other image formats."
+ echo ""
+ echo "If you have problems compiling GraphicsMagick, please try configuring it using"
+ echo "the --without-magick-plus-plus flag, the C++ API isn't needed for chalk."
+ echo ""
+ all_tests=bad
+ AC_DEFINE([include_imagemagick_filter],"",[don't use magick filter])
+fi
+
+if test -z "$LIBGMAGICK_LIBS" -a ! -z "$LIBMAGICK_LIBS"; then
+
+ echo ""
+ echo "You're missing GraphicsMagick (>=1.1.7). chalk's GraphicsMagick import/export"
+ echo "filter will not be compiled. But ImageMagick was found, which mean that chalk"
+ echo "will be able to read and write XCF, PSD, GIF, BMP, and many other image formats."
+ echo "But the ImageMagick filter is deprecated and we strongly advise you to install"
+ echo "GraphicsMagick either from your distribution or from http://www.graphicsmagick.org/"
+fi
diff --git a/filters/chalk/gmagick/kis_image_magick_converter.cc b/filters/chalk/gmagick/kis_image_magick_converter.cc
new file mode 100644
index 00000000..a0545569
--- /dev/null
+++ b/filters/chalk/gmagick/kis_image_magick_converter.cc
@@ -0,0 +1,1142 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ * Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <magick/api.h>
+
+#include <tqfile.h>
+#include <tqfileinfo.h>
+#include <tqstring.h>
+
+#include <kdeversion.h>
+#include <kdebug.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kurl.h>
+#include <kio/netaccess.h>
+
+#include <tqcolor.h>
+
+#include "kis_types.h"
+#include "kis_global.h"
+#include "kis_doc.h"
+#include "kis_image.h"
+#include "kis_layer.h"
+#include "kis_undo_adapter.h"
+#include "kis_image_magick_converter.h"
+#include "kis_meta_registry.h"
+#include "kis_colorspace_factory_registry.h"
+#include "kis_iterators_pixel.h"
+#include "kis_colorspace.h"
+#include "kis_profile.h"
+#include "kis_annotation.h"
+#include "kis_paint_layer.h"
+#include "kis_group_layer.h"
+#include "kis_paint_device.h"
+
+#include "../../../config.h"
+
+namespace {
+
+ const TQ_UINT8 PIXEL_BLUE = 0;
+ const TQ_UINT8 PIXEL_GREEN = 1;
+ const TQ_UINT8 PIXEL_RED = 2;
+ const TQ_UINT8 PIXEL_ALPHA = 3;
+
+ static const TQ_UINT8 PIXEL_CYAN = 0;
+ static const TQ_UINT8 PIXEL_MAGENTA = 1;
+ static const TQ_UINT8 PIXEL_YELLOW = 2;
+ static const TQ_UINT8 PIXEL_BLACK = 3;
+ static const TQ_UINT8 PIXEL_CMYK_ALPHA = 4;
+
+ static const TQ_UINT8 PIXEL_GRAY = 0;
+ static const TQ_UINT8 PIXEL_GRAY_ALPHA = 1;
+
+ /**
+ * Make this more flexible -- although... ImageMagick
+ * isn't that flexible either.
+ */
+ TQString getColorSpaceName(ColorspaceType type, unsigned long imageDepth = 8)
+ {
+
+ if (type == GRAYColorspace) {
+ if (imageDepth == 8)
+ return "GRAYA";
+ else if ( imageDepth == 16 )
+ return "GRAYA16" ;
+ }
+ else if (type == CMYKColorspace) {
+ if (imageDepth == 8)
+ return "CMYK";
+ else if ( imageDepth == 16 ) {
+ return "CMYK16";
+ }
+ }
+ else if (type == LABColorspace) {
+ kdDebug(41008) << "Lab!\n";
+ return "LABA";
+ }
+ else if (type == RGBColorspace || type == sRGBColorspace || type == TransparentColorspace) {
+ if (imageDepth == 8)
+ return "RGBA";
+ else if (imageDepth == 16)
+ return "RGBA16";
+ }
+ return "";
+
+ }
+
+ ColorspaceType getColorTypeforColorSpace( KisColorSpace * cs )
+ {
+ if ( cs->id() == KisID("GRAYA") || cs->id() == KisID("GRAYA16") ) return GRAYColorspace;
+ if ( cs->id() == KisID("RGBA") || cs->id() == KisID("RGBA16") ) return RGBColorspace;
+ if ( cs->id() == KisID("CMYK") || cs->id() == KisID("CMYK16") ) return CMYKColorspace;
+ if ( cs->id() == KisID("LABA") ) return LABColorspace;
+
+ kdDebug(41008) << "Cannot export images in " + cs->id().name() + " yet.\n";
+ return RGBColorspace;
+
+ }
+
+ KisProfile * getProfileForProfileInfo(const Image * image)
+ {
+ size_t length;
+
+ const unsigned char * profiledata = GetImageProfile(image, "ICM", &length);
+ if( profiledata == NULL )
+ return 0;
+ TQByteArray rawdata;
+ rawdata.resize(length);
+ memcpy(rawdata.data(), profiledata, length);
+
+ KisProfile* p = new KisProfile(rawdata);
+ return p;
+
+#if 0
+ return 0;
+
+ if (image->profiles == NULL)
+ return 0;
+
+ const char *name;
+ const StringInfo *profile;
+
+ KisProfile * p = 0;
+
+ ResetImageProfileIterator(image);
+ for (name = GetNextImageProfile(image); name != (char *) NULL; )
+ {
+ profile = GetImageProfile(image, name);
+ if (profile == (StringInfo *) NULL)
+ continue;
+
+ // XXX: Hardcoded for icc type -- is that correct for us?
+ if (TQString::compare(name, "icc") == 0) {
+ TQByteArray rawdata;
+ rawdata.resize(profile->length);
+ memcpy(rawdata.data(), profile->datum, profile->length);
+
+ p = new KisProfile(rawdata);
+ if (p == 0)
+ return 0;
+ }
+ name = GetNextImageProfile(image);
+ }
+ return p;
+#endif
+ }
+
+ void setAnnotationsForImage(const Image * src, KisImageSP image)
+ {
+ size_t length;
+
+ const unsigned char * profiledata = GetImageProfile(src, "IPTC", &length);
+ if( profiledata != NULL )
+ {
+ TQByteArray rawdata;
+ rawdata.resize(length);
+ memcpy(rawdata.data(), profiledata, length);
+
+ KisAnnotation* annotation = new KisAnnotation(TQString("IPTC"), "", rawdata);
+ Q_CHECK_PTR(annotation);
+
+ image -> addAnnotation(annotation);
+ }
+ for(int i = 0; i < src->generic_profiles; i++)
+ {
+ TQByteArray rawdata;
+ rawdata.resize(length);
+ memcpy(rawdata.data(), src->generic_profile[i].info, src->generic_profile[i].length);
+
+ KisAnnotation* annotation = new KisAnnotation(TQString(src->generic_profile[i].name), "", rawdata);
+ Q_CHECK_PTR(annotation);
+
+ image -> addAnnotation(annotation);
+ }
+
+ const ImageAttribute* imgAttr = GetImageAttribute(src, NULL);
+ while(imgAttr)
+ {
+ TQByteArray rawdata;
+ int len = strlen(imgAttr -> value) + 1;
+ rawdata.resize(len);
+ memcpy(rawdata.data(), imgAttr -> value, len);
+
+ KisAnnotation* annotation = new KisAnnotation( TQString("chalk_attribute:%1").tqarg(TQString(imgAttr -> key)), "", rawdata );
+ Q_CHECK_PTR(annotation);
+
+ image -> addAnnotation(annotation);
+
+ imgAttr = imgAttr->next;
+ }
+#if 0
+ return;
+ if (src->profiles == NULL)
+ return;
+
+ const char *name = 0;
+ const StringInfo *profile;
+ KisAnnotation* annotation = 0;
+
+ // Profiles and so
+ ResetImageProfileIterator(src);
+ while((name = GetNextImageProfile(src))) {
+ profile = GetImageProfile(src, name);
+ if (profile == (StringInfo *) NULL)
+ continue;
+
+ // XXX: icc will be written seperately?
+ if (TQString::compare(name, "icc") == 0)
+ continue;
+
+ TQByteArray rawdata;
+ rawdata.resize(profile->length);
+ memcpy(rawdata.data(), profile->datum, profile->length);
+
+ annotation = new KisAnnotation(TQString(name), "", rawdata);
+ Q_CHECK_PTR(annotation);
+
+ image -> addAnnotation(annotation);
+ }
+
+ // Attributes, since we have no hint on if this is an attribute or a profile
+ // annotation, we prefix it with 'chalk_attribute:'. XXX This needs to be rethought!
+ // The joys of imagemagick. From at version 6.2.1 (dfaure has 6.2.0 and confirms the
+ // old way of doing things) they changed the src -> attributes
+ // to void* and require us to use the iterator functions. So we #if around that, *sigh*
+#if MagickLibVersion >= 0x621
+ const ImageAttribute * attr;
+ ResetImageAttributeIterator(src);
+ while ( (attr = GetNextImageAttribute(src)) ) {
+#else
+ ImageAttribute * attr = src -> attributes;
+ while (attr) {
+#endif
+ TQByteArray rawdata;
+ int len = strlen(attr -> value) + 1;
+ rawdata.resize(len);
+ memcpy(rawdata.data(), attr -> value, len);
+
+ annotation = new KisAnnotation(
+ TQString("chalk_attribute:%1").tqarg(TQString(attr -> key)), "", rawdata);
+ Q_CHECK_PTR(annotation);
+
+ image -> addAnnotation(annotation);
+#if MagickLibVersion < 0x620
+ attr = attr -> next;
+#endif
+ }
+
+#endif
+ }
+ }
+
+ void exportAnnotationsForImage(Image * dst, vKisAnnotationSP_it& it, vKisAnnotationSP_it& annotationsEnd)
+ {
+ while(it != annotationsEnd) {
+ if (!(*it) || (*it) -> type() == TQString()) {
+ kdDebug(41008) << "Warning: empty annotation" << endl;
+ ++it;
+ continue;
+ }
+
+ kdDebug(41008) << "Trying to store annotation of type " << (*it) -> type() << " of size " << (*it) -> annotation() . size() << endl;
+
+ if ((*it) -> type().startsWith("chalk_attribute:")) { // Attribute
+ if (!SetImageAttribute(dst,
+ (*it) -> type().mid(strlen("chalk_attribute:")).ascii(),
+ (*it) -> annotation() . data()) ) {
+ kdDebug(41008) << "Storing of attribute " << (*it) -> type() << "failed!\n";
+ }
+ } else { // Profile
+ unsigned char * profiledata = new unsigned char[(*it) -> annotation() . size()];
+ memcpy( profiledata, (*it) -> annotation() . data(), (*it) -> annotation() . size());
+ if (!ProfileImage(dst, (*it) -> type().ascii(),
+ profiledata, (*it) -> annotation() . size(), MagickFalse)) {
+ kdDebug(41008) << "Storing failed!" << endl;
+ }
+ }
+ ++it;
+ }
+ }
+
+
+ void InitGlobalMagick()
+ {
+ static bool init = false;
+
+ if (!init) {
+ KApplication *app = KApplication::kApplication();
+
+ InitializeMagick(*app -> argv());
+ atexit(DestroyMagick);
+ init = true;
+ }
+ }
+
+ /*
+ * ImageMagick progress monitor callback. Unfortunately it doesn't support passing in some user
+ * data which complicates things quite a bit. The plan was to allow the user start multiple
+ * import/scans if he/she so wished. However, without passing user data it's not possible to tell
+ * on which task we have made progress on.
+ *
+ * Additionally, ImageMagick is thread-safe, not re-entrant... i.e. IM does not relinquish held
+ * locks when calling user defined callbacks, this means that the same thread going back into IM
+ * would deadlock since it would try to acquire locks it already holds.
+ */
+#if 0
+ MagickBooleanType monitor(const char *text, const ExtendedSignedIntegralType, const ExtendedUnsignedIntegralType, ExceptionInfo *)
+ {
+ KApplication *app = KApplication::kApplication();
+
+ Q_ASSERT(app);
+
+ if (app -> hasPendingEvents())
+ app -> processEvents();
+
+ printf("%s\n", text);
+ return MagickTrue;
+ }
+#else
+ unsigned int monitor(const char *text, const ExtendedSignedIntegralType, const ExtendedUnsignedIntegralType, ExceptionInfo *)
+ {
+ KApplication *app = KApplication::kApplication();
+
+ Q_ASSERT(app);
+
+ if (app -> hasPendingEvents())
+ app -> processEvents();
+
+ printf("%s\n", text);
+ return true;
+ }
+#endif
+
+
+
+KisImageMagickConverter::KisImageMagickConverter(KisDoc *doc, KisUndoAdapter *adapter)
+{
+ InitGlobalMagick();
+ init(doc, adapter);
+ SetMonitorHandler(monitor);
+ m_stop = false;
+}
+
+KisImageMagickConverter::~KisImageMagickConverter()
+{
+}
+
+KisImageBuilder_Result KisImageMagickConverter::decode(const KURL& uri, bool isBlob)
+{
+ Image *image;
+ Image *images;
+ ExceptionInfo ei;
+ ImageInfo *ii;
+
+ if (m_stop) {
+ m_img = 0;
+ return KisImageBuilder_RESULT_INTR;
+ }
+
+ GetExceptionInfo(&ei);
+ ii = CloneImageInfo(0);
+
+ if (isBlob) {
+
+ // TODO : Test. Does BlobToImage even work?
+ Q_ASSERT(uri.isEmpty());
+ images = BlobToImage(ii, &m_data[0], m_data.size(), &ei);
+ } else {
+
+ qstrncpy(ii -> filename, TQFile::encodeName(uri.path()), MaxTextExtent - 1);
+
+ if (ii -> filename[MaxTextExtent - 1]) {
+ emit notifyProgressError();
+ return KisImageBuilder_RESULT_PATH;
+ }
+
+ images = ReadImage(ii, &ei);
+
+ }
+
+ if (ei.severity != UndefinedException)
+ {
+ CatchException(&ei);
+ kdDebug(41008) << "Exceptions happen when loading" << endl;
+ return KisImageBuilder_RESULT_FAILURE;
+ }
+
+
+ if (images == 0) {
+ DestroyImageInfo(ii);
+ DestroyExceptionInfo(&ei);
+ emit notifyProgressError();
+ return KisImageBuilder_RESULT_FAILURE;
+ }
+
+ emit notifyProgressStage(i18n("Importing..."), 0);
+
+ m_img = 0;
+
+ while ((image = RemoveFirstImageFromList(&images))) {
+ if(image->rows == 0 or image->columns == 0) return KisImageBuilder_RESULT_FAILURE;
+ ViewInfo *vi = OpenCacheView(image);
+
+ // Determine image depth -- for now, all channels of an imported image are of the same depth
+ unsigned long imageDepth = image->depth;
+ kdDebug(41008) << "Image depth: " << imageDepth << "\n";
+
+ TQString csName;
+ KisColorSpace * cs = 0;
+ ColorspaceType colorspaceType;
+
+ // Determine image type -- rgb, grayscale or cmyk
+ if (GetImageType(image, &ei) == GrayscaleType || GetImageType(image, &ei) == GrayscaleMatteType) {
+ if (imageDepth == 8)
+ csName = "GRAYA";
+ else if ( imageDepth == 16 )
+ csName = "GRAYA16" ;
+ colorspaceType = GRAYColorspace;
+ }
+ else {
+ colorspaceType = image->colorspace;
+ csName = getColorSpaceName(image -> colorspace, imageDepth);
+ }
+
+ kdDebug(41008) << "image has " << csName << " colorspace\n";
+
+ KisProfile * profile = getProfileForProfileInfo(image);
+ if (profile)
+ {
+ kdDebug(41008) << "image has embedded profile: " << profile -> productName() << "\n";
+ cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(csName, profile);
+ }
+ else
+ cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName,""),"");
+
+ if (!cs) {
+ kdDebug(41008) << "Chalk does not support colorspace " << image -> colorspace << "\n";
+ CloseCacheView(vi);
+ DestroyImage(image);
+ DestroyExceptionInfo(&ei);
+ DestroyImageList(images);
+ DestroyImageInfo(ii);
+ emit notifyProgressError();
+ return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
+ }
+
+ if( ! m_img) {
+ m_img = new KisImage(m_doc->undoAdapter(), image -> columns, image -> rows, cs, "built image");
+ Q_CHECK_PTR(m_img);
+ m_img->blockSignals(true); // Don't send out signals while we're building the image
+
+ // XXX I'm assuming seperate layers won't have other profile things like EXIF
+ setAnnotationsForImage(image, m_img);
+ }
+
+ if (image -> columns && image -> rows) {
+
+ // Opacity (set by the photoshop import filter)
+ TQ_UINT8 opacity = OPACITY_OPAQUE;
+ const ImageAttribute * attr = GetImageAttribute(image, "[layer-opacity]");
+ if (attr != 0) {
+ opacity = TQ_UINT8_MAX - Downscale(TQString(attr->value).toInt());
+ }
+
+ KisPaintLayerSP layer = 0;
+
+ attr = GetImageAttribute(image, "[layer-name]");
+ if (attr != 0) {
+ layer = new KisPaintLayer(m_img, attr->value, opacity);
+ }
+ else {
+ layer = new KisPaintLayer(m_img, m_img -> nextLayerName(), opacity);
+ }
+
+ Q_ASSERT(layer);
+
+ // Layerlocation (set by the photoshop import filter)
+ TQ_INT32 x_offset = 0;
+ TQ_INT32 y_offset = 0;
+
+ attr = GetImageAttribute(image, "[layer-xpos]");
+ if (attr != 0) {
+ x_offset = TQString(attr->value).toInt();
+ }
+
+ attr = GetImageAttribute(image, "[layer-ypos]");
+ if (attr != 0) {
+ y_offset = TQString(attr->value).toInt();
+ }
+
+
+ for (TQ_UINT32 y = 0; y < image->rows; y ++)
+ {
+ const PixelPacket *pp = AcquireCacheView(vi, 0, y, image->columns, 1, &ei);
+
+ if(!pp)
+ {
+ CloseCacheView(vi);
+ DestroyImageList(images);
+ DestroyImageInfo(ii);
+ DestroyExceptionInfo(&ei);
+ emit notifyProgressError();
+ return KisImageBuilder_RESULT_FAILURE;
+ }
+
+ IndexPacket * indexes = GetCacheViewIndexes(vi);
+
+ KisHLineIteratorPixel hiter = layer->paintDevice()->createHLineIterator(0, y, image->columns, true);
+
+ if (colorspaceType== CMYKColorspace) {
+ if (imageDepth == 8) {
+ int x = 0;
+ while (!hiter.isDone())
+ {
+ TQ_UINT8 *ptr= hiter.rawData();
+ *(ptr++) = Downscale(pp->red); // cyan
+ *(ptr++) = Downscale(pp->green); // magenta
+ *(ptr++) = Downscale(pp->blue); // yellow
+ *(ptr++) = Downscale(indexes[x]); // Black
+// XXX: Warning! This ifdef messes up the paren matching big-time!
+#ifdef HAVE_MAGICK6
+ if (image->matte != MagickFalse) {
+#else
+ if (image->matte == true) {
+#endif
+ *(ptr++) = OPACITY_OPAQUE - Downscale(pp->opacity);
+ }
+ else {
+ *(ptr++) = OPACITY_OPAQUE;
+ }
+ ++x;
+ pp++;
+ ++hiter;
+ }
+ }
+ }
+ else if (colorspaceType == LABColorspace) {
+ while(! hiter.isDone())
+ {
+ TQ_UINT16 *ptr = reinterpret_cast<TQ_UINT16 *>(hiter.rawData());
+
+ *(ptr++) = ScaleQuantumToShort(pp->red);
+ *(ptr++) = ScaleQuantumToShort(pp->green);
+ *(ptr++) = ScaleQuantumToShort(pp->blue);
+ *(ptr++) = 65535/*OPACITY_OPAQUE*/ - ScaleQuantumToShort(pp->opacity);
+
+ pp++;
+ ++hiter;
+ }
+ }
+ else if (colorspaceType == RGBColorspace ||
+ colorspaceType == sRGBColorspace ||
+ colorspaceType == TransparentColorspace)
+ {
+ if (imageDepth == 8) {
+ while(! hiter.isDone())
+ {
+ TQ_UINT8 *ptr= hiter.rawData();
+ // XXX: not colorstrategy and bitdepth independent
+ *(ptr++) = Downscale(pp->blue);
+ *(ptr++) = Downscale(pp->green);
+ *(ptr++) = Downscale(pp->red);
+ *(ptr++) = OPACITY_OPAQUE - Downscale(pp->opacity);
+
+ pp++;
+ ++hiter;
+ }
+ }
+ else if (imageDepth == 16) {
+ while(! hiter.isDone())
+ {
+ TQ_UINT16 *ptr = reinterpret_cast<TQ_UINT16 *>(hiter.rawData());
+ // XXX: not colorstrategy independent
+ *(ptr++) = ScaleQuantumToShort(pp->blue);
+ *(ptr++) = ScaleQuantumToShort(pp->green);
+ *(ptr++) = ScaleQuantumToShort(pp->red);
+ *(ptr++) = 65535/*OPACITY_OPAQUE*/ - ScaleQuantumToShort(pp->opacity);
+
+ pp++;
+ ++hiter;
+ }
+ }
+ }
+ else if ( colorspaceType == GRAYColorspace) {
+ if (imageDepth == 8) {
+ while(! hiter.isDone())
+ {
+ TQ_UINT8 *ptr= hiter.rawData();
+ // XXX: not colorstrategy and bitdepth independent
+ *(ptr++) = Downscale(pp->blue);
+ *(ptr++) = OPACITY_OPAQUE - Downscale(pp->opacity);
+
+ pp++;
+ ++hiter;
+ }
+ }
+ else if (imageDepth == 16) {
+ while(! hiter.isDone())
+ {
+ TQ_UINT16 *ptr = reinterpret_cast<TQ_UINT16 *>(hiter.rawData());
+ // XXX: not colorstrategy independent
+ *(ptr++) = ScaleQuantumToShort(pp->blue);
+ *(ptr++) = 65535/*OPACITY_OPAQUE*/ - ScaleQuantumToShort(pp->opacity);
+
+ pp++;
+ ++hiter;
+ }
+ }
+ }
+
+ emit notifyProgress(y * 100 / image->rows);
+
+ if (m_stop) {
+ CloseCacheView(vi);
+ DestroyImage(image);
+ DestroyImageList(images);
+ DestroyImageInfo(ii);
+ DestroyExceptionInfo(&ei);
+ m_img = 0;
+ return KisImageBuilder_RESULT_INTR;
+ }
+ }
+ m_img->addLayer(layer.data(), m_img->rootLayer());
+ layer->paintDevice()->move(x_offset, y_offset);
+ }
+
+ emit notifyProgressDone();
+ CloseCacheView(vi);
+ DestroyImage(image);
+ }
+
+ emit notifyProgressDone();
+ DestroyImageList(images);
+ DestroyImageInfo(ii);
+ DestroyExceptionInfo(&ei);
+ return KisImageBuilder_RESULT_OK;
+ }
+
+ KisImageBuilder_Result KisImageMagickConverter::buildImage(const KURL& uri)
+ {
+ if (uri.isEmpty())
+ return KisImageBuilder_RESULT_NO_URI;
+
+ if (!KIO::NetAccess::exists(uri, false, tqApp -> mainWidget())) {
+ return KisImageBuilder_RESULT_NOT_EXIST;
+ }
+
+ KisImageBuilder_Result result = KisImageBuilder_RESULT_FAILURE;
+ TQString tmpFile;
+
+ if (KIO::NetAccess::download(uri, tmpFile, tqApp -> mainWidget())) {
+ KURL uriTF;
+ uriTF.setPath( tmpFile );
+ result = decode(uriTF, false);
+ KIO::NetAccess::removeTempFile(tmpFile);
+ }
+
+ return result;
+ }
+
+
+ KisImageSP KisImageMagickConverter::image()
+ {
+ return m_img;
+ }
+
+ void KisImageMagickConverter::init(KisDoc *doc, KisUndoAdapter *adapter)
+ {
+ m_doc = doc;
+ m_adapter = adapter;
+ m_job = 0;
+ }
+
+ KisImageBuilder_Result KisImageMagickConverter::buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd)
+ {
+ Image *image;
+ ExceptionInfo ei;
+ ImageInfo *ii;
+
+ if (!layer)
+ return KisImageBuilder_RESULT_INVALID_ARG;
+
+ KisImageSP img = layer->image();
+ if (!img)
+ return KisImageBuilder_RESULT_EMPTY;
+
+ if (uri.isEmpty())
+ return KisImageBuilder_RESULT_NO_URI;
+
+ if (!uri.isLocalFile())
+ return KisImageBuilder_RESULT_NOT_LOCAL;
+
+
+ TQ_UINT32 layerBytesPerChannel = layer->paintDevice()->pixelSize() / layer->paintDevice()->nChannels();
+
+ GetExceptionInfo(&ei);
+
+ ii = CloneImageInfo(0);
+
+ qstrncpy(ii -> filename, TQFile::encodeName(uri.path()), MaxTextExtent - 1);
+
+ if (ii -> filename[MaxTextExtent - 1]) {
+ emit notifyProgressError();
+ return KisImageBuilder_RESULT_PATH;
+ }
+
+ if (!img -> width() || !img -> height())
+ return KisImageBuilder_RESULT_EMPTY;
+
+ if (layerBytesPerChannel < 2) {
+ ii->depth = 8;
+ }
+ else {
+ ii->depth = 16;
+ }
+
+ ii->colorspace = getColorTypeforColorSpace(layer->paintDevice()->colorSpace());
+
+ image = AllocateImage(ii);
+// SetImageColorspace(image, ii->colorspace);
+ image -> columns = img -> width();
+ image -> rows = img -> height();
+
+ kdDebug(41008) << "Saving with colorspace " << image->colorspace << ", (" << layer->paintDevice()->colorSpace()->id().name() << ")\n";
+ kdDebug(41008) << "IM Image thinks it has depth: " << image->depth << "\n";
+
+#ifdef HAVE_MAGICK6
+ // if ( layer-> hasAlpha() )
+ image -> matte = MagickTrue;
+ // else
+ // image -> matte = MagickFalse;
+#else
+ // image -> matte = layer -> hasAlpha();
+ image -> matte = true;
+#endif
+
+ TQ_INT32 y, height, width;
+
+ height = img -> height();
+ width = img -> width();
+
+ bool alpha = true;
+ TQString ext = TQFileInfo(TQFile::encodeName(uri.path())).extension(false).upper();
+ if (ext == "BMP") {
+ alpha = false;
+ qstrncpy(ii->magick, "BMP2", MaxTextExtent - 1);
+ }
+ else if (ext == "RGB") {
+ qstrncpy(ii->magick, "SGI", MaxTextExtent - 1);
+ }
+
+ for (y = 0; y < height; y++) {
+
+ // Allocate pixels for this scanline
+ PixelPacket * pp = SetImagePixels(image, 0, y, width, 1);
+
+ if (!pp) {
+ DestroyExceptionInfo(&ei);
+ DestroyImage(image);
+ emit notifyProgressError();
+ return KisImageBuilder_RESULT_FAILURE;
+
+ }
+
+ KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, y, width, false);
+ if (alpha)
+ SetImageType(image, TrueColorMatteType);
+ else
+ SetImageType(image, TrueColorType);
+
+ if (image->colorspace== CMYKColorspace) {
+
+ IndexPacket * indexes = GetIndexes(image);
+ int x = 0;
+ if (layerBytesPerChannel == 2) {
+ while (!it.isDone()) {
+
+ const TQ_UINT16 *d = reinterpret_cast<const TQ_UINT16 *>(it.rawData());
+ pp -> red = ScaleShortToQuantum(d[PIXEL_CYAN]);
+ pp -> green = ScaleShortToQuantum(d[PIXEL_MAGENTA]);
+ pp -> blue = ScaleShortToQuantum(d[PIXEL_YELLOW]);
+ if (alpha)
+ pp -> opacity = ScaleShortToQuantum(65535/*OPACITY_OPAQUE*/ - d[PIXEL_CMYK_ALPHA]);
+ indexes[x] = ScaleShortToQuantum(d[PIXEL_BLACK]);
+ x++;
+ pp++;
+ ++it;
+ }
+ }
+ else {
+ while (!it.isDone()) {
+
+ TQ_UINT8 * d = it.rawData();
+ pp -> red = Upscale(d[PIXEL_CYAN]);
+ pp -> green = Upscale(d[PIXEL_MAGENTA]);
+ pp -> blue = Upscale(d[PIXEL_YELLOW]);
+ if (alpha)
+ pp -> opacity = Upscale(OPACITY_OPAQUE - d[PIXEL_CMYK_ALPHA]);
+
+ indexes[x]= Upscale(d[PIXEL_BLACK]);
+
+ x++;
+ pp++;
+ ++it;
+ }
+ }
+ }
+ else if (image->colorspace== RGBColorspace ||
+ image->colorspace == sRGBColorspace ||
+ image->colorspace == TransparentColorspace)
+ {
+ if (layerBytesPerChannel == 2) {
+ while (!it.isDone()) {
+
+ const TQ_UINT16 *d = reinterpret_cast<const TQ_UINT16 *>(it.rawData());
+ pp -> red = ScaleShortToQuantum(d[PIXEL_RED]);
+ pp -> green = ScaleShortToQuantum(d[PIXEL_GREEN]);
+ pp -> blue = ScaleShortToQuantum(d[PIXEL_BLUE]);
+ if (alpha)
+ pp -> opacity = ScaleShortToQuantum(65535/*OPACITY_OPAQUE*/ - d[PIXEL_ALPHA]);
+
+ pp++;
+ ++it;
+ }
+ }
+ else {
+ while (!it.isDone()) {
+
+ TQ_UINT8 * d = it.rawData();
+ pp -> red = Upscale(d[PIXEL_RED]);
+ pp -> green = Upscale(d[PIXEL_GREEN]);
+ pp -> blue = Upscale(d[PIXEL_BLUE]);
+ if (alpha)
+ pp -> opacity = Upscale(OPACITY_OPAQUE - d[PIXEL_ALPHA]);
+
+ pp++;
+ ++it;
+ }
+ }
+ }
+ else if (image->colorspace == GRAYColorspace)
+ {
+ SetImageType(image, GrayscaleMatteType);
+ if (layerBytesPerChannel == 2) {
+ while (!it.isDone()) {
+
+ const TQ_UINT16 *d = reinterpret_cast<const TQ_UINT16 *>(it.rawData());
+ pp -> red = ScaleShortToQuantum(d[PIXEL_GRAY]);
+ pp -> green = ScaleShortToQuantum(d[PIXEL_GRAY]);
+ pp -> blue = ScaleShortToQuantum(d[PIXEL_GRAY]);
+ if (alpha)
+ pp -> opacity = ScaleShortToQuantum(65535/*OPACITY_OPAQUE*/ - d[PIXEL_GRAY_ALPHA]);
+
+ pp++;
+ ++it;
+ }
+ }
+ else {
+ while (!it.isDone()) {
+ TQ_UINT8 * d = it.rawData();
+ pp -> red = Upscale(d[PIXEL_GRAY]);
+ pp -> green = Upscale(d[PIXEL_GRAY]);
+ pp -> blue = Upscale(d[PIXEL_GRAY]);
+ if (alpha)
+ pp -> opacity = Upscale(OPACITY_OPAQUE - d[PIXEL_GRAY_ALPHA]);
+
+ pp++;
+ ++it;
+ }
+ }
+ }
+ else {
+ kdDebug(41008) << "Unsupported image format\n";
+ return KisImageBuilder_RESULT_INVALID_ARG;
+ }
+
+ emit notifyProgressStage(i18n("Saving..."), y * 100 / height);
+
+#ifdef HAVE_MAGICK6
+ if (SyncImagePixels(image) == MagickFalse)
+ kdDebug(41008) << "Syncing pixels failed\n";
+#else
+ if (!SyncImagePixels(image))
+ kdDebug(41008) << "Syncing pixels failed\n";
+#endif
+ }
+
+ // set the annotations
+ exportAnnotationsForImage(image, annotationsStart, annotationsEnd);
+
+ // XXX: Write to a temp file, then have Chalk use KIO to copy temp
+ // image to remote location.
+
+ WriteImage(ii, image);
+ DestroyExceptionInfo(&ei);
+ DestroyImage(image);
+ emit notifyProgressDone();
+ return KisImageBuilder_RESULT_OK;
+ }
+
+ void KisImageMagickConverter::ioData(KIO::Job *job, const TQByteArray& data)
+ {
+ if (data.isNull() || data.isEmpty()) {
+ emit notifyProgressStage(i18n("Loading..."), 0);
+ return;
+ }
+
+ if (m_data.empty()) {
+ Image *image;
+ ImageInfo *ii;
+ ExceptionInfo ei;
+
+ ii = CloneImageInfo(0);
+ GetExceptionInfo(&ei);
+ image = PingBlob(ii, data.data(), data.size(), &ei);
+
+ if (image == 0 || ei.severity == BlobError) {
+ DestroyExceptionInfo(&ei);
+ DestroyImageInfo(ii);
+ job -> kill();
+ emit notifyProgressError();
+ return;
+ }
+
+ DestroyImage(image);
+ DestroyExceptionInfo(&ei);
+ DestroyImageInfo(ii);
+ emit notifyProgressStage(i18n("Loading..."), 0);
+ }
+
+ Q_ASSERT(data.size() + m_data.size() <= m_size);
+ memcpy(&m_data[m_data.size()], data.data(), data.count());
+ m_data.resize(m_data.size() + data.count());
+ emit notifyProgressStage(i18n("Loading..."), m_data.size() * 100 / m_size);
+
+ if (m_stop)
+ job -> kill();
+ }
+
+ void KisImageMagickConverter::ioResult(KIO::Job *job)
+ {
+ m_job = 0;
+
+ if (job -> error())
+ emit notifyProgressError();
+
+ decode(KURL(), true);
+ }
+
+ void KisImageMagickConverter::ioTotalSize(KIO::Job * /*job*/, KIO::filesize_t size)
+ {
+ m_size = size;
+ m_data.reserve(size);
+ emit notifyProgressStage(i18n("Loading..."), 0);
+ }
+
+ void KisImageMagickConverter::cancel()
+ {
+ m_stop = true;
+ }
+
+ /**
+ * @name readFilters
+ * @return Provide a list of file formats the application can read.
+ */
+ TQString KisImageMagickConverter::readFilters()
+ {
+ TQString s;
+ TQString all;
+ TQString name;
+ TQString description;
+ unsigned long matches;
+
+/*#ifdef HAVE_MAGICK6
+#ifdef HAVE_OLD_GETMAGICKINFOLIST
+ const MagickInfo **mi;
+ mi = GetMagickInfoList("*", &matches);
+#else // HAVE_OLD_GETMAGICKINFOLIST
+ ExceptionInfo ei;
+ GetExceptionInfo(&ei);
+ const MagickInfo **mi;
+ mi = GetMagickInfoList("*", &matches, &ei);
+ DestroyExceptionInfo(&ei);
+#endif // HAVE_OLD_GETMAGICKINFOLIST
+#else // HAVE_MAGICK6*/
+ const MagickInfo *mi;
+ ExceptionInfo ei;
+ GetExceptionInfo(&ei);
+ mi = GetMagickInfo("*", &ei);
+ DestroyExceptionInfo(&ei);
+// #endif // HAVE_MAGICK6
+
+ if (!mi)
+ return s;
+
+/*#ifdef HAVE_MAGICK6
+ for (unsigned long i = 0; i < matches; i++) {
+ const MagickInfo *info = mi[i];
+ if (info -> stealth)
+ continue;
+
+ if (info -> decoder) {
+ name = info -> name;
+ description = info -> description;
+ kdDebug(41008) << "Found import filter for: " << name << "\n";
+
+ if (!description.isEmpty() && !description.tqcontains('/')) {
+ all += "*." + name.lower() + " *." + name + " ";
+ s += "*." + name.lower() + " *." + name + "|";
+ s += i18n(description.utf8());
+ s += "\n";
+ }
+ }
+ }
+#else*/
+ for (; mi; mi = reinterpret_cast<const MagickInfo*>(mi -> next)) {
+ if (mi -> stealth)
+ continue;
+ if (mi -> decoder) {
+ name = mi -> name;
+ description = mi -> description;
+ kdDebug(41008) << "Found import filter for: " << name << "\n";
+
+ if (!description.isEmpty() && !description.tqcontains('/')) {
+ all += "*." + name.lower() + " *." + name + " ";
+ s += "*." + name.lower() + " *." + name + "|";
+ s += i18n(description.utf8());
+ s += "\n";
+ }
+ }
+ }
+// #endif
+
+ all += "|" + i18n("All Images");
+ all += "\n";
+
+ return all + s;
+ }
+
+ TQString KisImageMagickConverter::writeFilters()
+ {
+ TQString s;
+ TQString all;
+ TQString name;
+ TQString description;
+ unsigned long matches;
+
+/*#ifdef HAVE_MAGICK6
+#ifdef HAVE_OLD_GETMAGICKINFOLIST
+ const MagickInfo **mi;
+ mi = GetMagickInfoList("*", &matches);
+#else // HAVE_OLD_GETMAGICKINFOLIST
+ ExceptionInfo ei;
+ GetExceptionInfo(&ei);
+ const MagickInfo **mi;
+ mi = GetMagickInfoList("*", &matches, &ei);
+ DestroyExceptionInfo(&ei);
+#endif // HAVE_OLD_GETMAGICKINFOLIST
+#else // HAVE_MAGICK6*/
+ const MagickInfo *mi;
+ ExceptionInfo ei;
+ GetExceptionInfo(&ei);
+ mi = GetMagickInfo("*", &ei);
+ DestroyExceptionInfo(&ei);
+// #endif // HAVE_MAGICK6
+
+ if (!mi) {
+ kdDebug(41008) << "Eek, no magick info!\n";
+ return s;
+ }
+
+/*#ifdef HAVE_MAGICK6
+ for (unsigned long i = 0; i < matches; i++) {
+ const MagickInfo *info = mi[i];
+ kdDebug(41008) << "Found export filter for: " << info -> name << "\n";
+ if (info -> stealth)
+ continue;
+
+ if (info -> encoder) {
+ name = info -> name;
+
+ description = info -> description;
+
+ if (!description.isEmpty() && !description.tqcontains('/')) {
+ all += "*." + name.lower() + " *." + name + " ";
+ s += "*." + name.lower() + " *." + name + "|";
+ s += i18n(description.utf8());
+ s += "\n";
+ }
+ }
+ }
+#else*/
+ for (; mi; mi = reinterpret_cast<const MagickInfo*>(mi -> next)) {
+ kdDebug(41008) << "Found export filter for: " << mi -> name << "\n";
+ if (mi -> stealth)
+ continue;
+
+ if (mi -> encoder) {
+ name = mi -> name;
+
+ description = mi -> description;
+
+ if (!description.isEmpty() && !description.tqcontains('/')) {
+ all += "*." + name.lower() + " *." + name + " ";
+ s += "*." + name.lower() + " *." + name + "|";
+ s += i18n(description.utf8());
+ s += "\n";
+ }
+ }
+ }
+// #endif
+
+
+ all += "|" + i18n("All Images");
+ all += "\n";
+
+ return all + s;
+ }
+
+#include "kis_image_magick_converter.moc"
+
diff --git a/filters/chalk/gmagick/kis_image_magick_converter.h b/filters/chalk/gmagick/kis_image_magick_converter.h
new file mode 100644
index 00000000..28bd94ce
--- /dev/null
+++ b/filters/chalk/gmagick/kis_image_magick_converter.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef KIS_IMAGE_MAGICK_CONVERTER_H_
+#define KIS_IMAGE_MAGICK_CONVERTER_H_
+
+#include <tqobject.h>
+#include <tqvaluevector.h>
+
+#include <kio/job.h>
+
+#include "kis_types.h"
+#include "kis_global.h"
+#include "kis_progress_subject.h"
+
+class TQString;
+class KURL;
+class KisDoc;
+class KisNameServer;
+class KisUndoAdapter;
+/**
+ * Image import/export plugins can use these results to report about success or failure.
+ */
+enum KisImageBuilder_Result {
+ KisImageBuilder_RESULT_FAILURE = -400,
+ KisImageBuilder_RESULT_NOT_EXIST = -300,
+ KisImageBuilder_RESULT_NOT_LOCAL = -200,
+ KisImageBuilder_RESULT_BAD_FETCH = -100,
+ KisImageBuilder_RESULT_INVALID_ARG = -50,
+ KisImageBuilder_RESULT_OK = 0,
+ KisImageBuilder_RESULT_PROGRESS = 1,
+ KisImageBuilder_RESULT_EMPTY = 100,
+ KisImageBuilder_RESULT_BUSY = 150,
+ KisImageBuilder_RESULT_NO_URI = 200,
+ KisImageBuilder_RESULT_UNSUPPORTED = 300,
+ KisImageBuilder_RESULT_INTR = 400,
+ KisImageBuilder_RESULT_PATH = 500,
+ KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE = 600
+};
+
+
+
+/**
+ * Build a KisImage representation of an image file.
+ */
+class KisImageMagickConverter : public KisProgressSubject {
+ typedef TQObject super;
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ KisImageMagickConverter(KisDoc *doc, KisUndoAdapter *adapter);
+ virtual ~KisImageMagickConverter();
+
+public slots:
+ virtual void cancel();
+
+public:
+ KisImageBuilder_Result buildImage(const KURL& uri);
+ KisImageBuilder_Result buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd);
+ KisImageSP image();
+
+public:
+ static TQString readFilters();
+ static TQString writeFilters();
+
+private slots:
+ void ioData(KIO::Job *job, const TQByteArray& data);
+ void ioResult(KIO::Job *job);
+ void ioTotalSize(KIO::Job *job, KIO::filesize_t size);
+
+private:
+ KisImageMagickConverter(const KisImageMagickConverter&);
+ KisImageMagickConverter& operator=(const KisImageMagickConverter&);
+ void init(KisDoc *doc, KisUndoAdapter *adapter);
+ KisImageBuilder_Result decode(const KURL& uri, bool isBlob);
+
+private:
+ KisImageSP m_img;
+ KisDoc *m_doc;
+ KisUndoAdapter *m_adapter;
+ TQValueVector<TQ_UINT8> m_data;
+ KIO::TransferJob *m_job;
+ KIO::filesize_t m_size;
+ bool m_stop;
+};
+
+#endif // KIS_IMAGE_MAGICK_CONVERTER_H_
+
diff --git a/filters/chalk/gmagick/magickexport.cpp b/filters/chalk/gmagick/magickexport.cpp
new file mode 100644
index 00000000..e56f53d2
--- /dev/null
+++ b/filters/chalk/gmagick/magickexport.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <magickexport.h>
+#include <kgenericfactory.h>
+#include <KoDocument.h>
+#include <KoFilterChain.h>
+
+#include <kis_doc.h>
+#include <kis_paint_layer.h>
+#include <kis_image.h>
+#include <kis_annotation.h>
+#include <kis_types.h>
+#include <kis_image_magick_converter.h>
+
+typedef KGenericFactory<MagickExport, KoFilter> MagickExportFactory;
+K_EXPORT_COMPONENT_FACTORY(libchalkgmagickexport, MagickExportFactory("kofficefilters"))
+
+MagickExport::MagickExport(KoFilter *, const char *, const TQStringList&) : KoFilter()
+{
+}
+
+MagickExport::~MagickExport()
+{
+}
+
+KoFilter::ConversiontqStatus MagickExport::convert(const TQCString& from, const TQCString& to)
+{
+ kdDebug(41008) << "magick export! From: " << from << ", To: " << to << "\n";
+
+ if (from != "application/x-chalk")
+ return KoFilter::NotImplemented;
+
+ // XXX: Add dialog about flattening layers here
+
+ KisDoc *output = dynamic_cast<KisDoc*>(m_chain->inputDocument());
+ TQString filename = m_chain->outputFile();
+
+ if (!output)
+ return KoFilter::CreationError;
+
+ if (filename.isEmpty()) return KoFilter::FileNotFound;
+
+ KURL url;
+ url.setPath(filename);
+
+ KisImageSP img = output->currentImage();
+
+ KisImageMagickConverter ib(output, output->undoAdapter());
+
+ KisPaintDeviceSP pd = new KisPaintDevice(*img->projection());
+ KisPaintLayerSP l = new KisPaintLayer(img, "projection", OPACITY_OPAQUE, pd);
+
+ vKisAnnotationSP_it beginIt = img->beginAnnotations();
+ vKisAnnotationSP_it endIt = img->endAnnotations();
+ if (ib.buildFile(url, l, beginIt, endIt) == KisImageBuilder_RESULT_OK) {
+ return KoFilter::OK;
+ }
+ return KoFilter::InternalError;
+}
+
+#include <magickexport.moc>
+
diff --git a/filters/chalk/gmagick/magickexport.h b/filters/chalk/gmagick/magickexport.h
new file mode 100644
index 00000000..6ea7e238
--- /dev/null
+++ b/filters/chalk/gmagick/magickexport.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef MAGICKEXPORT_H_
+#define MAGICKEXPORT_H_
+
+#include <KoFilter.h>
+
+class MagickExport : public KoFilter {
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ MagickExport(KoFilter *tqparent, const char *name, const TQStringList&);
+ virtual ~MagickExport();
+
+public:
+ virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to);
+};
+
+#endif // MAGICKEXPORT_H_
+
diff --git a/filters/chalk/gmagick/magickimport.cpp b/filters/chalk/gmagick/magickimport.cpp
new file mode 100644
index 00000000..dbfe6da8
--- /dev/null
+++ b/filters/chalk/gmagick/magickimport.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <tqstring.h>
+
+#include <magickimport.h>
+#include <kgenericfactory.h>
+#include <KoDocument.h>
+#include <KoFilterChain.h>
+
+#include <kis_doc.h>
+#include <kis_view.h>
+#include <kis_image_magick_converter.h>
+#include <kis_progress_display_interface.h>
+#include <kis_image.h>
+#include <kis_layer.h>
+
+typedef KGenericFactory<MagickImport, KoFilter> MagickImportFactory;
+K_EXPORT_COMPONENT_FACTORY(libchalkgmagickimport, MagickImportFactory("kofficefilters"))
+
+MagickImport::MagickImport(KoFilter *, const char *, const TQStringList&) : KoFilter()
+{
+}
+
+MagickImport::~MagickImport()
+{
+}
+
+KoFilter::ConversiontqStatus MagickImport::convert(const TQCString&, const TQCString& to)
+{
+ kdDebug(41008) << "Importing using MagickImport!\n";
+
+ if (to != "application/x-chalk")
+ return KoFilter::BadMimeType;
+
+ KisDoc * doc = dynamic_cast<KisDoc*>(m_chain -> outputDocument());
+ KisView * view = static_cast<KisView*>(doc -> views().getFirst());
+
+ TQString filename = m_chain -> inputFile();
+
+ if (!doc)
+ return KoFilter::CreationError;
+
+ doc -> prepareForImport();
+
+
+ if (!filename.isEmpty()) {
+
+ KURL url;
+ url.setPath(filename);
+
+ if (url.isEmpty())
+ return KoFilter::FileNotFound;
+
+ KisImageMagickConverter ib(doc, doc -> undoAdapter());
+
+ if (view != 0)
+ view -> canvasSubject() -> progressDisplay() -> setSubject(&ib, false, true);
+
+ switch (ib.buildImage(url)) {
+ case KisImageBuilder_RESULT_UNSUPPORTED:
+ return KoFilter::NotImplemented;
+ break;
+ case KisImageBuilder_RESULT_INVALID_ARG:
+ return KoFilter::BadMimeType;
+ break;
+ case KisImageBuilder_RESULT_NO_URI:
+ case KisImageBuilder_RESULT_NOT_LOCAL:
+ return KoFilter::FileNotFound;
+ break;
+ case KisImageBuilder_RESULT_BAD_FETCH:
+ case KisImageBuilder_RESULT_EMPTY:
+ return KoFilter::ParsingError;
+ break;
+ case KisImageBuilder_RESULT_FAILURE:
+ return KoFilter::InternalError;
+ break;
+ case KisImageBuilder_RESULT_OK:
+ doc -> setCurrentImage( ib.image());
+ return KoFilter::OK;
+ default:
+ break;
+ }
+
+ }
+ return KoFilter::StorageCreationError;
+}
+
+#include <magickimport.moc>
+
diff --git a/filters/chalk/gmagick/magickimport.h b/filters/chalk/gmagick/magickimport.h
new file mode 100644
index 00000000..3373f129
--- /dev/null
+++ b/filters/chalk/gmagick/magickimport.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef MAGICKIMPORT_H_
+#define MAGICKIMPORT_H_
+
+#include <KoFilter.h>
+
+class MagickImport : public KoFilter {
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ MagickImport(KoFilter *tqparent, const char *name, const TQStringList&);
+ virtual ~MagickImport();
+
+public:
+ virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to);
+};
+
+#endif // MAGICKIMPORT_H_
+
diff --git a/filters/chalk/jpeg/Makefile.am b/filters/chalk/jpeg/Makefile.am
new file mode 100644
index 00000000..40a47d81
--- /dev/null
+++ b/filters/chalk/jpeg/Makefile.am
@@ -0,0 +1,51 @@
+noinst_LTLIBRARIES = libchalkconverter.la
+kde_module_LTLIBRARIES = libchalkjpegimport.la libchalkjpegexport.la
+
+libchalkconverter_la_LDFLAGS = $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalkconverter_la_SOURCES = kis_jpeg_converter.cc iccjpeg.c
+libchalkconverter_la_LIBADD = $(top_builddir)/filters/chalk/libkisexif/libkisexif.la
+
+libchalkjpegexport_la_LDFLAGS = -avoid-version -module -no-undefined \
+ $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalkjpegexport_la_LIBADD = $(top_builddir)/chalk/libchalkcommon.la \
+ libchalkconverter.la $(KOFFICE_LIBS) -ljpeg -lexif
+
+libchalkjpegimport_la_LDFLAGS = -avoid-version -module -no-undefined \
+ $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalkjpegimport_la_LIBADD = $(top_builddir)/chalk/libchalkcommon.la \
+ libchalkconverter.la $(KOFFICE_LIBS) -ljpeg -lexif
+
+INCLUDES= \
+ -I$(srcdir) \
+ $(KOFFICE_INCLUDES) \
+ -I$(top_srcdir)/chalk \
+ -I$(top_srcdir)/chalk/core \
+ -I$(top_srcdir)/chalk/sdk \
+ -I$(top_srcdir)/chalk/core/tiles \
+ -I$(top_srcdir)/chalk/chalkcolor \
+ -I$(top_srcdir)/chalk/ui \
+ -I$(top_srcdir)/filters/chalk/libkisexif \
+ $(KOFFICE_INCLUDES) -I$(interfacedir) \
+ $(KOPAINTER_INCLUDES) \
+ $(all_includes)
+
+service_DATA = chalk_jpeg_import.desktop chalk_jpeg_export.desktop
+servicedir = $(kde_servicesdir)
+
+kdelnk_DATA = chalk_jpeg.desktop
+kdelnkdir = $(kde_appsdir)/.hidden
+
+libchalkjpegimport_la_SOURCES = kis_jpeg_import.cc
+libchalkjpegexport_la_SOURCES = kis_wdg_options_jpeg.ui kis_jpeg_export.cc
+
+METASOURCES = AUTO
+
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+
diff --git a/filters/chalk/jpeg/chalk_jpeg.desktop b/filters/chalk/jpeg/chalk_jpeg.desktop
new file mode 100644
index 00000000..13239199
--- /dev/null
+++ b/filters/chalk/jpeg/chalk_jpeg.desktop
@@ -0,0 +1,58 @@
+[Desktop Entry]
+Categories=
+Exec=chalk %u
+GenericName=Application for Drawing and Handling of Images
+GenericName[bg]=Приложение за рисуване и обработка на изображения
+GenericName[ca]=Aplicació per a dibuix i modificació d'imatges
+GenericName[da]=Tegne- og billedbehandlingsprogram
+GenericName[de]=Programm zum Zeichnen und Bearbeiten von Bildern
+GenericName[el]=Εφαρμογή για επεξεργασία και χειρισμό εικόνων
+GenericName[eo]=Aplikaĵo por Desegnado kaj Mastrumado de Bildoj
+GenericName[es]=Aplicación para dibujo y manipulación de imágenes
+GenericName[et]=Joonistamise ja pilditöötluse rakendus
+GenericName[fa]=کاربرد برای ترسیم و به کار بردن تصاویر
+GenericName[fi]=Ohjelma kuvien piirtämiseen ja käsittelyyn
+GenericName[fr]=Application pour dessiner et manipuler des images
+GenericName[fy]=Aplikaasje om ôfbyldings mei te tekenjen en te bewurkjen
+GenericName[gl]=Aplicación de Debuxo e Manipulación de Imaxes
+GenericName[he]=יישום לצביעה וניהול תמונות
+GenericName[hu]=Rajzoló és képkezelő
+GenericName[is]=Teikni og myndvinnsluforrit
+GenericName[it]=Applicazione di disegno e gestione di immagini
+GenericName[ja]=描画と画像操作のためのアプリケーション
+GenericName[km]=កម្មវិធី​សម្រាប់​គូរ និង​ដោះស្រាយ​នៃ​រូបភាព
+GenericName[lv]=Programma zīmēšanai un attēlu apstrādei
+GenericName[nb]=Program for tegning og bildehåndtering
+GenericName[nds]=Programm för't Teken un Bildhanteren
+GenericName[ne]=रेखाचित्र र छविहरूको ह्यान्डल गर्न अनुप्रयोग
+GenericName[nl]=Toepassing om afbeeldingen te tekenen en te bewerken
+GenericName[pl]=Program do rysowania i obróbki obrazków
+GenericName[pt]=Aplicação de Desenho e Manipulação de Imagens
+GenericName[pt_BR]=Aplicação de Desenho e Manipulação de Imagens
+GenericName[ru]=Растровые изображения
+GenericName[se]=Prográmma sárgumii ja govvegieđaheapmái
+GenericName[sk]=Aplikácia na kresnenie a manilupáciu s obrázkami
+GenericName[sl]=Program za risanje in rokovanje s slikami
+GenericName[sr]=Програм за цртање и обраду слика
+GenericName[sr@Latn]=Program za crtanje i obradu slika
+GenericName[sv]=Program för att rita och hantera bilder
+GenericName[uk]=Програма для малювання і обробки зображень
+GenericName[uz]=Rasm chizish dasturi
+GenericName[uz@cyrillic]=Расм чизиш дастури
+GenericName[zh_CN]=绘制和操纵图像的应用程序
+GenericName[zh_TW]=影像繪製與處理應用程式
+Icon=chalk
+MimeType=image/jpeg
+Name=Chalk
+Name[hi]=के-रिता
+Name[km]= Chalk
+Name[lo]=ກຣິຕາ
+Name[ne]=क्रिता
+Path=
+StartupNotify=true
+Terminal=false
+Type=Application
+X-DCOP-ServiceType=multi
+X-KDE-StartupNotify=true
+X-KDE-SubstituteUID=false
+X-KDE-Username=
diff --git a/filters/chalk/jpeg/chalk_jpeg_export.desktop b/filters/chalk/jpeg/chalk_jpeg_export.desktop
new file mode 100644
index 00000000..17d776dd
--- /dev/null
+++ b/filters/chalk/jpeg/chalk_jpeg_export.desktop
@@ -0,0 +1,52 @@
+[Desktop Entry]
+Icon=
+Name=Chalk PNG Export Filter
+Name[bg]=Филтър за експортиране от Chalk в PNG
+Name[br]=Sil ezporzh PNG evit Chalk
+Name[ca]=Filtre d'exportació PNG per a Chalk
+Name[da]=Chalk PNG-eksportfilter
+Name[de]=Chalk PNG-Exportfilter
+Name[el]=Φίλτρο εξαγωγής PNG του Chalk
+Name[eo]=Chalk PNG-eksportfiltrilo
+Name[es]=Filtro de exportación a PNG de Chalk
+Name[et]=Chalk PNG ekspordifilter
+Name[fa]=پالایۀ صادرات Chalk PNG
+Name[fi]=Chalk PNG -viestisuodin
+Name[fr]=Filtre d'exportation PNG de Chalk
+Name[fy]=Chalk PNG Eksportfilter
+Name[ga]=Scagaire Easpórtála PNG Chalk
+Name[gl]=Filtro de Exportación de PNG para Chalk
+Name[he]=Chalk PNG מסנן יצוא
+Name[hr]=Chalk PNG filtar izvoza
+Name[hu]=Chalk PNG exportszűrő
+Name[is]=Chalk PNG útflutningssía
+Name[it]=Filtro di esportazione PNG per Chalk
+Name[ja]=Chalk PNG エクスポートフィルタ
+Name[km]=តម្រង​នាំចេញ PNG សម្រាប់ Chalk
+Name[lt]=Chalk PNG eksportavimo filtras
+Name[lv]=Chalk PNG eksporta filtrs
+Name[nb]=PNG-eksportfilter for Chalk
+Name[nds]=PNG-Exportfilter för Chalk
+Name[ne]=क्रिता पीएनजी निर्यात फिल्टर
+Name[nl]=Chalk PNG Exportfilter
+Name[pl]=Filtr eksportu do formatu PNG dla Chalk
+Name[pt]=Filtro de Exportação de PNG para o Chalk
+Name[pt_BR]=Filtro de Exportação de PNG para o Chalk
+Name[ru]=Фильтр экспорта рисунков Chalk в PNG
+Name[se]=Chalk PNG-olggosfievrridansilli
+Name[sk]=Exportný filter Chalk PNG
+Name[sl]=Izvozni filter PNG za Krito
+Name[sr]=Chalk-ин филтер за извоз у PNG
+Name[sr@Latn]=Chalk-in filter za izvoz u PNG
+Name[sv]=Chalk PNG-exportfilter
+Name[uk]=Фільтр експорту PNG для Chalk
+Name[uz]=Chalk PNG eksport filteri
+Name[uz@cyrillic]=Chalk PNG экспорт филтери
+Name[zh_CN]=Chalk PNG 导出过滤器
+Name[zh_TW]=Chalk PNG 匯出過濾程式
+ServiceTypes=KOfficeFilter
+Type=Service
+X-KDE-Export=image/jpeg
+X-KDE-Import=application/x-chalk
+X-KDE-Library=libchalkjpegexport
+X-KDE-Weight=1
diff --git a/filters/chalk/jpeg/chalk_jpeg_import.desktop b/filters/chalk/jpeg/chalk_jpeg_import.desktop
new file mode 100644
index 00000000..736c2c7b
--- /dev/null
+++ b/filters/chalk/jpeg/chalk_jpeg_import.desktop
@@ -0,0 +1,52 @@
+[Desktop Entry]
+Icon=
+Name=Chalk PNG Import Filter
+Name[bg]=Филтър за импортиране от PNG в Chalk
+Name[br]=Sil enporzh PNG evit Chalk
+Name[ca]=Filtre d'importació PNG per a Chalk
+Name[da]=Chalk PNG-importfilter
+Name[de]=Chalk PNG-Importfilter
+Name[el]=Φίλτρο εισαγωγής PNG του Chalk
+Name[eo]=Chalk PNG-importfiltrilo
+Name[es]=Filtro de importación a PNG de Chalk
+Name[et]=Chalk PNG impordifilter
+Name[fa]=پالایۀ واردات Chalk PNG
+Name[fi]=Chalk PNG -tuontisuodin
+Name[fr]=Filtre d'importation PNG de Chalk
+Name[fy]=Chalk PNG Ymportfilter
+Name[ga]=Scagaire Iompórtála PNG Chalk
+Name[gl]=Filtro de Importación de PNG para Chalk
+Name[he]=Chalk PNG מסנן יבוא
+Name[hr]=Chalk PNG filtar uvoza
+Name[hu]=Chalk PNG importszűrő
+Name[is]=Chalk PNG innflutningssía
+Name[it]=Filtro di importazione PNG per Chalk
+Name[ja]=Chalk PNG インポートフィルタ
+Name[km]=តម្រង​នាំចូល PNG សម្រាប់ Chalk
+Name[lt]=Chalk PNG importavimo filtras
+Name[lv]=Chalk PNG importa filtrs
+Name[nb]=PNG-importfilter for Chalk
+Name[nds]=PNG-Importfilter för Chalk
+Name[ne]=क्रिता पीएनजी आयात फिल्टर
+Name[nl]=Chalk PNG Importfilter
+Name[pl]=Filtr importu z formatu PNG dla Chalk
+Name[pt]=Filtro de Importação de PNG para o Chalk
+Name[pt_BR]=Filtro de Importação de PNG para o Chalk
+Name[ru]=Фильтр импорта рисунков PNG в Chalk
+Name[se]=Chalk PNG-olggosfievrridansilli
+Name[sk]=PNG filter pre import do Chalk
+Name[sl]=Uvozni filter PNG za Krito
+Name[sr]=Chalk-ин филтер за увоз из PNG-а
+Name[sr@Latn]=Chalk-in filter za uvoz iz PNG-a
+Name[sv]=Chalk PNG-importfilter
+Name[uk]=Фільтр імпорту PNG для Chalk
+Name[uz]=Chalk PNG import filteri
+Name[uz@cyrillic]=Chalk PNG импорт филтери
+Name[zh_CN]=Chalk PNG 导入过滤器
+Name[zh_TW]=Chalk PNG 匯入過濾程式
+ServiceTypes=KOfficeFilter
+Type=Service
+X-KDE-Export=application/x-chalk
+X-KDE-Import=image/jpeg
+X-KDE-Library=libchalkjpegimport
+X-KDE-Weight=1
diff --git a/filters/chalk/jpeg/configure.in.bot b/filters/chalk/jpeg/configure.in.bot
new file mode 100644
index 00000000..ecbc3393
--- /dev/null
+++ b/filters/chalk/jpeg/configure.in.bot
@@ -0,0 +1,7 @@
+if test -z "$LIBJPEG" -o -z "$LIBEXIF"; then
+ echo ""
+ echo "You're missing libjpeg or libexif 0.6.12 or later (binaries and/or headers)."
+ echo "chalk won't be able to import/export jpeg"
+ echo ""
+ all_tests=bad
+fi
diff --git a/filters/chalk/jpeg/iccjpeg.c b/filters/chalk/jpeg/iccjpeg.c
new file mode 100644
index 00000000..7abe1ff4
--- /dev/null
+++ b/filters/chalk/jpeg/iccjpeg.c
@@ -0,0 +1,270 @@
+/*
+ * Little cms
+ * Copyright (C) 1998-2004 Marti Maria
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * iccprofile.c
+ *
+ * This file provides code to read and write International Color Consortium
+ * (ICC) device profiles embedded in JFIF JPEG image files. The ICC has
+ * defined a standard format for including such data in JPEG "APP2" markers.
+ * The code given here does not know anything about the internal structure
+ * of the ICC profile data; it just knows how to put the profile data into
+ * a JPEG file being written, or get it back out when reading.
+ *
+ * This code depends on new features added to the IJG JPEG library as of
+ * IJG release 6b; it will not compile or work with older IJG versions.
+ *
+ * NOTE: this code would need surgery to work on 16-bit-int machines
+ * with ICC profiles exceeding 64K bytes in size. If you need to do that,
+ * change all the "unsigned int" variables to "INT32". You'll also need
+ * to find a malloc() replacement that can allocate more than 64K.
+ */
+
+#include "iccjpeg.h"
+#include <stdlib.h> /* define malloc() */
+
+
+/*
+ * Since an ICC profile can be larger than the maximum size of a JPEG marker
+ * (64K), we need provisions to split it into multiple markers. The format
+ * defined by the ICC specifies one or more APP2 markers containing the
+ * following data:
+ * Identifying string ASCII "ICC_PROFILE\0" (12 bytes)
+ * Marker sequence number 1 for first APP2, 2 for next, etc (1 byte)
+ * Number of markers Total number of APP2's used (1 byte)
+ * Profile data (remainder of APP2 data)
+ * Decoders should use the marker sequence numbers to reassemble the profile,
+ * rather than assuming that the APP2 markers appear in the correct sequence.
+ */
+
+#define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */
+#define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */
+#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */
+#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
+
+
+/*
+ * This routine writes the given ICC profile data into a JPEG file.
+ * It *must* be called AFTER calling jpeg_start_compress() and BEFORE
+ * the first call to jpeg_write_scanlines().
+ * (This ordering ensures that the APP2 marker(s) will appear after the
+ * SOI and JFIF or Adobe markers, but before all else.)
+ */
+
+void
+write_icc_profile (j_compress_ptr cinfo,
+ const JOCTET *icc_data_ptr,
+ unsigned int icc_data_len)
+{
+ unsigned int num_markers; /* total number of markers we'll write */
+ int cur_marker = 1; /* per spec, counting starts at 1 */
+ unsigned int length; /* number of bytes to write in this marker */
+
+ /* Calculate the number of markers we'll need, rounding up of course */
+ num_markers = icc_data_len / MAX_DATA_BYTES_IN_MARKER;
+ if (num_markers * MAX_DATA_BYTES_IN_MARKER != icc_data_len)
+ num_markers++;
+
+ while (icc_data_len > 0) {
+ /* length of profile to put in this marker */
+ length = icc_data_len;
+ if (length > MAX_DATA_BYTES_IN_MARKER)
+ length = MAX_DATA_BYTES_IN_MARKER;
+ icc_data_len -= length;
+
+ /* Write the JPEG marker header (APP2 code and marker length) */
+ jpeg_write_m_header(cinfo, ICC_MARKER,
+ (unsigned int) (length + ICC_OVERHEAD_LEN));
+
+ /* Write the marker identifying string "ICC_PROFILE" (null-terminated).
+ * We code it in this less-than-transparent way so that the code works
+ * even if the local character set is not ASCII.
+ */
+ jpeg_write_m_byte(cinfo, 0x49);
+ jpeg_write_m_byte(cinfo, 0x43);
+ jpeg_write_m_byte(cinfo, 0x43);
+ jpeg_write_m_byte(cinfo, 0x5F);
+ jpeg_write_m_byte(cinfo, 0x50);
+ jpeg_write_m_byte(cinfo, 0x52);
+ jpeg_write_m_byte(cinfo, 0x4F);
+ jpeg_write_m_byte(cinfo, 0x46);
+ jpeg_write_m_byte(cinfo, 0x49);
+ jpeg_write_m_byte(cinfo, 0x4C);
+ jpeg_write_m_byte(cinfo, 0x45);
+ jpeg_write_m_byte(cinfo, 0x0);
+
+ /* Add the sequencing info */
+ jpeg_write_m_byte(cinfo, cur_marker);
+ jpeg_write_m_byte(cinfo, (int) num_markers);
+
+ /* Add the profile data */
+ while (length--) {
+ jpeg_write_m_byte(cinfo, *icc_data_ptr);
+ icc_data_ptr++;
+ }
+ cur_marker++;
+ }
+}
+
+
+/*
+ * Prepare for reading an ICC profile
+ */
+
+void
+setup_read_icc_profile (j_decompress_ptr cinfo)
+{
+ /* Tell the library to keep any APP2 data it may tqfind */
+ jpeg_save_markers(cinfo, ICC_MARKER, 0xFFFF);
+}
+
+
+/*
+ * Handy subroutine to test whether a saved marker is an ICC profile marker.
+ */
+
+static boolean
+marker_is_icc (jpeg_saved_marker_ptr marker)
+{
+ return
+ marker->marker == ICC_MARKER &&
+ marker->data_length >= ICC_OVERHEAD_LEN &&
+ /* verify the identifying string */
+ GETJOCTET(marker->data[0]) == 0x49 &&
+ GETJOCTET(marker->data[1]) == 0x43 &&
+ GETJOCTET(marker->data[2]) == 0x43 &&
+ GETJOCTET(marker->data[3]) == 0x5F &&
+ GETJOCTET(marker->data[4]) == 0x50 &&
+ GETJOCTET(marker->data[5]) == 0x52 &&
+ GETJOCTET(marker->data[6]) == 0x4F &&
+ GETJOCTET(marker->data[7]) == 0x46 &&
+ GETJOCTET(marker->data[8]) == 0x49 &&
+ GETJOCTET(marker->data[9]) == 0x4C &&
+ GETJOCTET(marker->data[10]) == 0x45 &&
+ GETJOCTET(marker->data[11]) == 0x0;
+}
+
+
+/*
+ * See if there was an ICC profile in the JPEG file being read;
+ * if so, reassemble and return the profile data.
+ *
+ * TRUE is returned if an ICC profile was found, FALSE if not.
+ * If TRUE is returned, *icc_data_ptr is set to point to the
+ * returned data, and *icc_data_len is set to its length.
+ *
+ * IMPORTANT: the data at **icc_data_ptr has been allocated with malloc()
+ * and must be freed by the caller with free() when the caller no longer
+ * needs it. (Alternatively, we could write this routine to use the
+ * IJG library's memory allocator, so that the data would be freed implicitly
+ * at jpeg_finish_decompress() time. But it seems likely that many apps
+ * will prefer to have the data stick around after decompression finishes.)
+ *
+ * NOTE: if the file contains invalid ICC APP2 markers, we just silently
+ * return FALSE. You might want to issue an error message instead.
+ */
+
+boolean
+read_icc_profile (j_decompress_ptr cinfo,
+ JOCTET **icc_data_ptr,
+ unsigned int *icc_data_len)
+{
+ jpeg_saved_marker_ptr marker;
+ int num_markers = 0;
+ int seq_no;
+ JOCTET *icc_data;
+ unsigned int total_length;
+#define MAX_SEQ_NO 255 /* sufficient since marker numbers are bytes */
+ char marker_present[MAX_SEQ_NO+1]; /* 1 if marker found */
+ unsigned int data_length[MAX_SEQ_NO+1]; /* size of profile data in marker */
+ unsigned int data_offset[MAX_SEQ_NO+1]; /* offset for data in marker */
+
+ *icc_data_ptr = NULL; /* avoid confusion if FALSE return */
+ *icc_data_len = 0;
+
+ /* This first pass over the saved markers discovers whether there are
+ * any ICC markers and verifies the consistency of the marker numbering.
+ */
+
+ for (seq_no = 1; seq_no <= MAX_SEQ_NO; seq_no++)
+ marker_present[seq_no] = 0;
+
+ for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
+ if (marker_is_icc(marker)) {
+ if (num_markers == 0)
+ num_markers = GETJOCTET(marker->data[13]);
+ else if (num_markers != GETJOCTET(marker->data[13]))
+ return FALSE; /* inconsistent num_markers fields */
+ seq_no = GETJOCTET(marker->data[12]);
+ if (seq_no <= 0 || seq_no > num_markers)
+ return FALSE; /* bogus sequence number */
+ if (marker_present[seq_no])
+ return FALSE; /* duplicate sequence numbers */
+ marker_present[seq_no] = 1;
+ data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN;
+ }
+ }
+
+ if (num_markers == 0)
+ return FALSE;
+
+ /* Check for missing markers, count total space needed,
+ * compute offset of each marker's part of the data.
+ */
+
+ total_length = 0;
+ for (seq_no = 1; seq_no <= num_markers; seq_no++) {
+ if (marker_present[seq_no] == 0)
+ return FALSE; /* missing sequence number */
+ data_offset[seq_no] = total_length;
+ total_length += data_length[seq_no];
+ }
+
+ if (total_length <= 0)
+ return FALSE; /* found only empty markers? */
+
+ /* Allocate space for assembled data */
+ icc_data = (JOCTET *) malloc(total_length * sizeof(JOCTET));
+ if (icc_data == NULL)
+ return FALSE; /* oops, out of memory */
+
+ /* and fill it in */
+ for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
+ if (marker_is_icc(marker)) {
+ JOCTET FAR *src_ptr;
+ JOCTET *dst_ptr;
+ unsigned int length;
+ seq_no = GETJOCTET(marker->data[12]);
+ dst_ptr = icc_data + data_offset[seq_no];
+ src_ptr = marker->data + ICC_OVERHEAD_LEN;
+ length = data_length[seq_no];
+ while (length--) {
+ *dst_ptr++ = *src_ptr++;
+ }
+ }
+ }
+
+ *icc_data_ptr = icc_data;
+ *icc_data_len = total_length;
+
+ return TRUE;
+}
diff --git a/filters/chalk/jpeg/iccjpeg.h b/filters/chalk/jpeg/iccjpeg.h
new file mode 100644
index 00000000..8828dc99
--- /dev/null
+++ b/filters/chalk/jpeg/iccjpeg.h
@@ -0,0 +1,99 @@
+/*
+ * Little cms
+ * Copyright (C) 1998-2004 Marti Maria
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * iccprofile.h
+ *
+ * This file provides code to read and write International Color Consortium
+ * (ICC) device profiles embedded in JFIF JPEG image files. The ICC has
+ * defined a standard format for including such data in JPEG "APP2" markers.
+ * The code given here does not know anything about the internal structure
+ * of the ICC profile data; it just knows how to put the profile data into
+ * a JPEG file being written, or get it back out when reading.
+ *
+ * This code depends on new features added to the IJG JPEG library as of
+ * IJG release 6b; it will not compile or work with older IJG versions.
+ *
+ * NOTE: this code would need surgery to work on 16-bit-int machines
+ * with ICC profiles exceeding 64K bytes in size. See iccprofile.c
+ * for details.
+ */
+#ifndef ICCJPEG
+#define ICCJPEG
+
+#include <stdio.h> /* needed to define "FILE", "NULL" */
+#include "jpeglib.h"
+
+
+/*
+ * This routine writes the given ICC profile data into a JPEG file.
+ * It *must* be called AFTER calling jpeg_start_compress() and BEFORE
+ * the first call to jpeg_write_scanlines().
+ * (This ordering ensures that the APP2 marker(s) will appear after the
+ * SOI and JFIF or Adobe markers, but before all else.)
+ */
+
+extern void write_icc_profile JPP((j_compress_ptr cinfo,
+ const JOCTET *icc_data_ptr,
+ unsigned int icc_data_len));
+
+
+/*
+ * Reading a JPEG file that may contain an ICC profile requires two steps:
+ *
+ * 1. After jpeg_create_decompress() but before jpeg_read_header(),
+ * call setup_read_icc_profile(). This routine tells the IJG library
+ * to save in memory any APP2 markers it may find in the file.
+ *
+ * 2. After jpeg_read_header(), call read_icc_profile() to find out
+ * whether there was a profile and obtain it if so.
+ */
+
+
+/*
+ * Prepare for reading an ICC profile
+ */
+
+extern void setup_read_icc_profile JPP((j_decompress_ptr cinfo));
+
+
+/*
+ * See if there was an ICC profile in the JPEG file being read;
+ * if so, reassemble and return the profile data.
+ *
+ * TRUE is returned if an ICC profile was found, FALSE if not.
+ * If TRUE is returned, *icc_data_ptr is set to point to the
+ * returned data, and *icc_data_len is set to its length.
+ *
+ * IMPORTANT: the data at **icc_data_ptr has been allocated with malloc()
+ * and must be freed by the caller with free() when the caller no longer
+ * needs it. (Alternatively, we could write this routine to use the
+ * IJG library's memory allocator, so that the data would be freed implicitly
+ * at jpeg_finish_decompress() time. But it seems likely that many apps
+ * will prefer to have the data stick around after decompression finishes.)
+ */
+
+extern boolean read_icc_profile JPP((j_decompress_ptr cinfo,
+ JOCTET **icc_data_ptr,
+ unsigned int *icc_data_len));
+
+#endif
diff --git a/filters/chalk/jpeg/kis_jpeg_converter.cc b/filters/chalk/jpeg/kis_jpeg_converter.cc
new file mode 100644
index 00000000..8daebc00
--- /dev/null
+++ b/filters/chalk/jpeg/kis_jpeg_converter.cc
@@ -0,0 +1,542 @@
+/*
+ * Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_jpeg_converter.h"
+
+#include <stdio.h>
+
+extern "C" {
+#include <iccjpeg.h>
+}
+
+#include <tqfile.h>
+
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+
+#include <KoDocumentInfo.h>
+
+#include <kio/netaccess.h>
+
+#include <kis_abstract_colorspace.h>
+#include <kis_colorspace_factory_registry.h>
+#include <kis_doc.h>
+#include <kis_image.h>
+#include <kis_iterators_pixel.h>
+#include <kis_paint_layer.h>
+#include <kis_group_layer.h>
+#include <kis_meta_registry.h>
+#include <kis_profile.h>
+
+#include <kis_exif_io.h>
+
+extern "C" {
+#include <libexif/exif-loader.h>
+#include <libexif/exif-utils.h>
+}
+
+#define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */
+#define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */
+#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */
+#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
+
+namespace {
+
+ J_COLOR_SPACE getColorTypeforColorSpace( KisColorSpace * cs)
+ {
+ if ( cs->id() == KisID("GRAYA") || cs->id() == KisID("GRAYA16") )
+ {
+ return JCS_GRAYSCALE;
+ }
+ if ( cs->id() == KisID("RGBA") || cs->id() == KisID("RGBA16") )
+ {
+ return JCS_RGB;
+ }
+ if ( cs->id() == KisID("CMYK") || cs->id() == KisID("CMYK16") )
+ {
+ return JCS_CMYK;
+ }
+ KMessageBox::error(0, i18n("Cannot export images in %1.\n").tqarg(cs->id().name()) ) ;
+ return JCS_UNKNOWN;
+ }
+
+ TQString getColorSpaceForColorType(J_COLOR_SPACE color_type) {
+ kdDebug(41008) << "color_type = " << color_type << endl;
+ if(color_type == JCS_GRAYSCALE)
+ {
+ return "GRAYA";
+ } else if(color_type == JCS_RGB) {
+ return "RGBA";
+ } else if(color_type == JCS_CMYK) {
+ return "CMYK";
+ }
+ return "";
+ }
+
+}
+
+KisJPEGConverter::KisJPEGConverter(KisDoc *doc, KisUndoAdapter *adapter)
+{
+ m_doc = doc;
+ m_adapter = adapter;
+ m_job = 0;
+ m_stop = false;
+}
+
+KisJPEGConverter::~KisJPEGConverter()
+{
+}
+
+KisImageBuilder_Result KisJPEGConverter::decode(const KURL& uri)
+{
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_decompress(&cinfo);
+
+ // open the file
+ FILE *fp = fopen(TQFile::encodeName(uri.path()), "rb");
+ if (!fp)
+ {
+ return (KisImageBuilder_RESULT_NOT_EXIST);
+ }
+ jpeg_stdio_src(&cinfo, fp);
+
+ jpeg_save_markers (&cinfo, JPEG_COM, 0xFFFF);
+ /* Save APP0..APP15 markers */
+ for (int m = 0; m < 16; m++)
+ jpeg_save_markers (&cinfo, JPEG_APP0 + m, 0xFFFF);
+
+
+// setup_read_icc_profile(&cinfo);
+ // read header
+ jpeg_read_header(&cinfo, true);
+
+ // start reading
+ jpeg_start_decompress(&cinfo);
+
+ // Get the colorspace
+ TQString csName = getColorSpaceForColorType(cinfo.out_color_space);
+ if(csName.isEmpty()) {
+ kdDebug(41008) << "unsupported colorspace : " << cinfo.out_color_space << endl;
+ jpeg_destroy_decompress(&cinfo);
+ fclose(fp);
+ return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
+ }
+ uchar* profile_data;
+ uint profile_len;
+ KisProfile* profile = 0;
+ TQByteArray profile_rawdata;
+ if( read_icc_profile (&cinfo, &profile_data, &profile_len))
+ {
+ profile_rawdata.resize(profile_len);
+ memcpy(profile_rawdata.data(), profile_data, profile_len);
+ cmsHPROFILE hProfile = cmsOpenProfileFromMem(profile_data, (DWORD)profile_len);
+
+ if (hProfile != (cmsHPROFILE) NULL) {
+ profile = new KisProfile( profile_rawdata);
+ Q_CHECK_PTR(profile);
+ kdDebug(41008) << "profile name: " << profile->productName() << " profile description: " << profile->productDescription() << " information sur le produit: " << profile->productInfo() << endl;
+ if(!profile->isSuitableForOutput())
+ {
+ kdDebug(41008) << "the profile is not suitable for output and therefore cannot be used in chalk, we need to convert the image to a standard profile" << endl; // TODO: in ko2 popup a selection menu to inform the user
+ }
+ }
+ }
+
+ // Retrieve a pointer to the colorspace
+ KisColorSpace* cs;
+ if (profile && profile->isSuitableForOutput())
+ {
+ kdDebug(41008) << "image has embedded profile: " << profile -> productName() << "\n";
+ cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(csName, profile);
+ }
+ else
+ cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName,""),"");
+
+ if(cs == 0)
+ {
+ kdDebug(41008) << "unknown colorspace" << endl;
+ jpeg_destroy_decompress(&cinfo);
+ fclose(fp);
+ return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
+ }
+
+ // Create the cmsTransform if needed
+
+ cmsHTRANSFORM transform = 0;
+ if(profile && !profile->isSuitableForOutput())
+ {
+ transform = cmsCreateTransform(profile->profile(), cs->colorSpaceType(),
+ cs->getProfile()->profile() , cs->colorSpaceType(),
+ INTENT_PERCEPTUAL, 0);
+ }
+
+ // Creating the KisImageSP
+ if( ! m_img) {
+ m_img = new KisImage(m_doc->undoAdapter(), cinfo.image_width, cinfo.image_height, cs, "built image");
+ Q_CHECK_PTR(m_img);
+ if(profile && !profile->isSuitableForOutput())
+ {
+ m_img -> addAnnotation( new KisAnnotation( profile->productName(), "", profile_rawdata) );
+ }
+ }
+
+ KisPaintLayerSP layer = new KisPaintLayer(m_img, m_img -> nextLayerName(), TQ_UINT8_MAX);
+
+ // Read exif information if any
+
+ // Read data
+ JSAMPROW row_pointer = new JSAMPLE[cinfo.image_width *cinfo.num_components];
+
+ for (; cinfo.output_scanline < cinfo.image_height;) {
+ KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, cinfo.output_scanline, cinfo.image_width, true);
+ jpeg_read_scanlines(&cinfo, &row_pointer, 1);
+ TQ_UINT8 *src = row_pointer;
+ switch(cinfo.out_color_space)
+ {
+ case JCS_GRAYSCALE:
+ while (!it.isDone()) {
+ TQ_UINT8 *d = it.rawData();
+ d[0] = *(src++);
+ if(transform) cmsDoTransform(transform, d, d, 1);
+ d[1] = TQ_UINT8_MAX;
+ ++it;
+ }
+ break;
+ case JCS_RGB:
+ while (!it.isDone()) {
+ TQ_UINT8 *d = it.rawData();
+ d[2] = *(src++);
+ d[1] = *(src++);
+ d[0] = *(src++);
+ if(transform) cmsDoTransform(transform, d, d, 1);
+ d[3] = TQ_UINT8_MAX;
+ ++it;
+ }
+ break;
+ case JCS_CMYK:
+ while (!it.isDone()) {
+ TQ_UINT8 *d = it.rawData();
+ d[0] = TQ_UINT8_MAX - *(src++);
+ d[1] = TQ_UINT8_MAX - *(src++);
+ d[2] = TQ_UINT8_MAX - *(src++);
+ d[3] = TQ_UINT8_MAX - *(src++);
+ if(transform) cmsDoTransform(transform, d, d, 1);
+ d[4] = TQ_UINT8_MAX;
+ ++it;
+ }
+ break;
+ default:
+ return KisImageBuilder_RESULT_UNSUPPORTED;
+ }
+ }
+
+ m_img->addLayer(layer.data(), m_img->rootLayer(), 0);
+
+ // Read exif informations
+
+ kdDebug(41008) << "Looking for exif information" << endl;
+
+ for (jpeg_saved_marker_ptr marker = cinfo.marker_list; marker != NULL; marker = marker->next) {
+ kdDebug(41008) << "Marker is " << marker->marker << endl;
+ if (marker->marker != (JOCTET) (JPEG_APP0 + 1) ||
+ marker->data_length < 14)
+ continue; /* Exif data is in an APP1 marker of at least 14 octets */
+
+ if (GETJOCTET (marker->data[0]) != (JOCTET) 0x45 ||
+ GETJOCTET (marker->data[1]) != (JOCTET) 0x78 ||
+ GETJOCTET (marker->data[2]) != (JOCTET) 0x69 ||
+ GETJOCTET (marker->data[3]) != (JOCTET) 0x66 ||
+ GETJOCTET (marker->data[4]) != (JOCTET) 0x00 ||
+ GETJOCTET (marker->data[5]) != (JOCTET) 0x00)
+ continue; /* no Exif header */
+ kdDebug(41008) << "Found exif information of length : "<< marker->data_length << endl;
+ KisExifIO exifIO(layer->paintDevice()->exifInfo());
+ exifIO.readExifFromMem( marker->data , marker->data_length );
+ // Interpret orientation tag
+ ExifValue v;
+ if( layer->paintDevice()->exifInfo()->getValue("Qt::Orientation", v) && v.type() == ExifValue::EXIF_TYPE_SHORT)
+ {
+ switch(v.asShort(0)) //
+ {
+ case 2:
+ layer->paintDevice()->mirrorY();
+ break;
+ case 3:
+ image()->rotate(M_PI, 0);
+ break;
+ case 4:
+ layer->paintDevice()->mirrorX();
+ break;
+ case 5:
+ image()->rotate(M_PI/2, 0);
+ layer->paintDevice()->mirrorY();
+ break;
+ case 6:
+ image()->rotate(M_PI/2, 0);
+ break;
+ case 7:
+ image()->rotate(M_PI/2, 0);
+ layer->paintDevice()->mirrorX();
+ break;
+ case 8:
+ image()->rotate(-M_PI/2 + 2*M_PI, 0);
+ break;
+ default:
+ break;
+ }
+ v.setValue(0, (TQ_UINT16)1);
+ layer->paintDevice()->exifInfo()->setValue("Qt::Orientation", v);
+ }
+ break;
+ }
+
+ // Finish decompression
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+ fclose(fp);
+ delete []row_pointer;
+ return KisImageBuilder_RESULT_OK;
+}
+
+
+
+KisImageBuilder_Result KisJPEGConverter::buildImage(const KURL& uri)
+{
+ if (uri.isEmpty())
+ return KisImageBuilder_RESULT_NO_URI;
+
+ if (!KIO::NetAccess::exists(uri, false, tqApp -> mainWidget())) {
+ return KisImageBuilder_RESULT_NOT_EXIST;
+ }
+
+ // We're not set up to handle asynchronous loading at the moment.
+ KisImageBuilder_Result result = KisImageBuilder_RESULT_FAILURE;
+ TQString tmpFile;
+
+ if (KIO::NetAccess::download(uri, tmpFile, tqApp -> mainWidget())) {
+ KURL uriTF;
+ uriTF.setPath( tmpFile );
+ result = decode(uriTF);
+ KIO::NetAccess::removeTempFile(tmpFile);
+ }
+
+ return result;
+}
+
+
+KisImageSP KisJPEGConverter::image()
+{
+ return m_img;
+}
+
+
+KisImageBuilder_Result KisJPEGConverter::buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, KisJPEGOptions options, KisExifInfo* exifInfo)
+{
+ if (!layer)
+ return KisImageBuilder_RESULT_INVALID_ARG;
+
+ KisImageSP img = layer -> image();
+ if (!img)
+ return KisImageBuilder_RESULT_EMPTY;
+
+ if (uri.isEmpty())
+ return KisImageBuilder_RESULT_NO_URI;
+
+ if (!uri.isLocalFile())
+ return KisImageBuilder_RESULT_NOT_LOCAL;
+ // Open file for writing
+ FILE *fp = fopen(TQFile::encodeName(uri.path()), "wb");
+ if (!fp)
+ {
+ return (KisImageBuilder_RESULT_FAILURE);
+ }
+ uint height = img->height();
+ uint width = img->width();
+ // Initialize structure
+ struct jpeg_compress_struct cinfo;
+ jpeg_create_compress(&cinfo);
+ // Initialize error output
+ struct jpeg_error_mgr jerr;
+ cinfo.err = jpeg_std_error(&jerr);
+ // Initialize output stream
+ jpeg_stdio_dest(&cinfo, fp);
+
+ cinfo.image_width = width; // image width and height, in pixels
+ cinfo.image_height = height;
+ cinfo.input_components = img->colorSpace()->nColorChannels(); // number of color channels per pixel */
+ J_COLOR_SPACE color_type = getColorTypeforColorSpace(img->colorSpace());
+ if(color_type == JCS_UNKNOWN)
+ {
+ KIO::del(uri);
+ return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
+ }
+ cinfo.in_color_space = color_type; // colorspace of input image
+
+
+ // Set default compression parameters
+ jpeg_set_defaults(&cinfo);
+ // Customize them
+ jpeg_set_quality(&cinfo, options.quality, true);
+
+ if(options.progressive)
+ {
+ jpeg_simple_progression (&cinfo);
+ }
+
+ // Start compression
+ jpeg_start_compress(&cinfo, true);
+ // Save exif information if any available
+ if(exifInfo)
+ {
+ kdDebug(41008) << "Trying to save exif information" << endl;
+ KisExifIO exifIO(exifInfo);
+ unsigned char* exif_data;
+ unsigned int exif_size;
+ exifIO.saveExifToMem( &exif_data, &exif_size);
+ kdDebug(41008) << "Exif informations size is " << exif_size << endl;
+ if (exif_size < MAX_DATA_BYTES_IN_MARKER)
+ {
+ jpeg_write_marker(&cinfo, JPEG_APP0 + 1, exif_data, exif_size);
+ } else {
+ kdDebug(41008) << "exif informations couldn't be saved." << endl;
+ }
+ }
+
+
+ // Save annotation
+ vKisAnnotationSP_it it = annotationsStart;
+ while(it != annotationsEnd) {
+ if (!(*it) || (*it) -> type() == TQString()) {
+ kdDebug(41008) << "Warning: empty annotation" << endl;
+ ++it;
+ continue;
+ }
+
+ kdDebug(41008) << "Trying to store annotation of type " << (*it) -> type() << " of size " << (*it) -> annotation() . size() << endl;
+
+ if ((*it) -> type().startsWith("chalk_attribute:")) { // Attribute
+ // FIXME
+ kdDebug(41008) << "can't save this annotation : " << (*it) -> type() << endl;
+ } else { // Profile
+ //char* name = new char[(*it)->type().length()+1];
+ write_icc_profile(& cinfo, (uchar*)(*it)->annotation().data(), (*it)->annotation().size());
+ }
+ ++it;
+ }
+
+
+ // Write data information
+
+ JSAMPROW row_pointer = new JSAMPLE[width*cinfo.input_components];
+ int color_nb_bits = 8 * layer->paintDevice()->pixelSize() / layer->paintDevice()->nChannels();
+
+ for (; cinfo.next_scanline < height;) {
+ KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, cinfo.next_scanline, width, false);
+ TQ_UINT8 *dst = row_pointer;
+ switch(color_type)
+ {
+ case JCS_GRAYSCALE:
+ if(color_nb_bits == 16)
+ {
+ while (!it.isDone()) {
+ const TQ_UINT16 *d = reinterpret_cast<const TQ_UINT16 *>(it.rawData());
+ *(dst++) = d[0] / TQ_UINT8_MAX;
+ ++it;
+ }
+ } else {
+ while (!it.isDone()) {
+ const TQ_UINT8 *d = it.rawData();
+ *(dst++) = d[0];
+ ++it;
+ }
+ }
+ break;
+ case JCS_RGB:
+ if(color_nb_bits == 16)
+ {
+ while (!it.isDone()) {
+ const TQ_UINT16 *d = reinterpret_cast<const TQ_UINT16 *>(it.rawData());
+ *(dst++) = d[2] / TQ_UINT8_MAX;
+ *(dst++) = d[1] / TQ_UINT8_MAX;
+ *(dst++) = d[0] / TQ_UINT8_MAX;
+ ++it;
+ }
+ } else {
+ while (!it.isDone()) {
+ const TQ_UINT8 *d = it.rawData();
+ *(dst++) = d[2];
+ *(dst++) = d[1];
+ *(dst++) = d[0];
+ ++it;
+ }
+ }
+ break;
+ case JCS_CMYK:
+ if(color_nb_bits == 16)
+ {
+ while (!it.isDone()) {
+ const TQ_UINT16 *d = reinterpret_cast<const TQ_UINT16 *>(it.rawData());
+ *(dst++) = TQ_UINT8_MAX - d[0] / TQ_UINT8_MAX;
+ *(dst++) = TQ_UINT8_MAX - d[1] / TQ_UINT8_MAX;
+ *(dst++) = TQ_UINT8_MAX - d[2] / TQ_UINT8_MAX;
+ *(dst++) = TQ_UINT8_MAX - d[3] / TQ_UINT8_MAX;
+ ++it;
+ }
+ } else {
+ while (!it.isDone()) {
+ const TQ_UINT8 *d = it.rawData();
+ *(dst++) = TQ_UINT8_MAX - d[0];
+ *(dst++) = TQ_UINT8_MAX - d[1];
+ *(dst++) = TQ_UINT8_MAX - d[2];
+ *(dst++) = TQ_UINT8_MAX - d[3];
+ ++it;
+ }
+ }
+ break;
+ default:
+ KIO::del(uri);
+ return KisImageBuilder_RESULT_UNSUPPORTED;
+ }
+ jpeg_write_scanlines(&cinfo, &row_pointer, 1);
+ }
+
+
+ // Writting is over
+ jpeg_finish_compress(&cinfo);
+ fclose(fp);
+
+ delete [] row_pointer;
+ // Free memory
+ jpeg_destroy_compress(&cinfo);
+
+ return KisImageBuilder_RESULT_OK;
+}
+
+
+void KisJPEGConverter::cancel()
+{
+ m_stop = true;
+}
+
+#include "kis_jpeg_converter.moc"
+
diff --git a/filters/chalk/jpeg/kis_jpeg_converter.h b/filters/chalk/jpeg/kis_jpeg_converter.h
new file mode 100644
index 00000000..8500d146
--- /dev/null
+++ b/filters/chalk/jpeg/kis_jpeg_converter.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _KIS_JPEG_CONVERTER_H_
+#define _KIS_JPEG_CONVERTER_H_
+
+#include <stdio.h>
+
+extern "C" {
+#include <jpeglib.h>
+}
+
+#include <tqvaluevector.h>
+
+#include <kio/job.h>
+
+#include <kis_progress_subject.h>
+
+#include "kis_types.h"
+#include "kis_global.h"
+#include "kis_annotation.h"
+class KisDoc;
+class KisUndoAdapter;
+class KisExifInfo;
+
+/**
+ * Image import/export plugins can use these results to report about success or failure.
+ */
+enum KisImageBuilder_Result {
+ KisImageBuilder_RESULT_FAILURE = -400,
+ KisImageBuilder_RESULT_NOT_EXIST = -300,
+ KisImageBuilder_RESULT_NOT_LOCAL = -200,
+ KisImageBuilder_RESULT_BAD_FETCH = -100,
+ KisImageBuilder_RESULT_INVALID_ARG = -50,
+ KisImageBuilder_RESULT_OK = 0,
+ KisImageBuilder_RESULT_PROGRESS = 1,
+ KisImageBuilder_RESULT_EMPTY = 100,
+ KisImageBuilder_RESULT_BUSY = 150,
+ KisImageBuilder_RESULT_NO_URI = 200,
+ KisImageBuilder_RESULT_UNSUPPORTED = 300,
+ KisImageBuilder_RESULT_INTR = 400,
+ KisImageBuilder_RESULT_PATH = 500,
+ KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE = 600
+};
+
+struct KisJPEGOptions {
+ int quality;
+ bool progressive;
+};
+
+class KisJPEGConverter : public KisProgressSubject {
+ Q_OBJECT
+ TQ_OBJECT
+ public:
+ KisJPEGConverter(KisDoc *doc, KisUndoAdapter *adapter);
+ virtual ~KisJPEGConverter();
+ public:
+ KisImageBuilder_Result buildImage(const KURL& uri);
+ KisImageBuilder_Result buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, KisJPEGOptions options, KisExifInfo* exifInfo);
+ /** Retrieve the constructed image
+ */
+ KisImageSP image();
+ public slots:
+ virtual void cancel();
+ private:
+ KisImageBuilder_Result decode(const KURL& uri);
+ private:
+ KisImageSP m_img;
+ KisDoc *m_doc;
+ KisUndoAdapter *m_adapter;
+ bool m_stop;
+ KIO::TransferJob *m_job;
+};
+
+#endif
diff --git a/filters/chalk/jpeg/kis_jpeg_export.cc b/filters/chalk/jpeg/kis_jpeg_export.cc
new file mode 100644
index 00000000..edfbbc02
--- /dev/null
+++ b/filters/chalk/jpeg/kis_jpeg_export.cc
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_jpeg_export.h"
+
+#include <tqcheckbox.h>
+#include <tqslider.h>
+
+#include <kapplication.h>
+#include <kdialogbase.h>
+#include <kgenericfactory.h>
+
+#include <KoFilterChain.h>
+
+#include <kis_doc.h>
+#include <kis_image.h>
+#include <kis_group_layer.h>
+#include <kis_paint_layer.h>
+#include <kis_progress_display_interface.h>
+#include <kis_layer_visitor.h>
+
+#include "kis_jpeg_converter.h"
+#include "kis_wdg_options_jpeg.h"
+
+
+class KisExifInfoVisitor : public KisLayerVisitor
+{
+ public:
+ KisExifInfoVisitor() :
+ m_exifInfo(0),
+ m_countPaintLayer(0)
+ { };
+ public:
+ virtual bool visit(KisPaintLayer* layer) {
+ m_countPaintLayer++;
+ if( layer->paintDevice()->hasExifInfo())
+ m_exifInfo = layer->paintDevice()->exifInfo();
+ return true;
+ };
+ virtual bool visit(KisGroupLayer* layer)
+ {
+ kdDebug(41008) << "Visiting on grouplayer " << layer->name() << "\n";
+ KisLayerSP child = layer->firstChild();
+ while (child) {
+ child->accept(*this);
+ child = child->nextSibling();
+ }
+ return true;
+ }
+ virtual bool visit(KisPartLayer *) { return true; };
+ virtual bool visit(KisAdjustmentLayer* ) { return true; };
+ public:
+ inline uint countPaintLayer() { return m_countPaintLayer; }
+ inline KisExifInfo* exifInfo() {return m_exifInfo; }
+ private:
+ KisExifInfo* m_exifInfo;
+ uint m_countPaintLayer;
+};
+
+
+typedef KGenericFactory<KisJPEGExport, KoFilter> KisJPEGExportFactory;
+K_EXPORT_COMPONENT_FACTORY(libchalkjpegexport, KisJPEGExportFactory("kofficefilters"))
+
+KisJPEGExport::KisJPEGExport(KoFilter *, const char *, const TQStringList&) : KoFilter()
+{
+}
+
+KisJPEGExport::~KisJPEGExport()
+{
+}
+
+KoFilter::ConversiontqStatus KisJPEGExport::convert(const TQCString& from, const TQCString& to)
+{
+ kdDebug(41008) << "JPEG export! From: " << from << ", To: " << to << "\n";
+
+ if (from != "application/x-chalk")
+ return KoFilter::NotImplemented;
+
+
+ KDialogBase* kdb = new KDialogBase(0, "", false, i18n("JPEG Export Options"), KDialogBase::Ok | KDialogBase::Cancel);
+
+ KisWdgOptionsJPEG* wdg = new KisWdgOptionsJPEG(kdb);
+ kdb->setMainWidget(wdg);
+ kapp->restoreOverrideCursor();
+ if(kdb->exec() == TQDialog::Rejected)
+ {
+ return KoFilter::OK; // FIXME Cancel doesn't exist :(
+ }
+ KisJPEGOptions options;
+ options.progressive = wdg->progressive->isChecked();
+ options.quality = wdg->qualityLevel->value();
+
+ delete kdb;
+ // XXX: Add dialog about flattening layers here
+
+ KisDoc *output = dynamic_cast<KisDoc*>(m_chain->inputDocument());
+ TQString filename = m_chain->outputFile();
+
+ if (!output)
+ return KoFilter::CreationError;
+
+
+ if (filename.isEmpty()) return KoFilter::FileNotFound;
+
+ KURL url;
+ url.setPath(filename);
+
+ KisImageSP img = output->currentImage();
+ Q_CHECK_PTR(img);
+
+ KisJPEGConverter kpc(output, output->undoAdapter());
+
+ KisPaintDeviceSP pd = new KisPaintDevice(*img->projection());
+ KisPaintLayerSP l = new KisPaintLayer(img, "projection", OPACITY_OPAQUE, pd);
+
+ vKisAnnotationSP_it beginIt = img->beginAnnotations();
+ vKisAnnotationSP_it endIt = img->endAnnotations();
+ KisImageBuilder_Result res;
+
+ KisExifInfoVisitor eIV;
+ eIV.visit( img->rootLayer() );
+
+ KisExifInfo* eI = 0;
+ if(eIV.countPaintLayer() == 1)
+ eI = eIV.exifInfo();
+
+ if ( (res = kpc.buildFile(url, l, beginIt, endIt, options, eI)) == KisImageBuilder_RESULT_OK) {
+ kdDebug(41008) << "success !" << endl;
+ return KoFilter::OK;
+ }
+ kdDebug(41008) << " Result = " << res << endl;
+ return KoFilter::InternalError;
+}
+
+#include <kis_jpeg_export.moc>
+
diff --git a/filters/chalk/jpeg/kis_jpeg_export.h b/filters/chalk/jpeg/kis_jpeg_export.h
new file mode 100644
index 00000000..a0f47351
--- /dev/null
+++ b/filters/chalk/jpeg/kis_jpeg_export.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _KIS_JPEG_EXPORT_H_
+#define _KIS_JPEG_EXPORT_H_
+
+#include <KoFilter.h>
+
+class KisJPEGExport : public KoFilter {
+ Q_OBJECT
+ TQ_OBJECT
+ public:
+ KisJPEGExport(KoFilter *tqparent, const char *name, const TQStringList&);
+ virtual ~KisJPEGExport();
+ public:
+ virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to);
+};
+
+#endif
diff --git a/filters/chalk/jpeg/kis_jpeg_import.cc b/filters/chalk/jpeg/kis_jpeg_import.cc
new file mode 100644
index 00000000..2ca7c4c2
--- /dev/null
+++ b/filters/chalk/jpeg/kis_jpeg_import.cc
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_jpeg_import.h"
+
+#include <kgenericfactory.h>
+
+#include <KoFilterChain.h>
+
+#include <kis_doc.h>
+#include <kis_image.h>
+#include <kis_progress_display_interface.h>
+#include <kis_view.h>
+
+#include "kis_jpeg_converter.h"
+
+typedef KGenericFactory<KisJPEGImport, KoFilter> JPEGImportFactory;
+K_EXPORT_COMPONENT_FACTORY(libchalkjpegimport, JPEGImportFactory("kofficefilters"))
+
+KisJPEGImport::KisJPEGImport(KoFilter *, const char *, const TQStringList&) : KoFilter()
+{
+}
+
+KisJPEGImport::~KisJPEGImport()
+{
+}
+
+KoFilter::ConversiontqStatus KisJPEGImport::convert(const TQCString&, const TQCString& to)
+{
+ kdDebug(41008) << "Importing using JPEGImport!\n";
+
+ if (to != "application/x-chalk")
+ return KoFilter::BadMimeType;
+
+ KisDoc * doc = dynamic_cast<KisDoc*>(m_chain -> outputDocument());
+ KisView * view = static_cast<KisView*>(doc -> views().getFirst());
+
+ TQString filename = m_chain -> inputFile();
+
+ if (!doc)
+ return KoFilter::CreationError;
+
+ doc->prepareForImport();
+
+
+ if (!filename.isEmpty()) {
+
+ KURL url;
+ url.setPath(filename);
+
+ if (url.isEmpty())
+ return KoFilter::FileNotFound;
+
+ KisJPEGConverter ib(doc, doc -> undoAdapter());
+
+ if (view != 0)
+ view -> canvasSubject() -> progressDisplay() -> setSubject(&ib, false, true);
+
+ switch (ib.buildImage(url)) {
+ case KisImageBuilder_RESULT_UNSUPPORTED:
+ return KoFilter::NotImplemented;
+ break;
+ case KisImageBuilder_RESULT_INVALID_ARG:
+ return KoFilter::BadMimeType;
+ break;
+ case KisImageBuilder_RESULT_NO_URI:
+ case KisImageBuilder_RESULT_NOT_LOCAL:
+ return KoFilter::FileNotFound;
+ break;
+ case KisImageBuilder_RESULT_BAD_FETCH:
+ case KisImageBuilder_RESULT_EMPTY:
+ return KoFilter::ParsingError;
+ break;
+ case KisImageBuilder_RESULT_FAILURE:
+ return KoFilter::InternalError;
+ break;
+ case KisImageBuilder_RESULT_OK:
+ doc -> setCurrentImage( ib.image());
+ return KoFilter::OK;
+ default:
+ break;
+ }
+
+ }
+ return KoFilter::StorageCreationError;
+}
+
+#include <kis_jpeg_import.moc>
+
diff --git a/filters/chalk/jpeg/kis_jpeg_import.h b/filters/chalk/jpeg/kis_jpeg_import.h
new file mode 100644
index 00000000..4cfb62c2
--- /dev/null
+++ b/filters/chalk/jpeg/kis_jpeg_import.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef _KIS_JPEG_IMPORT_H_
+#define _KIS_JPEG_IMPORT_H_
+
+#include <KoFilter.h>
+
+class KisJPEGImport : public KoFilter {
+ Q_OBJECT
+ TQ_OBJECT
+ public:
+ KisJPEGImport(KoFilter *tqparent, const char *name, const TQStringList&);
+ virtual ~KisJPEGImport();
+ public:
+ virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to);
+};
+
+#endif
diff --git a/filters/chalk/jpeg/kis_wdg_options_jpeg.ui b/filters/chalk/jpeg/kis_wdg_options_jpeg.ui
new file mode 100644
index 00000000..06c39edc
--- /dev/null
+++ b/filters/chalk/jpeg/kis_wdg_options_jpeg.ui
@@ -0,0 +1,149 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KisWdgOptionsJPEG</class>
+<widget class="TQWidget">
+ <property name="name">
+ <cstring>KisWdgOptionsJPEG</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>167</width>
+ <height>87</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>tqlayout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Quality:</string>
+ </property>
+ <property name="tqalignment">
+ <set>AlignTop</set>
+ </property>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>tqlayout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQSlider">
+ <property name="name">
+ <cstring>qualityLevel</cstring>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="lineStep">
+ <number>1</number>
+ </property>
+ <property name="pageStep">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>80</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="tickmarks">
+ <enum>Below</enum>
+ </property>
+ <property name="tickInterval">
+ <number>10</number>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>These settings determine how much information is lost during compression</string>
+ </property>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>tqlayout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Smallest</string>
+ </property>
+ </widget>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Best</string>
+ </property>
+ <property name="tqalignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="TQCheckBox">
+ <property name="name">
+ <cstring>progressive</cstring>
+ </property>
+ <property name="text">
+ <string>Pr&amp;ogressive</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Use progressive when publishing on the Internet</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Progressive is useful if you intend to publish your image on the Internet.&lt;br&gt;
+Enabling progressive will cause the image to be displayed by the browser even while downloading.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="tqsizeHint">
+ <size>
+ <width>20</width>
+ <height>61</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<tqlayoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/filters/chalk/libkisexif/Makefile.am b/filters/chalk/libkisexif/Makefile.am
new file mode 100644
index 00000000..96ccd5b5
--- /dev/null
+++ b/filters/chalk/libkisexif/Makefile.am
@@ -0,0 +1,20 @@
+INCLUDES = \
+ -I$(srcdir) \
+ $(KOFFICE_INCLUDES) \
+ -I$(top_srcdir)/chalk \
+ -I$(top_srcdir)/chalk/core \
+ -I$(top_srcdir)/chalk/sdk \
+ -I$(top_srcdir)/chalk/core/tiles \
+ -I$(top_srcdir)/chalk/chalkcolor \
+ -I$(top_srcdir)/chalk/ui \
+ $(KOFFICE_INCLUDES) -I$(interfacedir) \
+ $(KOPAINTER_INCLUDES) \
+ $(all_includes)
+METASOURCES = AUTO
+libkisexif_la_LDFLAGS = $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+noinst_LTLIBRARIES = libkisexif.la
+
+
+libkisexif_la_SOURCES = kis_exif_io.cpp
diff --git a/filters/chalk/libkisexif/kis_exif_io.cpp b/filters/chalk/libkisexif/kis_exif_io.cpp
new file mode 100644
index 00000000..f02b49b7
--- /dev/null
+++ b/filters/chalk/libkisexif/kis_exif_io.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_exif_io.h"
+
+#include <kdebug.h>
+
+extern "C" {
+#include <libexif/exif-tag.h>
+#include <libexif/exif-log.h>
+}
+
+KisExifIO::KisExifIO(KisExifInfo* ei) : m_exifInfo(ei)
+{
+}
+
+void KisExifIO::readExifFromFile( const char* fileName)
+{
+ readExifData( exif_data_new_from_file(fileName) );
+}
+
+void KisExifIO::readExifFromMem( const unsigned char* data , unsigned int size)
+{
+ readExifData( exif_data_new_from_data(data, size) );
+}
+
+void KisExifIO::saveExifToMem( unsigned char** data, unsigned int *size)
+{
+ ExifData* exifData = exif_data_new();
+ writeExifData( exifData );
+ exif_data_save_data( exifData, data, size);
+}
+
+ExifValue::ExifType KisExifIO::format2type(ExifFormat format)
+{
+ switch(format)
+ {
+ case EXIF_FORMAT_BYTE:
+ return ExifValue::EXIF_TYPE_BYTE;
+ case EXIF_FORMAT_ASCII:
+ return ExifValue::EXIF_TYPE_ASCII;
+ case EXIF_FORMAT_SHORT:
+ return ExifValue::EXIF_TYPE_SHORT;
+ case EXIF_FORMAT_LONG:
+ return ExifValue::EXIF_TYPE_LONG;
+ case EXIF_FORMAT_RATIONAL:
+ return ExifValue::EXIF_TYPE_RATIONAL;
+ case EXIF_FORMAT_SBYTE:
+ return ExifValue::EXIF_TYPE_SBYTE;
+ case EXIF_FORMAT_SSHORT:
+ return ExifValue::EXIF_TYPE_SSHORT;
+ case EXIF_FORMAT_SLONG:
+ return ExifValue::EXIF_TYPE_SLONG;
+ case EXIF_FORMAT_SRATIONAL:
+ return ExifValue::EXIF_TYPE_SRATIONAL;
+ case EXIF_FORMAT_FLOAT:
+ return ExifValue::EXIF_TYPE_FLOAT;
+ case EXIF_FORMAT_DOUBLE:
+ return ExifValue::EXIF_TYPE_DOUBLE;
+ default:
+ case EXIF_FORMAT_UNDEFINED:
+ return ExifValue::EXIF_TYPE_UNDEFINED;
+ }
+}
+
+void KisExifIO::readExifData( ExifData* exifData)
+{
+ ExifValue::ByteOrder bO;
+ if(exif_data_get_byte_order( exifData) == EXIF_BYTE_ORDER_MOTOROLA)
+ {
+ bO = ExifValue::BYTE_ORDER_MOTOROLA;
+ } else {
+ bO = ExifValue::BYTE_ORDER_INTEL;
+ }
+ static ExifIfd ifds[5] = {
+ EXIF_IFD_0,
+ EXIF_IFD_1,
+ EXIF_IFD_EXIF,
+ EXIF_IFD_INTEROPERABILITY,
+ EXIF_IFD_GPS
+ };
+ for(int ifd = 0; ifd < 5; ifd ++)
+ {
+ ExifContent* content = exifData->ifd[ifds[ifd]];
+ kdDebug() << "There are " << content->count << " values in ifd=" << ifd << endl;
+ for (uint i = 0; i < content->count; i++)
+ {
+ ExifEntry* entry = content->entries[i];
+ TQString tagname = exif_tag_get_name ( entry->tag );
+// kdDebug() << "found tag : " << tagname << endl;
+ // TQString tagname = exif_tag_get_name_in_ifd ( entry->tag, EXIF_IFD_0 ); TODO: would be better to rely on 0.6.13 when it becomes more common, as it supports better other IFD (GPS and interoperrabilibity)
+ ExifValue value( format2type(entry->format), entry->data, entry->size, ifds[ifd], entry->components, bO );
+// exif_entry_dump( entry, 4);
+// kdDebug() << "value = " << value.toString() << endl;
+ m_exifInfo->setValue( tagname, value);
+ }
+ }
+
+}
+
+ExifFormat KisExifIO::type2format( ExifValue::ExifType type)
+{
+ switch(type)
+ {
+ case ExifValue::EXIF_TYPE_BYTE:
+ return EXIF_FORMAT_BYTE;
+ case ExifValue::EXIF_TYPE_ASCII:
+ return EXIF_FORMAT_ASCII;
+ case ExifValue::EXIF_TYPE_SHORT:
+ return EXIF_FORMAT_SHORT;
+ case ExifValue::EXIF_TYPE_LONG:
+ return EXIF_FORMAT_LONG;
+ case ExifValue::EXIF_TYPE_RATIONAL:
+ return EXIF_FORMAT_RATIONAL;
+ case ExifValue::EXIF_TYPE_SBYTE:
+ return EXIF_FORMAT_SBYTE;
+ case ExifValue::EXIF_TYPE_SSHORT:
+ return EXIF_FORMAT_SSHORT;
+ case ExifValue::EXIF_TYPE_SLONG:
+ return EXIF_FORMAT_SLONG;
+ case ExifValue::EXIF_TYPE_SRATIONAL:
+ return EXIF_FORMAT_SRATIONAL;
+ case ExifValue::EXIF_TYPE_FLOAT:
+ return EXIF_FORMAT_FLOAT;
+ case ExifValue::EXIF_TYPE_DOUBLE:
+ return EXIF_FORMAT_DOUBLE;
+ default:
+ case ExifValue::EXIF_TYPE_UNDEFINED:
+ return EXIF_FORMAT_UNDEFINED;
+ }
+}
+
+
+void KisExifIO::writeExifData( ExifData* exifData)
+{
+ ExifValue::ByteOrder bO;
+ if(exif_data_get_byte_order( exifData) == EXIF_BYTE_ORDER_MOTOROLA)
+ {
+ bO = ExifValue::BYTE_ORDER_MOTOROLA;
+ } else {
+ bO = ExifValue::BYTE_ORDER_INTEL;
+ }
+
+ for( KisExifInfo::evMap::const_iterator it = m_exifInfo->begin(); it != m_exifInfo->end(); ++it)
+ {
+ ExifValue ev = it.data();
+ if(ev.ifd() != -1)
+ {
+ ExifEntry * entry = exif_entry_new();
+ ExifContent* content = exifData->ifd[ev.ifd()];
+ exif_content_add_entry(content, entry);
+ kdDebug() << "Saving tag:" << it.key() << " " << ev.toString() << endl;
+ ExifTag tag = exif_tag_from_name( it.key().ascii());
+ entry->components = ev.components();
+ entry->format = type2format( ev.type());
+ entry->tag = tag;
+// exif_entry_dump(entry, 2);
+ ev.convertToData(&entry->data, &entry->size, bO);
+ }
+ }
+}
diff --git a/filters/chalk/libkisexif/kis_exif_io.h b/filters/chalk/libkisexif/kis_exif_io.h
new file mode 100644
index 00000000..58928811
--- /dev/null
+++ b/filters/chalk/libkisexif/kis_exif_io.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KIS_EXIF_IO_H
+#define KIS_EXIF_IO_H
+
+extern "C" {
+#include <libexif/exif-data.h>
+}
+
+#include <kis_exif_info.h>
+
+class KisExifIO {
+ public:
+ KisExifIO( KisExifInfo* ei);
+ public:
+ void readExifFromFile( const char* fileName );
+ void readExifFromMem( const unsigned char* data , unsigned int size);
+ void saveExifToMem( unsigned char** data , unsigned int *size);
+ private:
+ void readExifData( ExifData* exifData );
+ void writeExifData( ExifData* exifData );
+ ExifFormat type2format( ExifValue::ExifType type);
+ ExifValue::ExifType format2type(ExifFormat format);
+ private:
+ KisExifInfo* m_exifInfo;
+};
+
+#endif
diff --git a/filters/chalk/magick/Makefile.am b/filters/chalk/magick/Makefile.am
new file mode 100644
index 00000000..b64ea1ce
--- /dev/null
+++ b/filters/chalk/magick/Makefile.am
@@ -0,0 +1,44 @@
+kde_module_LTLIBRARIES = libchalkmagickimport.la libchalkmagickexport.la
+
+libchalkmagickexport_la_LDFLAGS = $(KDE_PLUGIN) $(LIBMAGICK_LDFLAGS) $(KDE_RPATH) $(LIBMAGICK_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalkmagickexport_la_LIBADD = \
+ $(KOFFICE_LIBS) \
+ $(LIBMAGICK_LIBS) \
+ $(top_builddir)/chalk/libchalkcommon.la
+
+libchalkmagickimport_la_LDFLAGS = $(KDE_PLUGIN) $(LIBMAGICK_LDFLAGS) $(KDE_RPATH) $(LIBMAGICK_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalkmagickimport_la_LIBADD = \
+ $(KOFFICE_LIBS) \
+ $(LIBMAGICK_LIBS) \
+ $(top_builddir)/chalk/libchalkcommon.la
+
+INCLUDES= \
+ -I$(srcdir) \
+ $(KOFFICE_INCLUDES) \
+ -I$(top_srcdir)/chalk \
+ -I$(top_srcdir)/chalk/core \
+ -I$(top_srcdir)/chalk/sdk \
+ -I$(top_srcdir)/chalk/core/tiles \
+ -I$(top_srcdir)/chalk/chalkcolor \
+ -I$(top_srcdir)/chalk/ui \
+ $(KOFFICE_INCLUDES) -I$(interfacedir) \
+ $(KOPAINTER_INCLUDES) $(LIBMAGICK_CPPFLAGS) \
+ $(all_includes)
+
+service_DATA = chalk_magick_import.desktop chalk_magick_export.desktop
+servicedir = $(kde_servicesdir)
+
+kdelnk_DATA = chalk_magick.desktop
+kdelnkdir = $(kde_appsdir)/Office
+
+libchalkmagickimport_la_SOURCES = magickimport.cpp kis_image_magick_converter.cc
+libchalkmagickexport_la_SOURCES = magickexport.cpp kis_image_magick_converter.cc
+
+METASOURCES = AUTO
+
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
diff --git a/filters/chalk/magick/chalk_magick.desktop b/filters/chalk/magick/chalk_magick.desktop
new file mode 100644
index 00000000..621ad158
--- /dev/null
+++ b/filters/chalk/magick/chalk_magick.desktop
@@ -0,0 +1,58 @@
+[Desktop Entry]
+Name=Chalk
+Name[hi]=के-रिता
+Name[km]= Chalk
+Name[lo]=ກຣິຕາ
+Name[ne]=क्रिता
+Exec=chalk %u
+GenericName=Painting and Image Editing Application
+GenericName[bg]=Редактор на графични изображения
+GenericName[ca]=Programa de dibuix i manipulació d'imatges
+GenericName[cs]=Malování a úpravy obrázků
+GenericName[cy]=Cymhwysiad Peintio Golygu Delweddau
+GenericName[da]=Male- og billedredigeringsprogram
+GenericName[de]=Mal- und Bildbearbeitungsprogramm
+GenericName[el]=Εφαρμογή επεξεργασίας εικόνων
+GenericName[eo]=Aplikaĵo por Pentrado kaj Bildredaktado
+GenericName[es]=Aplicación de pintura y de edición de imágenes
+GenericName[et]=Joonistamise ja pilditöötluse rakendus
+GenericName[eu]=Irudien marrazketa eta ediziorako aplikazioa
+GenericName[fa]=کاربرد ویرایش تصویر و نقاشی
+GenericName[fi]=Maalaus- ja kuvankäsitelyohjelma
+GenericName[fr]=Application de dessin et de manipulation d'images
+GenericName[fy]=Ofbyldingsmanipulaasje
+GenericName[gl]=Aplicación de Pintura e Manipulación de Imaxes
+GenericName[he]=יישום לציור ועריכת תמונות
+GenericName[hr]=Aplikacija za obradu slika i fotografija
+GenericName[hu]=Képszerkesztő
+GenericName[is]=Málun og myndritill
+GenericName[it]=Applicazione di disegno e di modifica delle immagini
+GenericName[ja]=描画と画像編集のためのアプリケーション
+GenericName[km]=កម្មវិធី​គូរ​គំនូរ និង​កែសម្រួល​រូបភាព
+GenericName[lv]=Zīmēšanas un attēlu apstrādes programma
+GenericName[nb]=Program for tegning og bilderedigering
+GenericName[nds]=Programm för't Malen un Bildbewerken
+GenericName[ne]=पेन्टीङ्ग र छवि सम्पादन अनुप्रयोग
+GenericName[nl]=Afbeeldingsmanipulatie
+GenericName[pl]=Program do edycji zdjęć oraz rysunków
+GenericName[pt]=Aplicação de Pintura e Edição de Imagens
+GenericName[pt_BR]=Aplicação de Pintura e Edição de Imagens
+GenericName[ru]=Растровые изображения
+GenericName[se]=Málen- ja govvagieđahallanprográmma
+GenericName[sk]=Program pre tvorbu a úpravu obrázkov
+GenericName[sl]=Program za risanje in obdelavo slik
+GenericName[sr]=Програм за цртање и уређивање слика
+GenericName[sr@Latn]=Program za crtanje i uređivanje slika
+GenericName[sv]=Målnings- och bildredigeringsprogram
+GenericName[uk]=Програма для малювання і редагування зображень
+GenericName[uz]=Rasmlar bilan ishlaydigan dastur
+GenericName[uz@cyrillic]=Расмлар билан ишлайдиган дастур
+GenericName[zh_CN]=绘图和图像编辑应用程序
+GenericName[zh_TW]=繪圖與影像處理程式
+MimeType=image/x-xcf-gimp;image/gif;image/cgm;image/x-bmp;image/x-ico;image/x-pcx;image/x-portable-pixmap;image/x-targa;image/x-xbm;image/x-xcf;image/x-xpm;image/x-vnd.adobe.photoshop;image/x-rgb
+Type=Application
+Icon=chalk
+Categories=Qt;KDE;Office;Graphics;
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Multi
+NoDisplay=true
diff --git a/filters/chalk/magick/chalk_magick_export.desktop b/filters/chalk/magick/chalk_magick_export.desktop
new file mode 100644
index 00000000..9bbdedc8
--- /dev/null
+++ b/filters/chalk/magick/chalk_magick_export.desktop
@@ -0,0 +1,55 @@
+[Desktop Entry]
+Name=Chalk Magick Export Filter
+Name[bg]=Филтър за експортиране от Chalk в Magick
+Name[br]=Sil ezporzh Magick evit Chalk
+Name[ca]=Filtre d'exportació Magick per a Chalk
+Name[cy]=Hidl Allforio Magick Chalk
+Name[da]=Chalk Magick-eksportfilter
+Name[de]=Chalk Magick-Exportfilter
+Name[el]=Φίλτρο εξαγωγής Magick του Chalk
+Name[eo]=Chalk Magick-eksportfiltrilo
+Name[es]=Filtro de exportación a Magick de Chalk
+Name[et]=Chalk Magick'i ekspordifilter
+Name[eu]=Chalk-ren Magick esportaziorako iragazkia
+Name[fa]=پالایۀ صادرات Chalk Magick
+Name[fi]=Chalk Magick -vientisuodin
+Name[fr]=Filtre d'exportation Magick de Chalk
+Name[fy]=Chalk Magick Eksportfilter
+Name[ga]=Scagaire Easpórtála Magick Chalk
+Name[gl]=Filtro de Exportación de Magick para Chalk
+Name[he]=מסנן יצוא מ־Chalk ל־Magick
+Name[hr]=Chalk Magick filtar izvoza
+Name[hu]=Chalk Magick exportszűrő
+Name[is]=Chalk Magick útflutningssía
+Name[it]=Filtro di esportazione Magick per Chalk
+Name[ja]=Chalk Magick エクスポートフィルタ
+Name[km]=តម្រង​នាំចេញ Magick សម្រាប់ Chalk
+Name[lt]=Chalk Magick eksportavimo filtras
+Name[lv]=Chalk Magick eksporta filtrs
+Name[ms]=Penapis Eksport Chalk Magick
+Name[nb]=Magick-eksportfilter for Chalk
+Name[nds]=Magick-Exportfilter för Chalk
+Name[ne]=क्रिता म्याजिक निर्यात फिल्टर
+Name[nl]=Chalk Magick Exportfilter
+Name[nn]=Magick-eksportfilter for Chalk
+Name[pl]=Filtr eksportu do formatu Magick z Chalk
+Name[pt]=Filtro de Exportação de Magick para o Chalk
+Name[pt_BR]=Filtro de exportação Magick para o Chalk
+Name[ru]=Фильтр экспорта рисунков Chalk в Magick
+Name[se]=Chalk Magick-olggosfievrridansilli
+Name[sk]=Magick filter pre export do Chalk
+Name[sl]=Izvozni filter Magick za Krito
+Name[sr]=Chalk-ин филтер за извоз у Magick
+Name[sr@Latn]=Chalk-in filter za izvoz u Magick
+Name[sv]=Chalk Magick-exportfilter
+Name[uk]=Фільтр експорту Magick для Chalk
+Name[uz]=Chalk Magick eksport filteri
+Name[uz@cyrillic]=Chalk Magick экспорт филтери
+Name[zh_CN]=Chalk Magick 导出过滤器
+Name[zh_TW]=Chalk Magick 匯出過濾程式
+X-KDE-Export=image/gif,image/cgm,image/x-ico,image/x-pcx,image/x-portable-pixmap,image/x-targa,image/x-xbm,image/x-xpm,image/x-rgb,image/x-eps
+ServiceTypes=KOfficeFilter
+Type=Service
+X-KDE-Import=application/x-chalk
+X-KDE-Weight=1
+X-KDE-Library=libchalkmagickexport
diff --git a/filters/chalk/magick/chalk_magick_import.desktop b/filters/chalk/magick/chalk_magick_import.desktop
new file mode 100644
index 00000000..0d32448f
--- /dev/null
+++ b/filters/chalk/magick/chalk_magick_import.desktop
@@ -0,0 +1,61 @@
+[Desktop Entry]
+Type=Service
+Name=Chalk Magick Import Filter
+Name[bg]=Филтър за импортиране от Magick в Chalk
+Name[br]=Sil enporzh Magick evit Chalk
+Name[ca]=Filtre d'importació Magick per a Chalk
+Name[cs]=Importní filtr formátu Magick pro Kritu
+Name[cy]=Hidl Mewnforio Chalk Magick
+Name[da]=Chalk Magick-importfilter
+Name[de]=Chalk Magick-Importfilter
+Name[el]=Φίλτρο εισαγωγής Magick του Chalk
+Name[eo]=Chalk Magick-importfiltrilo
+Name[es]=Filtro de importación a Magick de Chalk
+Name[et]=Chalk Magick'i impordifilter
+Name[eu]=Chalk-ren Magick inportaziorako iragazkia
+Name[fa]=پالایۀ واردات Chalk Magick
+Name[fi]=Chalk Magick-tuontisuodin
+Name[fr]=Filtre d'importation Magick de Chalk
+Name[fy]=Chalk Magick Ymportfilter
+Name[ga]=Scagaire Iompórtála Magick Chalk
+Name[gl]=Filtro de Importación de Magick para Chalk
+Name[he]=מסנן יבוא מ־Magick ל־Chalk
+Name[hi]=के-रीता मैजिक आयात फ़िल्टर
+Name[hr]=Chalk Magick filtar uvoza
+Name[hu]=Chalk Magick importszűrő
+Name[is]=Chalk Magick innflutningssía
+Name[it]=Filtro di importazione Magick per Chalk
+Name[ja]=Chalk Magick インポートフィルタ
+Name[km]=តម្រង​នាំចូល Magick សម្រាប់ Chalk
+Name[lo]= ຕົວຕອງການນຳເຂົ້າ WML ຂອງເອກະສານຂໍ້ຄວາມ K
+Name[lt]=Chalk Magick importavimo filtras
+Name[lv]=Chalk Magick importa filtrs
+Name[ms]=Penapis Import Chalk Magick
+Name[nb]=Magick-importfilter for Chalk
+Name[nds]=Magick-Importfilter för Chalk
+Name[ne]=क्रिता म्याजिक आयात फिल्टर
+Name[nl]=Chalk Magick Importfilter
+Name[nn]=Magick-importfilter for Chalk
+Name[pl]=Filtr importu formatu Magick do Chalk
+Name[pt]=Filtro de Importação de Magick para o Chalk
+Name[pt_BR]=Filtro de importação Magick para o Chalk
+Name[ru]=Фильтр импорта рисунков Magick в Chalk
+Name[se]=Chalk Magick-sisafievrridansilli
+Name[sk]=Magick filter pre import do Chalk
+Name[sl]=Uvozni filter Magick za Krito
+Name[sr]=Chalk-ин филтер за увоз из Magick-а
+Name[sr@Latn]=Chalk-in filter za uvoz iz Magick-a
+Name[sv]=Chalk Magick-importfilter
+Name[ta]=Chalk மாயk இறக்குமதி வடிகட்டி
+Name[tg]=Филтри Воридоти Chalk Magick
+Name[tr]=Chalk Magick Alma Filtresi
+Name[uk]=Фільтр імпорту Magick для Chalk
+Name[uz]=Chalk Magick import filteri
+Name[uz@cyrillic]=Chalk Magick импорт филтери
+Name[zh_CN]=Chalk Magick 导入过滤器
+Name[zh_TW]=Chalk Magick 匯入過濾程式
+X-KDE-Export=application/x-chalk
+X-KDE-Import=image/x-xcf-gimp,image/gif,image/cgm,image/x-bmp,image/x-ico,image/x-pcx,image/x-portable-pixmap,image/x-targa,image/x-xbm,image/x-xcf,image/x-xpm,image/x-vnd.adobe.photoshop,image/x-rgb,image/x-eps
+X-KDE-Weight=1
+X-KDE-Library=libchalkmagickimport
+ServiceTypes=KOfficeFilter
diff --git a/filters/chalk/magick/configure.in.bot b/filters/chalk/magick/configure.in.bot
new file mode 100644
index 00000000..2d3cb2ca
--- /dev/null
+++ b/filters/chalk/magick/configure.in.bot
@@ -0,0 +1,15 @@
+# ImageMagick is deprecated, we don't care anymore if it's not here
+#
+#if test -z "$LIBMAGICK_LIBS"; then
+# echo ""
+# echo "You're missing ImageMagick (>=6.1.0). chalk's ImageMagick import/export"
+# echo "filter will not be compiled. You can download ImageMagick from"
+# echo "http://www.imagemagick.org/. The ImageMagick filter allows chalk to"
+# echo "read and write XCF, PSD, GIF, BMP, and many other image formats."
+# echo ""
+# echo "If you have problems compiling ImageMagick, please try configuring it using"
+# echo "the --without-magick-plus-plus flag, the C++ API isn't needed for chalk."
+# echo ""
+# all_tests=bad
+#fi
+
diff --git a/filters/chalk/magick/kis_image_magick_converter.cc b/filters/chalk/magick/kis_image_magick_converter.cc
new file mode 100644
index 00000000..ee6267ad
--- /dev/null
+++ b/filters/chalk/magick/kis_image_magick_converter.cc
@@ -0,0 +1,1087 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <magick/api.h>
+
+#include <tqfile.h>
+#include <tqfileinfo.h>
+#include <tqstring.h>
+
+#include <kdeversion.h>
+#include <kdebug.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kurl.h>
+#include <kio/netaccess.h>
+
+#include <tqcolor.h>
+
+#include "kis_types.h"
+#include "kis_global.h"
+#include "kis_doc.h"
+#include "kis_image.h"
+#include "kis_layer.h"
+#include "kis_undo_adapter.h"
+#include "kis_image_magick_converter.h"
+#include "kis_meta_registry.h"
+#include "kis_colorspace_factory_registry.h"
+#include "kis_iterators_pixel.h"
+#include "kis_colorspace.h"
+#include "kis_profile.h"
+#include "kis_annotation.h"
+#include "kis_paint_layer.h"
+#include "kis_group_layer.h"
+#include "kis_paint_device.h"
+
+#include "../../../config.h"
+
+namespace {
+
+ const TQ_UINT8 PIXEL_BLUE = 0;
+ const TQ_UINT8 PIXEL_GREEN = 1;
+ const TQ_UINT8 PIXEL_RED = 2;
+ const TQ_UINT8 PIXEL_ALPHA = 3;
+
+ static const TQ_UINT8 PIXEL_CYAN = 0;
+ static const TQ_UINT8 PIXEL_MAGENTA = 1;
+ static const TQ_UINT8 PIXEL_YELLOW = 2;
+ static const TQ_UINT8 PIXEL_BLACK = 3;
+ static const TQ_UINT8 PIXEL_CMYK_ALPHA = 4;
+
+ static const TQ_UINT8 PIXEL_GRAY = 0;
+ static const TQ_UINT8 PIXEL_GRAY_ALPHA = 1;
+
+ /**
+ * Make this more flexible -- although... ImageMagick
+ * isn't that flexible either.
+ */
+ TQString getColorSpaceName(ColorspaceType type, unsigned long imageDepth = 8)
+ {
+
+ if (type == GRAYColorspace) {
+ if (imageDepth == 8)
+ return "GRAYA";
+ else if ( imageDepth == 16 )
+ return "GRAYA16" ;
+ }
+ else if (type == CMYKColorspace) {
+ if (imageDepth == 8)
+ return "CMYK";
+ else if ( imageDepth == 16 ) {
+ return "CMYK16";
+ }
+ }
+ else if (type == LABColorspace) {
+ kdDebug(41008) << "Lab!\n";
+ return "LABA";
+ }
+ else if (type == RGBColorspace || type == sRGBColorspace || type == TransparentColorspace) {
+ if (imageDepth == 8)
+ return "RGBA";
+ else if (imageDepth == 16)
+ return "RGBA16";
+ }
+ return "";
+
+ }
+
+ ColorspaceType getColorTypeforColorSpace( KisColorSpace * cs )
+ {
+ if ( cs->id() == KisID("GRAYA") || cs->id() == KisID("GRAYA16") ) return GRAYColorspace;
+ if ( cs->id() == KisID("RGBA") || cs->id() == KisID("RGBA16") ) return RGBColorspace;
+ if ( cs->id() == KisID("CMYK") || cs->id() == KisID("CMYK16") ) return CMYKColorspace;
+ if ( cs->id() == KisID("LABA") ) return LABColorspace;
+
+ kdDebug(41008) << "Cannot export images in " + cs->id().name() + " yet.\n";
+ return RGBColorspace;
+
+ }
+
+ KisProfile * getProfileForProfileInfo(const Image * image)
+ {
+#ifndef HAVE_MAGICK6
+ return 0;
+#else
+
+ if (image->profiles == NULL)
+ return 0;
+
+ const char *name;
+ const StringInfo *profile;
+
+ KisProfile * p = 0;
+
+ ResetImageProfileIterator(image);
+ for (name = GetNextImageProfile(image); name != (char *) NULL; )
+ {
+ profile = GetImageProfile(image, name);
+ if (profile == (StringInfo *) NULL)
+ continue;
+
+ // XXX: Hardcoded for icc type -- is that correct for us?
+ if (TQString::compare(name, "icc") == 0) {
+ TQByteArray rawdata;
+ rawdata.resize(profile->length);
+ memcpy(rawdata.data(), profile->datum, profile->length);
+
+ p = new KisProfile(rawdata);
+ if (p == 0)
+ return 0;
+ }
+ name = GetNextImageProfile(image);
+ }
+ return p;
+#endif
+ }
+
+ void setAnnotationsForImage(const Image * src, KisImageSP image)
+ {
+#ifndef HAVE_MAGICK6
+ return;
+#else
+ if (src->profiles == NULL)
+ return;
+
+ const char *name = 0;
+ const StringInfo *profile;
+ KisAnnotation* annotation = 0;
+
+ // Profiles and so
+ ResetImageProfileIterator(src);
+ while((name = GetNextImageProfile(src))) {
+ profile = GetImageProfile(src, name);
+ if (profile == (StringInfo *) NULL)
+ continue;
+
+ // XXX: icc will be written seperately?
+ if (TQString::compare(name, "icc") == 0)
+ continue;
+
+ TQByteArray rawdata;
+ rawdata.resize(profile->length);
+ memcpy(rawdata.data(), profile->datum, profile->length);
+
+ annotation = new KisAnnotation(TQString(name), "", rawdata);
+ Q_CHECK_PTR(annotation);
+
+ image -> addAnnotation(annotation);
+ }
+
+ // Attributes, since we have no hint on if this is an attribute or a profile
+ // annotation, we prefix it with 'chalk_attribute:'. XXX This needs to be rethought!
+ // The joys of imagemagick. From at version 6.2.1 (dfaure has 6.2.0 and confirms the
+ // old way of doing things) they changed the src -> attributes
+ // to void* and require us to use the iterator functions. So we #if around that, *sigh*
+#if MagickLibVersion >= 0x621
+ const ImageAttribute * attr;
+ ResetImageAttributeIterator(src);
+ while ( (attr = GetNextImageAttribute(src)) ) {
+#else
+ ImageAttribute * attr = src -> attributes;
+ while (attr) {
+#endif
+ TQByteArray rawdata;
+ int len = strlen(attr -> value) + 1;
+ rawdata.resize(len);
+ memcpy(rawdata.data(), attr -> value, len);
+
+ annotation = new KisAnnotation(
+ TQString("chalk_attribute:%1").tqarg(TQString(attr -> key)), "", rawdata);
+ Q_CHECK_PTR(annotation);
+
+ image -> addAnnotation(annotation);
+#if MagickLibVersion < 0x620
+ attr = attr -> next;
+#endif
+ }
+
+#endif
+ }
+ }
+
+ void exportAnnotationsForImage(Image * dst, vKisAnnotationSP_it& it, vKisAnnotationSP_it& annotationsEnd)
+ {
+#ifndef HAVE_MAGICK6
+ return;
+#else
+ while(it != annotationsEnd) {
+ if (!(*it) || (*it) -> type() == TQString()) {
+ kdDebug(41008) << "Warning: empty annotation" << endl;
+ ++it;
+ continue;
+ }
+
+ kdDebug(41008) << "Trying to store annotation of type " << (*it) -> type() << " of size " << (*it) -> annotation() . size() << endl;
+
+ if ((*it) -> type().startsWith("chalk_attribute:")) { // Attribute
+ if (!SetImageAttribute(dst,
+ (*it) -> type().mid(strlen("chalk_attribute:")).ascii(),
+ (*it) -> annotation() . data()) ) {
+ kdDebug(41008) << "Storing of attribute " << (*it) -> type() << "failed!\n";
+ }
+ } else { // Profile
+ if (!ProfileImage(dst, (*it) -> type().ascii(),
+ (unsigned char*)(*it) -> annotation() . data(),
+ (*it) -> annotation() . size(), MagickFalse)) {
+ kdDebug(41008) << "Storing failed!" << endl;
+ }
+ }
+ ++it;
+ }
+#endif
+ }
+
+
+ void InitGlobalMagick()
+ {
+ static bool init = false;
+
+ if (!init) {
+ KApplication *app = KApplication::kApplication();
+
+ InitializeMagick(*app -> argv());
+ atexit(DestroyMagick);
+ init = true;
+ }
+ }
+
+ /*
+ * ImageMagick progress monitor callback. Unfortunately it doesn't support passing in some user
+ * data which complicates things quite a bit. The plan was to allow the user start multiple
+ * import/scans if he/she so wished. However, without passing user data it's not possible to tell
+ * on which task we have made progress on.
+ *
+ * Additionally, ImageMagick is thread-safe, not re-entrant... i.e. IM does not relinquish held
+ * locks when calling user defined callbacks, this means that the same thread going back into IM
+ * would deadlock since it would try to acquire locks it already holds.
+ */
+#ifdef HAVE_MAGICK6
+ MagickBooleanType monitor(const char *text, const ExtendedSignedIntegralType, const ExtendedUnsignedIntegralType, ExceptionInfo *)
+ {
+ KApplication *app = KApplication::kApplication();
+
+ Q_ASSERT(app);
+
+ if (app -> hasPendingEvents())
+ app -> processEvents();
+
+ printf("%s\n", text);
+ return MagickTrue;
+ }
+#else
+ unsigned int monitor(const char *text, const ExtendedSignedIntegralType, const ExtendedUnsignedIntegralType, ExceptionInfo *)
+ {
+ KApplication *app = KApplication::kApplication();
+
+ Q_ASSERT(app);
+
+ if (app -> hasPendingEvents())
+ app -> processEvents();
+
+ printf("%s\n", text);
+ return true;
+ }
+#endif
+
+
+
+KisImageMagickConverter::KisImageMagickConverter(KisDoc *doc, KisUndoAdapter *adapter)
+{
+ InitGlobalMagick();
+ init(doc, adapter);
+ SetMonitorHandler(monitor);
+ m_stop = false;
+}
+
+KisImageMagickConverter::~KisImageMagickConverter()
+{
+}
+
+KisImageBuilder_Result KisImageMagickConverter::decode(const KURL& uri, bool isBlob)
+{
+ Image *image;
+ Image *images;
+ ExceptionInfo ei;
+ ImageInfo *ii;
+
+ if (m_stop) {
+ m_img = 0;
+ return KisImageBuilder_RESULT_INTR;
+ }
+
+ GetExceptionInfo(&ei);
+ ii = CloneImageInfo(0);
+
+ if (isBlob) {
+
+ // TODO : Test. Does BlobToImage even work?
+ Q_ASSERT(uri.isEmpty());
+ images = BlobToImage(ii, &m_data[0], m_data.size(), &ei);
+ } else {
+
+ qstrncpy(ii -> filename, TQFile::encodeName(uri.path()), MaxTextExtent - 1);
+
+ if (ii -> filename[MaxTextExtent - 1]) {
+ emit notifyProgressError();
+ return KisImageBuilder_RESULT_PATH;
+ }
+
+ images = ReadImage(ii, &ei);
+
+ }
+
+ if (ei.severity != UndefinedException)
+ CatchException(&ei);
+
+ if (images == 0) {
+ DestroyImageInfo(ii);
+ DestroyExceptionInfo(&ei);
+ emit notifyProgressError();
+ return KisImageBuilder_RESULT_FAILURE;
+ }
+
+ emit notifyProgressStage(i18n("Importing..."), 0);
+
+ m_img = 0;
+
+ while ((image = RemoveFirstImageFromList(&images))) {
+ ViewInfo *vi = OpenCacheView(image);
+
+ // Determine image depth -- for now, all channels of an imported image are of the same depth
+ unsigned long imageDepth = image->depth;
+ kdDebug(41008) << "Image depth: " << imageDepth << "\n";
+
+ TQString csName;
+ KisColorSpace * cs = 0;
+ ColorspaceType colorspaceType;
+
+ // Determine image type -- rgb, grayscale or cmyk
+ if (GetImageType(image, &ei) == GrayscaleType || GetImageType(image, &ei) == GrayscaleMatteType) {
+ if (imageDepth == 8)
+ csName = "GRAYA";
+ else if ( imageDepth == 16 )
+ csName = "GRAYA16" ;
+ colorspaceType = GRAYColorspace;
+ }
+ else {
+ colorspaceType = image->colorspace;
+ csName = getColorSpaceName(image -> colorspace, imageDepth);
+ }
+
+ kdDebug(41008) << "image has " << csName << " colorspace\n";
+
+ KisProfile * profile = getProfileForProfileInfo(image);
+ if (profile)
+ {
+ kdDebug(41008) << "image has embedded profile: " << profile -> productName() << "\n";
+ cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(csName, profile);
+ }
+ else
+ cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName,""),"");
+
+ if (!cs) {
+ kdDebug(41008) << "Chalk does not support colorspace " << image -> colorspace << "\n";
+ CloseCacheView(vi);
+ DestroyImage(image);
+ DestroyExceptionInfo(&ei);
+ DestroyImageList(images);
+ DestroyImageInfo(ii);
+ emit notifyProgressError();
+ return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
+ }
+
+ if( ! m_img) {
+ m_img = new KisImage(m_doc->undoAdapter(), image -> columns, image -> rows, cs, "built image");
+ Q_CHECK_PTR(m_img);
+ m_img->blockSignals(true); // Don't send out signals while we're building the image
+
+ // XXX I'm assuming seperate layers won't have other profile things like EXIF
+ setAnnotationsForImage(image, m_img);
+ }
+
+ if (image -> columns && image -> rows) {
+
+ // Opacity (set by the photoshop import filter)
+ TQ_UINT8 opacity = OPACITY_OPAQUE;
+ const ImageAttribute * attr = GetImageAttribute(image, "[layer-opacity]");
+ if (attr != 0) {
+ opacity = TQ_UINT8_MAX - Downscale(TQString(attr->value).toInt());
+ }
+
+ KisPaintLayerSP layer = 0;
+
+ attr = GetImageAttribute(image, "[layer-name]");
+ if (attr != 0) {
+ layer = new KisPaintLayer(m_img, attr->value, opacity);
+ }
+ else {
+ layer = new KisPaintLayer(m_img, m_img -> nextLayerName(), opacity);
+ }
+
+ Q_ASSERT(layer);
+
+ // Layerlocation (set by the photoshop import filter)
+ TQ_INT32 x_offset = 0;
+ TQ_INT32 y_offset = 0;
+
+ attr = GetImageAttribute(image, "[layer-xpos]");
+ if (attr != 0) {
+ x_offset = TQString(attr->value).toInt();
+ }
+
+ attr = GetImageAttribute(image, "[layer-ypos]");
+ if (attr != 0) {
+ y_offset = TQString(attr->value).toInt();
+ }
+
+
+ for (TQ_UINT32 y = 0; y < image->rows; y ++)
+ {
+ const PixelPacket *pp = AcquireCacheView(vi, 0, y, image->columns, 1, &ei);
+
+ if(!pp)
+ {
+ CloseCacheView(vi);
+ DestroyImageList(images);
+ DestroyImageInfo(ii);
+ DestroyExceptionInfo(&ei);
+ emit notifyProgressError();
+ return KisImageBuilder_RESULT_FAILURE;
+ }
+
+ IndexPacket * indexes = GetCacheViewIndexes(vi);
+
+ KisHLineIteratorPixel hiter = layer->paintDevice()->createHLineIterator(0, y, image->columns, true);
+
+ if (colorspaceType== CMYKColorspace) {
+ if (imageDepth == 8) {
+ int x = 0;
+ while (!hiter.isDone())
+ {
+ TQ_UINT8 *ptr= hiter.rawData();
+ *(ptr++) = Downscale(pp->red); // cyan
+ *(ptr++) = Downscale(pp->green); // magenta
+ *(ptr++) = Downscale(pp->blue); // yellow
+ *(ptr++) = Downscale(indexes[x]); // Black
+// XXX: Warning! This ifdef messes up the paren matching big-time!
+#ifdef HAVE_MAGICK6
+ if (image->matte != MagickFalse) {
+#else
+ if (image->matte == true) {
+#endif
+ *(ptr++) = OPACITY_OPAQUE - Downscale(pp->opacity);
+ }
+ else {
+ *(ptr++) = OPACITY_OPAQUE;
+ }
+ ++x;
+ pp++;
+ ++hiter;
+ }
+ }
+ }
+ else if (colorspaceType == LABColorspace) {
+ while(! hiter.isDone())
+ {
+ TQ_UINT16 *ptr = reinterpret_cast<TQ_UINT16 *>(hiter.rawData());
+
+ *(ptr++) = ScaleQuantumToShort(pp->red);
+ *(ptr++) = ScaleQuantumToShort(pp->green);
+ *(ptr++) = ScaleQuantumToShort(pp->blue);
+ *(ptr++) = 65535/*OPACITY_OPAQUE*/ - ScaleQuantumToShort(pp->opacity);
+
+ pp++;
+ ++hiter;
+ }
+ }
+ else if (colorspaceType == RGBColorspace ||
+ colorspaceType == sRGBColorspace ||
+ colorspaceType == TransparentColorspace)
+ {
+ if (imageDepth == 8) {
+ while(! hiter.isDone())
+ {
+ TQ_UINT8 *ptr= hiter.rawData();
+ // XXX: not colorstrategy and bitdepth independent
+ *(ptr++) = Downscale(pp->blue);
+ *(ptr++) = Downscale(pp->green);
+ *(ptr++) = Downscale(pp->red);
+ *(ptr++) = OPACITY_OPAQUE - Downscale(pp->opacity);
+
+ pp++;
+ ++hiter;
+ }
+ }
+ else if (imageDepth == 16) {
+ while(! hiter.isDone())
+ {
+ TQ_UINT16 *ptr = reinterpret_cast<TQ_UINT16 *>(hiter.rawData());
+ // XXX: not colorstrategy independent
+ *(ptr++) = ScaleQuantumToShort(pp->blue);
+ *(ptr++) = ScaleQuantumToShort(pp->green);
+ *(ptr++) = ScaleQuantumToShort(pp->red);
+ *(ptr++) = 65535/*OPACITY_OPAQUE*/ - ScaleQuantumToShort(pp->opacity);
+
+ pp++;
+ ++hiter;
+ }
+ }
+ }
+ else if ( colorspaceType == GRAYColorspace) {
+ if (imageDepth == 8) {
+ while(! hiter.isDone())
+ {
+ TQ_UINT8 *ptr= hiter.rawData();
+ // XXX: not colorstrategy and bitdepth independent
+ *(ptr++) = Downscale(pp->blue);
+ *(ptr++) = OPACITY_OPAQUE - Downscale(pp->opacity);
+
+ pp++;
+ ++hiter;
+ }
+ }
+ else if (imageDepth == 16) {
+ while(! hiter.isDone())
+ {
+ TQ_UINT16 *ptr = reinterpret_cast<TQ_UINT16 *>(hiter.rawData());
+ // XXX: not colorstrategy independent
+ *(ptr++) = ScaleQuantumToShort(pp->blue);
+ *(ptr++) = 65535/*OPACITY_OPAQUE*/ - ScaleQuantumToShort(pp->opacity);
+
+ pp++;
+ ++hiter;
+ }
+ }
+ }
+
+ emit notifyProgress(y * 100 / image->rows);
+
+ if (m_stop) {
+ CloseCacheView(vi);
+ DestroyImage(image);
+ DestroyImageList(images);
+ DestroyImageInfo(ii);
+ DestroyExceptionInfo(&ei);
+ m_img = 0;
+ return KisImageBuilder_RESULT_INTR;
+ }
+ }
+ m_img->addLayer(layer.data(), m_img->rootLayer());
+ layer->paintDevice()->move(x_offset, y_offset);
+ }
+
+ emit notifyProgressDone();
+ CloseCacheView(vi);
+ DestroyImage(image);
+ }
+
+ emit notifyProgressDone();
+ DestroyImageList(images);
+ DestroyImageInfo(ii);
+ DestroyExceptionInfo(&ei);
+ return KisImageBuilder_RESULT_OK;
+ }
+
+ KisImageBuilder_Result KisImageMagickConverter::buildImage(const KURL& uri)
+ {
+ if (uri.isEmpty())
+ return KisImageBuilder_RESULT_NO_URI;
+
+ if (!KIO::NetAccess::exists(uri, false, tqApp -> mainWidget())) {
+ return KisImageBuilder_RESULT_NOT_EXIST;
+ }
+
+ KisImageBuilder_Result result = KisImageBuilder_RESULT_FAILURE;
+ TQString tmpFile;
+
+ if (KIO::NetAccess::download(uri, tmpFile, tqApp -> mainWidget())) {
+ KURL uriTF;
+ uriTF.setPath( tmpFile );
+ result = decode(uriTF, false);
+ KIO::NetAccess::removeTempFile(tmpFile);
+ }
+
+ return result;
+ }
+
+
+ KisImageSP KisImageMagickConverter::image()
+ {
+ return m_img;
+ }
+
+ void KisImageMagickConverter::init(KisDoc *doc, KisUndoAdapter *adapter)
+ {
+ m_doc = doc;
+ m_adapter = adapter;
+ m_job = 0;
+ }
+
+ KisImageBuilder_Result KisImageMagickConverter::buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd)
+ {
+ Image *image;
+ ExceptionInfo ei;
+ ImageInfo *ii;
+
+ if (!layer)
+ return KisImageBuilder_RESULT_INVALID_ARG;
+
+ KisImageSP img = layer->image();
+ if (!img)
+ return KisImageBuilder_RESULT_EMPTY;
+
+ if (uri.isEmpty())
+ return KisImageBuilder_RESULT_NO_URI;
+
+ if (!uri.isLocalFile())
+ return KisImageBuilder_RESULT_NOT_LOCAL;
+
+
+ TQ_UINT32 layerBytesPerChannel = layer->paintDevice()->pixelSize() / layer->paintDevice()->nChannels();
+
+ GetExceptionInfo(&ei);
+
+ ii = CloneImageInfo(0);
+
+ qstrncpy(ii -> filename, TQFile::encodeName(uri.path()), MaxTextExtent - 1);
+
+ if (ii -> filename[MaxTextExtent - 1]) {
+ emit notifyProgressError();
+ return KisImageBuilder_RESULT_PATH;
+ }
+
+ if (!img -> width() || !img -> height())
+ return KisImageBuilder_RESULT_EMPTY;
+
+ if (layerBytesPerChannel < 2) {
+ ii->depth = 8;
+ }
+ else {
+ ii->depth = 16;
+ }
+
+ ii->colorspace = getColorTypeforColorSpace(layer->paintDevice()->colorSpace());
+
+ image = AllocateImage(ii);
+ SetImageColorspace(image, ii->colorspace);
+ image -> columns = img -> width();
+ image -> rows = img -> height();
+
+ kdDebug(41008) << "Saving with colorspace " << image->colorspace << ", (" << layer->paintDevice()->colorSpace()->id().name() << ")\n";
+ kdDebug(41008) << "IM Image thinks it has depth: " << image->depth << "\n";
+
+#ifdef HAVE_MAGICK6
+ // if ( layer-> hasAlpha() )
+ image -> matte = MagickTrue;
+ // else
+ // image -> matte = MagickFalse;
+#else
+ // image -> matte = layer -> hasAlpha();
+ image -> matte = true;
+#endif
+
+ TQ_INT32 y, height, width;
+
+ height = img -> height();
+ width = img -> width();
+
+ bool alpha = true;
+ TQString ext = TQFileInfo(TQFile::encodeName(uri.path())).extension(false).upper();
+ if (ext == "BMP") {
+ alpha = false;
+ qstrncpy(ii->magick, "BMP2", MaxTextExtent - 1);
+ }
+ else if (ext == "RGB") {
+ qstrncpy(ii->magick, "SGI", MaxTextExtent - 1);
+ }
+
+ for (y = 0; y < height; y++) {
+
+ // Allocate pixels for this scanline
+ PixelPacket * pp = SetImagePixels(image, 0, y, width, 1);
+
+ if (!pp) {
+ DestroyExceptionInfo(&ei);
+ DestroyImage(image);
+ emit notifyProgressError();
+ return KisImageBuilder_RESULT_FAILURE;
+
+ }
+
+ KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, y, width, false);
+ if (alpha)
+ SetImageType(image, TrueColorMatteType);
+ else
+ SetImageType(image, TrueColorType);
+
+ if (image->colorspace== CMYKColorspace) {
+
+ IndexPacket * indexes = GetIndexes(image);
+ int x = 0;
+ if (layerBytesPerChannel == 2) {
+ while (!it.isDone()) {
+
+ const TQ_UINT16 *d = reinterpret_cast<const TQ_UINT16 *>(it.rawData());
+ pp -> red = ScaleShortToQuantum(d[PIXEL_CYAN]);
+ pp -> green = ScaleShortToQuantum(d[PIXEL_MAGENTA]);
+ pp -> blue = ScaleShortToQuantum(d[PIXEL_YELLOW]);
+ if (alpha)
+ pp -> opacity = ScaleShortToQuantum(65535/*OPACITY_OPAQUE*/ - d[PIXEL_CMYK_ALPHA]);
+ indexes[x] = ScaleShortToQuantum(d[PIXEL_BLACK]);
+ x++;
+ pp++;
+ ++it;
+ }
+ }
+ else {
+ while (!it.isDone()) {
+
+ TQ_UINT8 * d = it.rawData();
+ pp -> red = Upscale(d[PIXEL_CYAN]);
+ pp -> green = Upscale(d[PIXEL_MAGENTA]);
+ pp -> blue = Upscale(d[PIXEL_YELLOW]);
+ if (alpha)
+ pp -> opacity = Upscale(OPACITY_OPAQUE - d[PIXEL_CMYK_ALPHA]);
+
+ indexes[x]= Upscale(d[PIXEL_BLACK]);
+
+ x++;
+ pp++;
+ ++it;
+ }
+ }
+ }
+ else if (image->colorspace== RGBColorspace ||
+ image->colorspace == sRGBColorspace ||
+ image->colorspace == TransparentColorspace)
+ {
+ if (layerBytesPerChannel == 2) {
+ while (!it.isDone()) {
+
+ const TQ_UINT16 *d = reinterpret_cast<const TQ_UINT16 *>(it.rawData());
+ pp -> red = ScaleShortToQuantum(d[PIXEL_RED]);
+ pp -> green = ScaleShortToQuantum(d[PIXEL_GREEN]);
+ pp -> blue = ScaleShortToQuantum(d[PIXEL_BLUE]);
+ if (alpha)
+ pp -> opacity = ScaleShortToQuantum(65535/*OPACITY_OPAQUE*/ - d[PIXEL_ALPHA]);
+
+ pp++;
+ ++it;
+ }
+ }
+ else {
+ while (!it.isDone()) {
+
+ TQ_UINT8 * d = it.rawData();
+ pp -> red = Upscale(d[PIXEL_RED]);
+ pp -> green = Upscale(d[PIXEL_GREEN]);
+ pp -> blue = Upscale(d[PIXEL_BLUE]);
+ if (alpha)
+ pp -> opacity = Upscale(OPACITY_OPAQUE - d[PIXEL_ALPHA]);
+
+ pp++;
+ ++it;
+ }
+ }
+ }
+ else if (image->colorspace == GRAYColorspace)
+ {
+ SetImageType(image, GrayscaleMatteType);
+ if (layerBytesPerChannel == 2) {
+ while (!it.isDone()) {
+
+ const TQ_UINT16 *d = reinterpret_cast<const TQ_UINT16 *>(it.rawData());
+ pp -> red = ScaleShortToQuantum(d[PIXEL_GRAY]);
+ pp -> green = ScaleShortToQuantum(d[PIXEL_GRAY]);
+ pp -> blue = ScaleShortToQuantum(d[PIXEL_GRAY]);
+ if (alpha)
+ pp -> opacity = ScaleShortToQuantum(65535/*OPACITY_OPAQUE*/ - d[PIXEL_GRAY_ALPHA]);
+
+ pp++;
+ ++it;
+ }
+ }
+ else {
+ while (!it.isDone()) {
+ TQ_UINT8 * d = it.rawData();
+ pp -> red = Upscale(d[PIXEL_GRAY]);
+ pp -> green = Upscale(d[PIXEL_GRAY]);
+ pp -> blue = Upscale(d[PIXEL_GRAY]);
+ if (alpha)
+ pp -> opacity = Upscale(OPACITY_OPAQUE - d[PIXEL_GRAY_ALPHA]);
+
+ pp++;
+ ++it;
+ }
+ }
+ }
+ else {
+ kdDebug(41008) << "Unsupported image format\n";
+ return KisImageBuilder_RESULT_INVALID_ARG;
+ }
+
+ emit notifyProgressStage(i18n("Saving..."), y * 100 / height);
+
+#ifdef HAVE_MAGICK6
+ if (SyncImagePixels(image) == MagickFalse)
+ kdDebug(41008) << "Syncing pixels failed\n";
+#else
+ if (!SyncImagePixels(image))
+ kdDebug(41008) << "Syncing pixels failed\n";
+#endif
+ }
+
+ // set the annotations
+ exportAnnotationsForImage(image, annotationsStart, annotationsEnd);
+
+ // XXX: Write to a temp file, then have Chalk use KIO to copy temp
+ // image to remote location.
+
+ WriteImage(ii, image);
+ DestroyExceptionInfo(&ei);
+ DestroyImage(image);
+ emit notifyProgressDone();
+ return KisImageBuilder_RESULT_OK;
+ }
+
+ void KisImageMagickConverter::ioData(KIO::Job *job, const TQByteArray& data)
+ {
+ if (data.isNull() || data.isEmpty()) {
+ emit notifyProgressStage(i18n("Loading..."), 0);
+ return;
+ }
+
+ if (m_data.empty()) {
+ Image *image;
+ ImageInfo *ii;
+ ExceptionInfo ei;
+
+ ii = CloneImageInfo(0);
+ GetExceptionInfo(&ei);
+ image = PingBlob(ii, data.data(), data.size(), &ei);
+
+ if (image == 0 || ei.severity == BlobError) {
+ DestroyExceptionInfo(&ei);
+ DestroyImageInfo(ii);
+ job -> kill();
+ emit notifyProgressError();
+ return;
+ }
+
+ DestroyImage(image);
+ DestroyExceptionInfo(&ei);
+ DestroyImageInfo(ii);
+ emit notifyProgressStage(i18n("Loading..."), 0);
+ }
+
+ Q_ASSERT(data.size() + m_data.size() <= m_size);
+ memcpy(&m_data[m_data.size()], data.data(), data.count());
+ m_data.resize(m_data.size() + data.count());
+ emit notifyProgressStage(i18n("Loading..."), m_data.size() * 100 / m_size);
+
+ if (m_stop)
+ job -> kill();
+ }
+
+ void KisImageMagickConverter::ioResult(KIO::Job *job)
+ {
+ m_job = 0;
+
+ if (job -> error())
+ emit notifyProgressError();
+
+ decode(KURL(), true);
+ }
+
+ void KisImageMagickConverter::ioTotalSize(KIO::Job * /*job*/, KIO::filesize_t size)
+ {
+ m_size = size;
+ m_data.reserve(size);
+ emit notifyProgressStage(i18n("Loading..."), 0);
+ }
+
+ void KisImageMagickConverter::cancel()
+ {
+ m_stop = true;
+ }
+
+ /**
+ * @name readFilters
+ * @return Provide a list of file formats the application can read.
+ */
+ TQString KisImageMagickConverter::readFilters()
+ {
+ TQString s;
+ TQString all;
+ TQString name;
+ TQString description;
+ unsigned long matches;
+
+#ifdef HAVE_MAGICK6
+#ifdef HAVE_OLD_GETMAGICKINFOLIST
+ const MagickInfo **mi;
+ mi = GetMagickInfoList("*", &matches);
+#else // HAVE_OLD_GETMAGICKINFOLIST
+ ExceptionInfo ei;
+ GetExceptionInfo(&ei);
+ const MagickInfo **mi;
+ mi = GetMagickInfoList("*", &matches, &ei);
+ DestroyExceptionInfo(&ei);
+#endif // HAVE_OLD_GETMAGICKINFOLIST
+#else // HAVE_MAGICK6
+ const MagickInfo *mi;
+ ExceptionInfo ei;
+ GetExceptionInfo(&ei);
+ mi = GetMagickInfo("*", &ei);
+ DestroyExceptionInfo(&ei);
+#endif // HAVE_MAGICK6
+
+ if (!mi)
+ return s;
+
+#ifdef HAVE_MAGICK6
+ for (unsigned long i = 0; i < matches; i++) {
+ const MagickInfo *info = mi[i];
+ if (info -> stealth)
+ continue;
+
+ if (info -> decoder) {
+ name = info -> name;
+ description = info -> description;
+ kdDebug(41008) << "Found import filter for: " << name << "\n";
+
+ if (!description.isEmpty() && !description.tqcontains('/')) {
+ all += "*." + name.lower() + " *." + name + " ";
+ s += "*." + name.lower() + " *." + name + "|";
+ s += i18n(description.utf8());
+ s += "\n";
+ }
+ }
+ }
+#else
+ for (; mi; mi = reinterpret_cast<const MagickInfo*>(mi -> next)) {
+ if (mi -> stealth)
+ continue;
+ if (mi -> decoder) {
+ name = mi -> name;
+ description = mi -> description;
+ kdDebug(41008) << "Found import filter for: " << name << "\n";
+
+ if (!description.isEmpty() && !description.tqcontains('/')) {
+ all += "*." + name.lower() + " *." + name + " ";
+ s += "*." + name.lower() + " *." + name + "|";
+ s += i18n(description.utf8());
+ s += "\n";
+ }
+ }
+ }
+#endif
+
+ all += "|" + i18n("All Images");
+ all += "\n";
+
+ return all + s;
+ }
+
+ TQString KisImageMagickConverter::writeFilters()
+ {
+ TQString s;
+ TQString all;
+ TQString name;
+ TQString description;
+ unsigned long matches;
+
+#ifdef HAVE_MAGICK6
+#ifdef HAVE_OLD_GETMAGICKINFOLIST
+ const MagickInfo **mi;
+ mi = GetMagickInfoList("*", &matches);
+#else // HAVE_OLD_GETMAGICKINFOLIST
+ ExceptionInfo ei;
+ GetExceptionInfo(&ei);
+ const MagickInfo **mi;
+ mi = GetMagickInfoList("*", &matches, &ei);
+ DestroyExceptionInfo(&ei);
+#endif // HAVE_OLD_GETMAGICKINFOLIST
+#else // HAVE_MAGICK6
+ const MagickInfo *mi;
+ ExceptionInfo ei;
+ GetExceptionInfo(&ei);
+ mi = GetMagickInfo("*", &ei);
+ DestroyExceptionInfo(&ei);
+#endif // HAVE_MAGICK6
+
+ if (!mi) {
+ kdDebug(41008) << "Eek, no magick info!\n";
+ return s;
+ }
+
+#ifdef HAVE_MAGICK6
+ for (unsigned long i = 0; i < matches; i++) {
+ const MagickInfo *info = mi[i];
+ kdDebug(41008) << "Found export filter for: " << info -> name << "\n";
+ if (info -> stealth)
+ continue;
+
+ if (info -> encoder) {
+ name = info -> name;
+
+ description = info -> description;
+
+ if (!description.isEmpty() && !description.tqcontains('/')) {
+ all += "*." + name.lower() + " *." + name + " ";
+ s += "*." + name.lower() + " *." + name + "|";
+ s += i18n(description.utf8());
+ s += "\n";
+ }
+ }
+ }
+#else
+ for (; mi; mi = reinterpret_cast<const MagickInfo*>(mi -> next)) {
+ kdDebug(41008) << "Found export filter for: " << mi -> name << "\n";
+ if (mi -> stealth)
+ continue;
+
+ if (mi -> encoder) {
+ name = mi -> name;
+
+ description = mi -> description;
+
+ if (!description.isEmpty() && !description.tqcontains('/')) {
+ all += "*." + name.lower() + " *." + name + " ";
+ s += "*." + name.lower() + " *." + name + "|";
+ s += i18n(description.utf8());
+ s += "\n";
+ }
+ }
+ }
+#endif
+
+
+ all += "|" + i18n("All Images");
+ all += "\n";
+
+ return all + s;
+ }
+
+#include "kis_image_magick_converter.moc"
+
diff --git a/filters/chalk/magick/kis_image_magick_converter.h b/filters/chalk/magick/kis_image_magick_converter.h
new file mode 100644
index 00000000..28bd94ce
--- /dev/null
+++ b/filters/chalk/magick/kis_image_magick_converter.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef KIS_IMAGE_MAGICK_CONVERTER_H_
+#define KIS_IMAGE_MAGICK_CONVERTER_H_
+
+#include <tqobject.h>
+#include <tqvaluevector.h>
+
+#include <kio/job.h>
+
+#include "kis_types.h"
+#include "kis_global.h"
+#include "kis_progress_subject.h"
+
+class TQString;
+class KURL;
+class KisDoc;
+class KisNameServer;
+class KisUndoAdapter;
+/**
+ * Image import/export plugins can use these results to report about success or failure.
+ */
+enum KisImageBuilder_Result {
+ KisImageBuilder_RESULT_FAILURE = -400,
+ KisImageBuilder_RESULT_NOT_EXIST = -300,
+ KisImageBuilder_RESULT_NOT_LOCAL = -200,
+ KisImageBuilder_RESULT_BAD_FETCH = -100,
+ KisImageBuilder_RESULT_INVALID_ARG = -50,
+ KisImageBuilder_RESULT_OK = 0,
+ KisImageBuilder_RESULT_PROGRESS = 1,
+ KisImageBuilder_RESULT_EMPTY = 100,
+ KisImageBuilder_RESULT_BUSY = 150,
+ KisImageBuilder_RESULT_NO_URI = 200,
+ KisImageBuilder_RESULT_UNSUPPORTED = 300,
+ KisImageBuilder_RESULT_INTR = 400,
+ KisImageBuilder_RESULT_PATH = 500,
+ KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE = 600
+};
+
+
+
+/**
+ * Build a KisImage representation of an image file.
+ */
+class KisImageMagickConverter : public KisProgressSubject {
+ typedef TQObject super;
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ KisImageMagickConverter(KisDoc *doc, KisUndoAdapter *adapter);
+ virtual ~KisImageMagickConverter();
+
+public slots:
+ virtual void cancel();
+
+public:
+ KisImageBuilder_Result buildImage(const KURL& uri);
+ KisImageBuilder_Result buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd);
+ KisImageSP image();
+
+public:
+ static TQString readFilters();
+ static TQString writeFilters();
+
+private slots:
+ void ioData(KIO::Job *job, const TQByteArray& data);
+ void ioResult(KIO::Job *job);
+ void ioTotalSize(KIO::Job *job, KIO::filesize_t size);
+
+private:
+ KisImageMagickConverter(const KisImageMagickConverter&);
+ KisImageMagickConverter& operator=(const KisImageMagickConverter&);
+ void init(KisDoc *doc, KisUndoAdapter *adapter);
+ KisImageBuilder_Result decode(const KURL& uri, bool isBlob);
+
+private:
+ KisImageSP m_img;
+ KisDoc *m_doc;
+ KisUndoAdapter *m_adapter;
+ TQValueVector<TQ_UINT8> m_data;
+ KIO::TransferJob *m_job;
+ KIO::filesize_t m_size;
+ bool m_stop;
+};
+
+#endif // KIS_IMAGE_MAGICK_CONVERTER_H_
+
diff --git a/filters/chalk/magick/magickexport.cpp b/filters/chalk/magick/magickexport.cpp
new file mode 100644
index 00000000..09f351c1
--- /dev/null
+++ b/filters/chalk/magick/magickexport.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <magickexport.h>
+#include <kgenericfactory.h>
+#include <KoDocument.h>
+#include <KoFilterChain.h>
+
+#include <kis_doc.h>
+#include <kis_paint_layer.h>
+#include <kis_image.h>
+#include <kis_annotation.h>
+#include <kis_types.h>
+#include <kis_image_magick_converter.h>
+
+typedef KGenericFactory<MagickExport, KoFilter> MagickExportFactory;
+K_EXPORT_COMPONENT_FACTORY(libchalkmagickexport, MagickExportFactory("kofficefilters"))
+
+MagickExport::MagickExport(KoFilter *, const char *, const TQStringList&) : KoFilter()
+{
+}
+
+MagickExport::~MagickExport()
+{
+}
+
+KoFilter::ConversiontqStatus MagickExport::convert(const TQCString& from, const TQCString& to)
+{
+ kdDebug(41008) << "magick export! From: " << from << ", To: " << to << "\n";
+
+ if (from != "application/x-chalk")
+ return KoFilter::NotImplemented;
+
+ // XXX: Add dialog about flattening layers here
+
+ KisDoc *output = dynamic_cast<KisDoc*>(m_chain->inputDocument());
+ TQString filename = m_chain->outputFile();
+
+ if (!output)
+ return KoFilter::CreationError;
+
+ if (filename.isEmpty()) return KoFilter::FileNotFound;
+
+ KURL url;
+ url.setPath(filename);
+
+ KisImageSP img = output->currentImage();
+
+ KisImageMagickConverter ib(output, output->undoAdapter());
+
+ KisPaintDeviceSP pd = new KisPaintDevice(*img->projection());
+ KisPaintLayerSP l = new KisPaintLayer(img, "projection", OPACITY_OPAQUE, pd);
+
+ vKisAnnotationSP_it beginIt = img->beginAnnotations();
+ vKisAnnotationSP_it endIt = img->endAnnotations();
+ if (ib.buildFile(url, l, beginIt, endIt) == KisImageBuilder_RESULT_OK) {
+ return KoFilter::OK;
+ }
+ return KoFilter::InternalError;
+}
+
+#include <magickexport.moc>
+
diff --git a/filters/chalk/magick/magickexport.h b/filters/chalk/magick/magickexport.h
new file mode 100644
index 00000000..6ea7e238
--- /dev/null
+++ b/filters/chalk/magick/magickexport.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef MAGICKEXPORT_H_
+#define MAGICKEXPORT_H_
+
+#include <KoFilter.h>
+
+class MagickExport : public KoFilter {
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ MagickExport(KoFilter *tqparent, const char *name, const TQStringList&);
+ virtual ~MagickExport();
+
+public:
+ virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to);
+};
+
+#endif // MAGICKEXPORT_H_
+
diff --git a/filters/chalk/magick/magickimport.cpp b/filters/chalk/magick/magickimport.cpp
new file mode 100644
index 00000000..b5f73d19
--- /dev/null
+++ b/filters/chalk/magick/magickimport.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <tqstring.h>
+
+#include <magickimport.h>
+#include <kgenericfactory.h>
+#include <KoDocument.h>
+#include <KoFilterChain.h>
+
+#include <kis_doc.h>
+#include <kis_view.h>
+#include <kis_image_magick_converter.h>
+#include <kis_progress_display_interface.h>
+#include <kis_image.h>
+#include <kis_layer.h>
+
+typedef KGenericFactory<MagickImport, KoFilter> MagickImportFactory;
+K_EXPORT_COMPONENT_FACTORY(libchalkmagickimport, MagickImportFactory("kofficefilters"))
+
+MagickImport::MagickImport(KoFilter *, const char *, const TQStringList&) : KoFilter()
+{
+}
+
+MagickImport::~MagickImport()
+{
+}
+
+KoFilter::ConversiontqStatus MagickImport::convert(const TQCString&, const TQCString& to)
+{
+ kdDebug(41008) << "Importing using MagickImport!\n";
+
+ if (to != "application/x-chalk")
+ return KoFilter::BadMimeType;
+
+ KisDoc * doc = dynamic_cast<KisDoc*>(m_chain -> outputDocument());
+ KisView * view = static_cast<KisView*>(doc -> views().getFirst());
+
+ TQString filename = m_chain -> inputFile();
+
+ if (!doc)
+ return KoFilter::CreationError;
+
+ doc -> prepareForImport();
+
+
+ if (!filename.isEmpty()) {
+
+ KURL url;
+ url.setPath(filename);
+
+ if (url.isEmpty())
+ return KoFilter::FileNotFound;
+
+ KisImageMagickConverter ib(doc, doc -> undoAdapter());
+
+ if (view != 0)
+ view -> canvasSubject() -> progressDisplay() -> setSubject(&ib, false, true);
+
+ switch (ib.buildImage(url)) {
+ case KisImageBuilder_RESULT_UNSUPPORTED:
+ return KoFilter::NotImplemented;
+ break;
+ case KisImageBuilder_RESULT_INVALID_ARG:
+ return KoFilter::BadMimeType;
+ break;
+ case KisImageBuilder_RESULT_NO_URI:
+ case KisImageBuilder_RESULT_NOT_LOCAL:
+ return KoFilter::FileNotFound;
+ break;
+ case KisImageBuilder_RESULT_BAD_FETCH:
+ case KisImageBuilder_RESULT_EMPTY:
+ return KoFilter::ParsingError;
+ break;
+ case KisImageBuilder_RESULT_FAILURE:
+ return KoFilter::InternalError;
+ break;
+ case KisImageBuilder_RESULT_OK:
+ doc -> setCurrentImage( ib.image());
+ return KoFilter::OK;
+ default:
+ break;
+ }
+
+ }
+ return KoFilter::StorageCreationError;
+}
+
+#include <magickimport.moc>
+
diff --git a/filters/chalk/magick/magickimport.h b/filters/chalk/magick/magickimport.h
new file mode 100644
index 00000000..3373f129
--- /dev/null
+++ b/filters/chalk/magick/magickimport.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef MAGICKIMPORT_H_
+#define MAGICKIMPORT_H_
+
+#include <KoFilter.h>
+
+class MagickImport : public KoFilter {
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ MagickImport(KoFilter *tqparent, const char *name, const TQStringList&);
+ virtual ~MagickImport();
+
+public:
+ virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to);
+};
+
+#endif // MAGICKIMPORT_H_
+
diff --git a/filters/chalk/openexr/Makefile.am b/filters/chalk/openexr/Makefile.am
new file mode 100644
index 00000000..26470890
--- /dev/null
+++ b/filters/chalk/openexr/Makefile.am
@@ -0,0 +1,51 @@
+AM_CPPFLAGS= \
+ -I$(srcdir) \
+ -I$(top_srcdir)/chalk \
+ -I$(top_srcdir)/chalk/core \
+ -I$(top_srcdir)/chalk/sdk \
+ -I$(top_srcdir)/chalk/core/tiles \
+ -I$(top_srcdir)/chalk/chalkcolor \
+ -I$(top_srcdir)/chalk/ui \
+ -I$(top_srcdir)/chalk/colorspaces/rgb_f32 \
+ -I$(top_srcdir)/chalk/colorspaces/rgb_f16half \
+ $(KOFFICE_INCLUDES) \
+ -I$(interfacedir) \
+ $(OPENEXR_CFLAGS) \
+ $(all_includes)
+
+kde_module_LTLIBRARIES = libchalk_openexr_import.la libchalk_openexr_export.la
+
+libchalk_openexr_export_la_LDFLAGS = $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -module -avoid-version -no-undefined $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalk_openexr_export_la_LIBADD = \
+ $(KOFFICE_LIBS) \
+ $(OPENEXR_LIBS) \
+ $(top_builddir)/chalk/libchalkcommon.la \
+ $(top_builddir)/chalk/colorspaces/rgb_f32/libchalk_rgb_f32.la \
+ $(top_builddir)/chalk/colorspaces/rgb_f16half/libchalk_rgb_f16half.la
+
+
+libchalk_openexr_import_la_LDFLAGS = $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -module -avoid-version -no-undefined $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts -L../../../lib/kofficecore/.libs/ -lkofficecore \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalk_openexr_import_la_LIBADD = \
+ $(KOFFICE_LIBS) \
+ $(OPENEXR_LIBS) \
+ $(top_builddir)/chalk/libchalkcommon.la \
+ $(top_builddir)/chalk/colorspaces/rgb_f32/libchalk_rgb_f32.la \
+ $(top_builddir)/chalk/colorspaces/rgb_f16half/libchalk_rgb_f16half.la
+
+
+service_DATA = chalk_openexr_import.desktop chalk_openexr_export.desktop
+servicedir = $(kde_servicesdir)
+
+kdelnk_DATA = chalk_openexr.desktop
+kdelnkdir = $(kde_appsdir)/.hidden
+
+libchalk_openexr_import_la_SOURCES = kis_openexr_import.cpp
+libchalk_openexr_export_la_SOURCES = kis_openexr_export.cpp
+
+METASOURCES = AUTO
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+
diff --git a/filters/chalk/openexr/chalk_openexr.desktop b/filters/chalk/openexr/chalk_openexr.desktop
new file mode 100644
index 00000000..26f81ccd
--- /dev/null
+++ b/filters/chalk/openexr/chalk_openexr.desktop
@@ -0,0 +1,57 @@
+[Desktop Entry]
+Name=Chalk
+Name[hi]=के-रिता
+Name[km]= Chalk
+Name[lo]=ກຣິຕາ
+Name[ne]=क्रिता
+Exec=chalk %u
+GenericName=Painting and Image Editing Application
+GenericName[bg]=Редактор на графични изображения
+GenericName[ca]=Programa de dibuix i manipulació d'imatges
+GenericName[cs]=Malování a úpravy obrázků
+GenericName[cy]=Cymhwysiad Peintio Golygu Delweddau
+GenericName[da]=Male- og billedredigeringsprogram
+GenericName[de]=Mal- und Bildbearbeitungsprogramm
+GenericName[el]=Εφαρμογή επεξεργασίας εικόνων
+GenericName[eo]=Aplikaĵo por Pentrado kaj Bildredaktado
+GenericName[es]=Aplicación de pintura y de edición de imágenes
+GenericName[et]=Joonistamise ja pilditöötluse rakendus
+GenericName[eu]=Irudien marrazketa eta ediziorako aplikazioa
+GenericName[fa]=کاربرد ویرایش تصویر و نقاشی
+GenericName[fi]=Maalaus- ja kuvankäsitelyohjelma
+GenericName[fr]=Application de dessin et de manipulation d'images
+GenericName[fy]=Ofbyldingsmanipulaasje
+GenericName[gl]=Aplicación de Pintura e Manipulación de Imaxes
+GenericName[he]=יישום לציור ועריכת תמונות
+GenericName[hr]=Aplikacija za obradu slika i fotografija
+GenericName[hu]=Képszerkesztő
+GenericName[is]=Málun og myndritill
+GenericName[it]=Applicazione di disegno e di modifica delle immagini
+GenericName[ja]=描画と画像編集のためのアプリケーション
+GenericName[km]=កម្មវិធី​គូរ​គំនូរ និង​កែសម្រួល​រូបភាព
+GenericName[lv]=Zīmēšanas un attēlu apstrādes programma
+GenericName[nb]=Program for tegning og bilderedigering
+GenericName[nds]=Programm för't Malen un Bildbewerken
+GenericName[ne]=पेन्टीङ्ग र छवि सम्पादन अनुप्रयोग
+GenericName[nl]=Afbeeldingsmanipulatie
+GenericName[pl]=Program do edycji zdjęć oraz rysunków
+GenericName[pt]=Aplicação de Pintura e Edição de Imagens
+GenericName[pt_BR]=Aplicação de Pintura e Edição de Imagens
+GenericName[ru]=Растровые изображения
+GenericName[se]=Málen- ja govvagieđahallanprográmma
+GenericName[sk]=Program pre tvorbu a úpravu obrázkov
+GenericName[sl]=Program za risanje in obdelavo slik
+GenericName[sr]=Програм за цртање и уређивање слика
+GenericName[sr@Latn]=Program za crtanje i uređivanje slika
+GenericName[sv]=Målnings- och bildredigeringsprogram
+GenericName[uk]=Програма для малювання і редагування зображень
+GenericName[uz]=Rasmlar bilan ishlaydigan dastur
+GenericName[uz@cyrillic]=Расмлар билан ишлайдиган дастур
+GenericName[zh_CN]=绘图和图像编辑应用程序
+GenericName[zh_TW]=繪圖與影像處理程式
+MimeType=image/x-exr
+Type=Application
+Icon=chalk
+Categories=
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Multi
diff --git a/filters/chalk/openexr/chalk_openexr_export.desktop b/filters/chalk/openexr/chalk_openexr_export.desktop
new file mode 100644
index 00000000..92b68518
--- /dev/null
+++ b/filters/chalk/openexr/chalk_openexr_export.desktop
@@ -0,0 +1,52 @@
+[Desktop Entry]
+Name=Chalk OpenEXR Export Filter
+Name[bg]=Филтър за експортиране от Chalk в OpenEXR
+Name[br]=Sil ezporzh OpenEXR evit Chalk
+Name[ca]=Filtre d'exportació OpenEXR per a Chalk
+Name[cy]=Hidl Allforio OpenEXR Chalk
+Name[da]=Chalk OpenEXR-eksportfilter
+Name[de]=Chalk OpenEXR-Exportfilter
+Name[el]=Φίλτρο εξαγωγής OpenEXR του Chalk
+Name[eo]=Chalk OpenEXR-eksportfiltrilo
+Name[es]=Filtro de exportación a OpenEXR de Chalk
+Name[et]=Chalk OpenEXR'i ekspordifilter
+Name[fa]=پالایۀ صادرات Chalk OpenEXR
+Name[fi]=Chalk OpenEXR -vientisuodin
+Name[fr]=Filtre d'exportation OpenEXR de Chalk
+Name[fy]=Chalk OpenEXR Eksportfilter
+Name[ga]=Scagaire Easpórtála OpenEXR Chalk
+Name[gl]=Filtro de Exportación de OpenEXR de Chalk
+Name[he]=Chalk OpenEXR מסנן יצוא
+Name[hr]=Chalk OpenEXR filtar izvoza
+Name[hu]=Chalk OpenEXR exportszűrő
+Name[is]=Chalk OpenEXR útflutningssía
+Name[it]=Filtro di esportazione OpenEXR per Chalk
+Name[ja]=Chalk OpenEXR エクスポートフィルタ
+Name[km]=តម្រង​នាំចេញ OpenEXR សម្រាប់ Chalk
+Name[lt]=Chalk OpenEXR eksportavimo filtras
+Name[lv]=Chalk OpenEXR eksporta filtrs
+Name[nb]=OpenEXR-eksportfilter for Chalk
+Name[nds]=OpenEXR-Exportfilter för Chalk
+Name[ne]=क्रिता खुलाEXR निर्यात फिल्टर
+Name[nl]=Chalk OpenEXR Exportfilter
+Name[pl]=Filtr eksportu do formatu OpenEXR z Chalk
+Name[pt]=Filtro de Exportação de OpenEXR do Chalk
+Name[pt_BR]=Filtro de Exportação de OpenEXR do Chalk
+Name[ru]=Фильтр экспорта рисунков Chalk в OpenEXR
+Name[se]=Chalk OpenEXR-olggosfievrridansilli
+Name[sk]=Exportný filter Chalk OpenEXR
+Name[sl]=Izvozni filter OpenEXR za Krito
+Name[sr]=Chalk-ин филтер за извоз у OpenEXR
+Name[sr@Latn]=Chalk-in filter za izvoz u OpenEXR
+Name[sv]=Chalk OpenEXR-exportfilter
+Name[uk]=Фільтр експорту OpenEXR для Chalk
+Name[uz]=Chalk OpenEXR eksport filteri
+Name[uz@cyrillic]=Chalk OpenEXR экспорт филтери
+Name[zh_CN]=Chalk OpenEXR 导出过滤器
+Name[zh_TW]=Chalk OpenEXR 匯出過濾程式
+X-KDE-Export=image/x-exr
+ServiceTypes=KOfficeFilter
+Type=Service
+X-KDE-Import=application/x-chalk
+X-KDE-Weight=1
+X-KDE-Library=libchalk_openexr_export
diff --git a/filters/chalk/openexr/chalk_openexr_import.desktop b/filters/chalk/openexr/chalk_openexr_import.desktop
new file mode 100644
index 00000000..60f6bc54
--- /dev/null
+++ b/filters/chalk/openexr/chalk_openexr_import.desktop
@@ -0,0 +1,52 @@
+[Desktop Entry]
+Type=Service
+Name=Chalk OpenEXR Import Filter
+Name[bg]=Филтър за импортиране от OpenEXR в Chalk
+Name[br]=Sil enporzh OpenEXR evit Chalk
+Name[ca]=Filtre d'importació OpenEXR per a Chalk
+Name[cy]=Hidl Mewnforio OpenEXR Chalk
+Name[da]=Chalk OpenEXR-importfilter
+Name[de]=Chalk OpenEXR-Importfilter
+Name[el]=Φίλτρο εισαγωγής OpenEXR του Chalk
+Name[eo]=Chalk OpenEXR-importfiltrilo
+Name[es]=Filtro de importación a OpenEXR de Chalk
+Name[et]=Chalk OpenEXR'i impordifilter
+Name[fa]=پالایۀ واردات Chalk OpenEXR
+Name[fi]=Chalk OpenEXR -tuontisuodin
+Name[fr]=Filtre d'importation OpenEXT de Chalk
+Name[fy]=Chalk OpenEXR Ymportfilter
+Name[ga]=Scagaire Iompórtála OpenEXR Chalk
+Name[gl]=Filtro de Importación de OpenEXR para Chalk
+Name[he]=Chalk OpenEXR מסנן יבוא
+Name[hr]=Chalk OpenEXR filtar uvoza
+Name[hu]=Chalk OpenEXR importszűrő
+Name[is]=Chalk OpenEXR innflutningssía
+Name[it]=Filtro di importazione OpenEXR per Chalk
+Name[ja]=Chalk OpenEXR インポートフィルタ
+Name[km]=តម្រង​នាំចូល OpenEXR សម្រាប់ Chalk
+Name[lt]=Chalk OpenEXR importavimo filtras
+Name[lv]=Chalk OpenEXR importa filtrs
+Name[nb]=OpenEXR-importfilter for Chalk
+Name[nds]=OpenEXR-Importfilter för Chalk
+Name[ne]=क्रिता खुलाEXR आयात फिल्टर
+Name[nl]=Chalk OpenEXR Importfilter
+Name[pl]=Filtr importu formatu OpenEXR do Chalk
+Name[pt]=Filtro de Importação de OpenEXR para o Chalk
+Name[pt_BR]=Filtro de Importação de OpenEXR para o Chalk
+Name[ru]=Фильтр импорта рисунков OpenEXR в Chalk
+Name[se]=Chalk OpenEXR-sisafievrridansilli
+Name[sk]=OpenEXR filter pre import do Chalk
+Name[sl]=Uvozni filter OpenEXR za Krito
+Name[sr]=Chalk-ин филтер за увоз из OpenEXR-а
+Name[sr@Latn]=Chalk-in filter za uvoz iz OpenEXR-a
+Name[sv]=Chalk OpenEXR-importfilter
+Name[uk]=Фільтр імпорту OpenEXR для Chalk
+Name[uz]=Chalk OpenEXR import filteri
+Name[uz@cyrillic]=Chalk OpenEXR импорт филтери
+Name[zh_CN]=Chalk OpenEXR 导入过滤器
+Name[zh_TW]=Chalk OpenEXR 匯入過濾程式
+X-KDE-Export=application/x-chalk
+X-KDE-Import=image/x-exr
+X-KDE-Weight=1
+X-KDE-Library=libchalk_openexr_import
+ServiceTypes=KOfficeFilter
diff --git a/filters/chalk/openexr/configure.in.bot b/filters/chalk/openexr/configure.in.bot
new file mode 100644
index 00000000..3a743f82
--- /dev/null
+++ b/filters/chalk/openexr/configure.in.bot
@@ -0,0 +1,9 @@
+if test -z "$OPENEXR_LIBS"; then
+ echo ""
+ echo "You're missing the OpenEXR library. Chalk's OpenEXR import/export filter will "
+ echo "not be compiled. You can download OpenEXR from http://www.openexr.com or "
+ echo "install it from an appropriate binary package."
+ echo ""
+ all_tests=bad
+fi
+
diff --git a/filters/chalk/openexr/kis_openexr_export.cpp b/filters/chalk/openexr/kis_openexr_export.cpp
new file mode 100644
index 00000000..4859f5d9
--- /dev/null
+++ b/filters/chalk/openexr/kis_openexr_export.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2005 Adrian Page <adrian@pagenet.plus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <tqfile.h>
+
+#include <kmessagebox.h>
+
+#include <half.h>
+#include <ImfRgbaFile.h>
+
+#include <kgenericfactory.h>
+#include <KoDocument.h>
+#include <KoFilterChain.h>
+
+#include "kis_doc.h"
+#include "kis_image.h"
+#include "kis_layer.h"
+#include "kis_paint_layer.h"
+#include "kis_annotation.h"
+#include "kis_types.h"
+#include "kis_iterators_pixel.h"
+#include "kis_abstract_colorspace.h"
+#include "kis_paint_device.h"
+#include "kis_rgb_f32_colorspace.h"
+#include "kis_rgb_f16half_colorspace.h"
+
+#include "kis_openexr_export.h"
+
+using namespace std;
+using namespace Imf;
+using namespace Imath;
+
+typedef KGenericFactory<KisOpenEXRExport, KoFilter> KisOpenEXRExportFactory;
+K_EXPORT_COMPONENT_FACTORY(libchalk_openexr_export, KisOpenEXRExportFactory("kofficefilters"))
+
+KisOpenEXRExport::KisOpenEXRExport(KoFilter *, const char *, const TQStringList&) : KoFilter()
+{
+}
+
+KisOpenEXRExport::~KisOpenEXRExport()
+{
+}
+
+KoFilter::ConversiontqStatus KisOpenEXRExport::convert(const TQCString& from, const TQCString& to)
+{
+ if (to != "image/x-exr" || from != "application/x-chalk") {
+ return KoFilter::NotImplemented;
+ }
+
+ kdDebug(41008) << "Chalk exporting to OpenEXR\n";
+
+ // XXX: Add dialog about flattening layers here
+
+ KisDoc *doc = dynamic_cast<KisDoc*>(m_chain -> inputDocument());
+ TQString filename = m_chain -> outputFile();
+
+ if (!doc) {
+ return KoFilter::CreationError;
+ }
+
+ if (filename.isEmpty()) {
+ return KoFilter::FileNotFound;
+ }
+
+ KisImageSP img = new KisImage(*doc -> currentImage());
+ Q_CHECK_PTR(img);
+
+ // Don't store this information in the document's undo adapter
+ bool undo = doc -> undoAdapter() -> undo();
+ doc -> undoAdapter() -> setUndo(false);
+
+ img -> flatten();
+
+ KisPaintLayerSP layer = dynamic_cast<KisPaintLayer*>(img->activeLayer().data());
+ Q_ASSERT(layer);
+
+ doc -> undoAdapter() -> setUndo(undo);
+
+ //KisF32RgbColorSpace * cs = static_cast<KisF32RgbColorSpace *>((KisColorSpaceRegistry::instance() -> get(KisID("RGBAF32", ""))));
+ KisRgbF16HalfColorSpace *cs = dynamic_cast<KisRgbF16HalfColorSpace *>(layer->paintDevice()->colorSpace());
+
+ if (cs == 0) {
+ // We could convert automatically, but the conversion wants to be done with
+ // selectable profiles and rendering intent.
+ KMessageBox::information(0, i18n("The image is using an unsupported color space. "
+ "Please convert to 16-bit floating point RGB/Alpha "
+ "before saving in the OpenEXR format."));
+
+ // Don't show the couldn't save error dialog.
+ doc -> setErrorMessage("USER_CANCELED");
+
+ return KoFilter::WrongFormat;
+ }
+
+ Box2i displayWindow(V2i(0, 0), V2i(img -> width() - 1, img -> height() - 1));
+
+ TQRect dataExtent = layer -> exactBounds();
+ int dataWidth = dataExtent.width();
+ int dataHeight = dataExtent.height();
+
+ Box2i dataWindow(V2i(dataExtent.left(), dataExtent.top()), V2i(dataExtent.right(), dataExtent.bottom()));
+
+ RgbaOutputFile file(TQFile::encodeName(filename), displayWindow, dataWindow, WRITE_RGBA);
+
+ TQMemArray<Rgba> pixels(dataWidth);
+
+ for (int y = 0; y < dataHeight; ++y) {
+
+ file.setFrameBuffer(pixels.data() - dataWindow.min.x - (dataWindow.min.y + y) * dataWidth, 1, dataWidth);
+
+ KisHLineIterator it = layer->paintDevice()->createHLineIterator(dataWindow.min.x, dataWindow.min.y + y, dataWidth, false);
+ Rgba *rgba = pixels.data();
+
+ while (!it.isDone()) {
+
+ // XXX: Currently we use unmultiplied data so premult it.
+ half unmultipliedRed;
+ half unmultipliedGreen;
+ half unmultipliedBlue;
+ half alpha;
+
+ cs -> getPixel(it.rawData(), &unmultipliedRed, &unmultipliedGreen, &unmultipliedBlue, &alpha);
+ rgba -> r = unmultipliedRed * alpha;
+ rgba -> g = unmultipliedGreen * alpha;
+ rgba -> b = unmultipliedBlue * alpha;
+ rgba -> a = alpha;
+ ++it;
+ ++rgba;
+ }
+ file.writePixels();
+ }
+
+ //vKisAnnotationSP_it beginIt = img -> beginAnnotations();
+ //vKisAnnotationSP_it endIt = img -> endAnnotations();
+ return KoFilter::OK;
+}
+
+#include "kis_openexr_export.moc"
+
diff --git a/filters/chalk/openexr/kis_openexr_export.h b/filters/chalk/openexr/kis_openexr_export.h
new file mode 100644
index 00000000..56568e57
--- /dev/null
+++ b/filters/chalk/openexr/kis_openexr_export.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2005 Adrian Page <adrian@pagenet.plus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KIS_OPENEXR_EXPORT_H_
+#define KIS_OPENEXR_EXPORT_H_
+
+#include <KoFilter.h>
+
+class KisOpenEXRExport : public KoFilter {
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ KisOpenEXRExport(KoFilter *tqparent, const char *name, const TQStringList&);
+ virtual ~KisOpenEXRExport();
+
+public:
+ virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to);
+};
+
+#endif // KIS_OPENEXR_EXPORT_H_
+
diff --git a/filters/chalk/openexr/kis_openexr_import.cpp b/filters/chalk/openexr/kis_openexr_import.cpp
new file mode 100644
index 00000000..974d4a67
--- /dev/null
+++ b/filters/chalk/openexr/kis_openexr_import.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2005 Adrian Page <adrian@pagenet.plus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <tqstring.h>
+#include <tqfile.h>
+
+#include <kgenericfactory.h>
+#include <KoDocument.h>
+#include <KoFilterChain.h>
+
+#include <half.h>
+#include <ImfRgbaFile.h>
+//#include <ImfStringAttribute.h>
+//#include <ImfMatrixAttribute.h>
+//#include <ImfArray.h>
+//#include <drawImage.h>
+
+#include <iostream>
+
+#include "kis_types.h"
+#include "kis_openexr_import.h"
+#include "kis_doc.h"
+#include "kis_image.h"
+#include "kis_meta_registry.h"
+#include "kis_layer.h"
+#include "kis_paint_layer.h"
+#include "kis_annotation.h"
+#include "kis_colorspace_factory_registry.h"
+#include "kis_iterators_pixel.h"
+#include "kis_abstract_colorspace.h"
+#include "kis_rgb_f32_colorspace.h"
+#include "kis_rgb_f16half_colorspace.h"
+
+using namespace std;
+using namespace Imf;
+using namespace Imath;
+
+typedef KGenericFactory<KisOpenEXRImport, KoFilter> KisOpenEXRImportFactory;
+K_EXPORT_COMPONENT_FACTORY(libchalk_openexr_import, KisOpenEXRImportFactory("kofficefilters"))
+
+KisOpenEXRImport::KisOpenEXRImport(KoFilter *, const char *, const TQStringList&) : KoFilter()
+{
+}
+
+KisOpenEXRImport::~KisOpenEXRImport()
+{
+}
+
+KoFilter::ConversiontqStatus KisOpenEXRImport::convert(const TQCString& from, const TQCString& to)
+{
+ if (from != "image/x-exr" || to != "application/x-chalk") {
+ return KoFilter::NotImplemented;
+ }
+
+ kdDebug(41008) << "\n\n\nChalk importing from OpenEXR\n";
+
+ KisDoc * doc = dynamic_cast<KisDoc*>(m_chain -> outputDocument());
+ if (!doc) {
+ return KoFilter::CreationError;
+ }
+
+ doc -> prepareForImport();
+
+ TQString filename = m_chain -> inputFile();
+
+ if (filename.isEmpty()) {
+ return KoFilter::FileNotFound;
+ }
+
+ RgbaInputFile file(TQFile::encodeName(filename));
+ Box2i dataWindow = file.dataWindow();
+ Box2i displayWindow = file.displayWindow();
+
+ kdDebug(41008) << "Data window: " << TQRect(dataWindow.min.x, dataWindow.min.y, dataWindow.max.x - dataWindow.min.x + 1, dataWindow.max.y - dataWindow.min.y + 1) << endl;
+ kdDebug(41008) << "Display window: " << TQRect(displayWindow.min.x, displayWindow.min.y, displayWindow.max.x - displayWindow.min.x + 1, displayWindow.max.y - displayWindow.min.y + 1) << endl;
+
+ int imageWidth = displayWindow.max.x - displayWindow.min.x + 1;
+ int imageHeight = displayWindow.max.y - displayWindow.min.y + 1;
+
+ TQString imageName = "Imported from OpenEXR";
+
+ int dataWidth = dataWindow.max.x - dataWindow.min.x + 1;
+ int dataHeight = dataWindow.max.y - dataWindow.min.y + 1;
+
+ KisRgbF16HalfColorSpace *cs = static_cast<KisRgbF16HalfColorSpace *>((KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBAF16HALF", ""),"")));
+
+ if (cs == 0) {
+ return KoFilter::InternalError;
+ }
+
+ doc -> undoAdapter() -> setUndo(false);
+
+ KisImageSP image = new KisImage(doc->undoAdapter(), imageWidth, imageHeight, cs, imageName);
+
+ if (image == 0) {
+ return KoFilter::CreationError;
+ }
+
+ KisPaintLayerSP layer = dynamic_cast<KisPaintLayer*>(image->newLayer(image -> nextLayerName(), OPACITY_OPAQUE).data());
+
+ if (layer == 0) {
+ return KoFilter::CreationError;
+ }
+
+ TQMemArray<Rgba> pixels(dataWidth);
+
+ for (int y = 0; y < dataHeight; ++y) {
+
+ file.setFrameBuffer(pixels.data() - dataWindow.min.x - (dataWindow.min.y + y) * dataWidth, 1, dataWidth);
+ file.readPixels(dataWindow.min.y + y);
+
+ KisHLineIterator it = layer->paintDevice()->createHLineIterator(dataWindow.min.x, dataWindow.min.y + y, dataWidth, true);
+ Rgba *rgba = pixels.data();
+
+ while (!it.isDone()) {
+
+ // XXX: For now unmultiply the alpha, though compositing will be faster if we
+ // keep it premultiplied.
+ half unmultipliedRed = rgba -> r;
+ half unmultipliedGreen = rgba -> g;
+ half unmultipliedBlue = rgba -> b;
+
+ if (rgba -> a >= HALF_EPSILON) {
+ unmultipliedRed /= rgba -> a;
+ unmultipliedGreen /= rgba -> a;
+ unmultipliedBlue /= rgba -> a;
+ }
+
+ cs -> setPixel(it.rawData(), unmultipliedRed, unmultipliedGreen, unmultipliedBlue, rgba -> a);
+ ++it;
+ ++rgba;
+ }
+ }
+
+ layer->setDirty();
+ doc -> setCurrentImage(image);
+ doc -> undoAdapter() -> setUndo(true);
+ doc -> setModified(false);
+
+ return KoFilter::OK;
+}
+
+#include "kis_openexr_import.moc"
+
diff --git a/filters/chalk/openexr/kis_openexr_import.h b/filters/chalk/openexr/kis_openexr_import.h
new file mode 100644
index 00000000..f8cd5144
--- /dev/null
+++ b/filters/chalk/openexr/kis_openexr_import.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2005 Adrian Page <adrian@pagenet.plus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KIS_OPENEXR_IMPORT_H_
+#define KIS_OPENEXR_IMPORT_H_
+
+#include <KoFilter.h>
+
+class KisOpenEXRImport : public KoFilter {
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ KisOpenEXRImport(KoFilter *tqparent, const char *name, const TQStringList&);
+ virtual ~KisOpenEXRImport();
+
+public:
+ virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to);
+};
+
+#endif // KIS_OPENEXR_IMPORT_H_
+
diff --git a/filters/chalk/pdf/Makefile.am b/filters/chalk/pdf/Makefile.am
new file mode 100644
index 00000000..9357a98a
--- /dev/null
+++ b/filters/chalk/pdf/Makefile.am
@@ -0,0 +1,30 @@
+INCLUDES = \
+ -I$(srcdir) \
+ $(KOFFICE_INCLUDES) \
+ -I$(top_srcdir)/chalk \
+ -I$(top_srcdir)/chalk/core \
+ -I$(top_srcdir)/chalk/sdk \
+ -I$(top_srcdir)/chalk/core/tiles \
+ -I$(top_srcdir)/chalk/chalkcolor \
+ -I$(top_srcdir)/chalk/ui \
+ $(KOFFICE_INCLUDES) -I$(interfacedir) \
+ $(KOPAINTER_INCLUDES) \
+ $(all_includes) $(POPPLER_CFLAGS)
+
+servicedir = $(kde_servicesdir)
+
+kdelnkdir = $(kde_appsdir)/.hidden
+
+METASOURCES = AUTO
+kde_module_LTLIBRARIES = libchalkpdfimport.la
+libchalkpdfimport_la_LDFLAGS = -avoid-version -module -no-undefined $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalkpdfimport_la_LIBADD = $(top_builddir)/chalk/libchalkcommon.la \
+ -lpoppler-qt $(KOFFICE_LIBS) $(POPPLER_LIBS)
+
+noinst_HEADERS = kis_pdf_import.h kis_pdf_import_widget.h
+libchalkpdfimport_la_SOURCES = kis_pdf_import.cpp pdfimportwidgetbase.ui \
+ kis_pdf_import_widget.cpp
+kde_services_DATA = chalk_pdf_import.desktop
+kdelnk_DATA = chalk_pdf.desktop
diff --git a/filters/chalk/pdf/chalk_pdf.desktop b/filters/chalk/pdf/chalk_pdf.desktop
new file mode 100644
index 00000000..b518da84
--- /dev/null
+++ b/filters/chalk/pdf/chalk_pdf.desktop
@@ -0,0 +1,63 @@
+[Desktop Entry]
+Categories=
+Exec=chalk %u
+GenericName=Painting and Image Editing Application
+GenericName[bg]=Редактор на графични изображения
+GenericName[ca]=Programa de dibuix i manipulació d'imatges
+GenericName[cs]=Malování a úpravy obrázků
+GenericName[cy]=Cymhwysiad Peintio Golygu Delweddau
+GenericName[da]=Male- og billedredigeringsprogram
+GenericName[de]=Mal- und Bildbearbeitungsprogramm
+GenericName[el]=Εφαρμογή επεξεργασίας εικόνων
+GenericName[eo]=Aplikaĵo por Pentrado kaj Bildredaktado
+GenericName[es]=Aplicación de pintura y de edición de imágenes
+GenericName[et]=Joonistamise ja pilditöötluse rakendus
+GenericName[eu]=Irudien marrazketa eta ediziorako aplikazioa
+GenericName[fa]=کاربرد ویرایش تصویر و نقاشی
+GenericName[fi]=Maalaus- ja kuvankäsitelyohjelma
+GenericName[fr]=Application de dessin et de manipulation d'images
+GenericName[fy]=Ofbyldingsmanipulaasje
+GenericName[gl]=Aplicación de Pintura e Manipulación de Imaxes
+GenericName[he]=יישום לציור ועריכת תמונות
+GenericName[hr]=Aplikacija za obradu slika i fotografija
+GenericName[hu]=Képszerkesztő
+GenericName[is]=Málun og myndritill
+GenericName[it]=Applicazione di disegno e di modifica delle immagini
+GenericName[ja]=描画と画像編集のためのアプリケーション
+GenericName[km]=កម្មវិធី​គូរ​គំនូរ និង​កែសម្រួល​រូបភាព
+GenericName[lv]=Zīmēšanas un attēlu apstrādes programma
+GenericName[nb]=Program for tegning og bilderedigering
+GenericName[nds]=Programm för't Malen un Bildbewerken
+GenericName[ne]=पेन्टीङ्ग र छवि सम्पादन अनुप्रयोग
+GenericName[nl]=Afbeeldingsmanipulatie
+GenericName[pl]=Program do edycji zdjęć oraz rysunków
+GenericName[pt]=Aplicação de Pintura e Edição de Imagens
+GenericName[pt_BR]=Aplicação de Pintura e Edição de Imagens
+GenericName[ru]=Растровые изображения
+GenericName[se]=Málen- ja govvagieđahallanprográmma
+GenericName[sk]=Program pre tvorbu a úpravu obrázkov
+GenericName[sl]=Program za risanje in obdelavo slik
+GenericName[sr]=Програм за цртање и уређивање слика
+GenericName[sr@Latn]=Program za crtanje i uređivanje slika
+GenericName[sv]=Målnings- och bildredigeringsprogram
+GenericName[uk]=Програма для малювання і редагування зображень
+GenericName[uz]=Rasmlar bilan ishlaydigan dastur
+GenericName[uz@cyrillic]=Расмлар билан ишлайдиган дастур
+GenericName[zh_CN]=绘图和图像编辑应用程序
+GenericName[zh_TW]=繪圖與影像處理程式
+Icon=chalk
+MimeType=application/pdf
+Name=Chalk
+Name[hi]=के-रिता
+Name[km]= Chalk
+Name[lo]=ກຣິຕາ
+Name[ne]=क्रिता
+Path=
+StartupNotify=true
+Terminal=false
+TerminalOptions=
+Type=Application
+X-DCOP-ServiceType=multi
+X-KDE-StartupNotify=true
+X-KDE-SubstituteUID=false
+X-KDE-Username=
diff --git a/filters/chalk/pdf/chalk_pdf_import.desktop b/filters/chalk/pdf/chalk_pdf_import.desktop
new file mode 100644
index 00000000..cfc6e1ea
--- /dev/null
+++ b/filters/chalk/pdf/chalk_pdf_import.desktop
@@ -0,0 +1,51 @@
+[Desktop Entry]
+Type=Service
+Name=Chalk PDF Import Filter
+Name[bg]=Филтър за импортиране от PDF в Chalk
+Name[br]=Sil enporzh PDF evit Chalk
+Name[ca]=Filtre d'importació PDF per a Chalk
+Name[da]=Chalk PDF-importfilter
+Name[de]=Chalk PDF-Importfilter
+Name[el]=Φίλτρο εισαγωγής PDF του Chalk
+Name[eo]=Chalk PD-importfiltrilo
+Name[es]=Filtro de importación a PDF de Chalk
+Name[et]=Chalk PDF impordifilter
+Name[fa]=پالایۀ واردات Chalk PDF
+Name[fr]=Filtre d'importation PDF de Chalk
+Name[fy]=Chalk PDF Ymportfilter
+Name[ga]=Scagaire Iompórtála PDF Chalk
+Name[gl]=Filtro de Importación de PDF para Chalk
+Name[hr]=Chalk PDF filtar uvoza
+Name[hu]=Chalk PDF importszűrő
+Name[it]=Filtro di importazione PDF per Chalk
+Name[ja]=Chalk PDF インポートフィルタ
+Name[km]=តម្រង​នាំចូល PNG របស់​រាប់ Chalk
+Name[lt]=Chalk PDF importavimo filtras
+Name[lv]=Chalk PDF importa filtrs
+Name[nb]=PDF-importfilter for Chalk
+Name[nds]=PDF-Importfilter för Chalk
+Name[ne]=क्रिता PDF आयात फिल्टर
+Name[nl]=Chalk PDF Importfilter
+Name[pl]=Filtr importu formatu PDF do Chalk
+Name[pt]=Filtro de Importação de PDF para o Chalk
+Name[pt_BR]=Filtro de Importação de PDF para o Chalk
+Name[ru]=Фильтр импорта документов PDF в Chalk
+Name[se]=Chalk PDF-sisafievrridansilli
+Name[sk]=PDF filter pre import do Chalk
+Name[sl]=Uvozni filter PDF za Krito
+Name[sr]=Chalk-ин филтер за увоз из PDF-а
+Name[sr@Latn]=Chalk-in filter za uvoz iz PDF-a
+Name[sv]=Chalk PDF-importfilter
+Name[uk]=Фільтр імпорту PDF для Chalk
+Name[uz]=Chalk uchun PDF import filteri
+Name[uz@cyrillic]=Chalk учун PDF импорт филтери
+Name[zh_TW]=Chalk PDF 匯入過濾程式
+Comment=
+Comment[uz]=PDF-fayllarni Chalk bilan oʻqish vositasi
+Comment[uz@cyrillic]=PDF-файлларни Chalk билан ўқиш воситаси
+ServiceTypes=KOfficeFilter
+X-KDE-Available=
+X-KDE-Export=application/x-chalk
+X-KDE-Import=application/pdf
+X-KDE-Weight=1
+X-KDE-Library=libchalkpdfimport
diff --git a/filters/chalk/pdf/configure.in.bot b/filters/chalk/pdf/configure.in.bot
new file mode 100644
index 00000000..89bd198e
--- /dev/null
+++ b/filters/chalk/pdf/configure.in.bot
@@ -0,0 +1,7 @@
+if test -z "$POPPLER_LIBS"; then
+ echo ""
+ echo "You're missing libpoppler 0.5.1 or later (binaries and/or headers)."
+ echo "chalk won't be able to import pdf"
+ echo "note that the qt-binding of libpoppler is required"
+ echo ""
+fi
diff --git a/filters/chalk/pdf/configure.in.in b/filters/chalk/pdf/configure.in.in
new file mode 100644
index 00000000..e4343277
--- /dev/null
+++ b/filters/chalk/pdf/configure.in.in
@@ -0,0 +1,4 @@
+# Compile the pdf import filter only if Poppler is available
+PKG_CHECK_MODULES(POPPLER, poppler-qt >= 0.5.1, have_poppler=yes, have_poppler=no)
+
+AM_CONDITIONAL(include_PDF, test "x$have_poppler" = xyes)
diff --git a/filters/chalk/pdf/kis_pdf_import.cpp b/filters/chalk/pdf/kis_pdf_import.cpp
new file mode 100644
index 00000000..2cef93e9
--- /dev/null
+++ b/filters/chalk/pdf/kis_pdf_import.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_pdf_import.h"
+
+// poppler's headers
+#include <poppler-qt.h>
+
+// TQt's headers
+#include <tqfile.h>
+#include <tqimage.h> // TODO that too
+#include <tqradiobutton.h>
+
+// KDE's headers
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kdialogbase.h>
+#include <kgenericfactory.h>
+#include <knuminput.h>
+#include <kpassdlg.h>
+
+#include <kio/netaccess.h>
+
+// koffice's headers
+#include <KoFilterChain.h>
+
+// chalk's headers
+#include <kis_doc.h>
+#include <kis_colorspace.h>
+#include <kis_colorspace_factory_registry.h>
+#include <kis_group_layer.h>
+#include <kis_image.h>
+#include <kis_meta_registry.h>
+#include <kis_paint_layer.h>
+
+// plugins's headers
+#include "kis_pdf_import_widget.h"
+
+typedef KGenericFactory<KisPDFImport, KoFilter> PDFImportFactory;
+K_EXPORT_COMPONENT_FACTORY(libchalkpdfimport, PDFImportFactory("kofficefilters"))
+
+KisPDFImport::KisPDFImport(KoFilter *, const char *, const TQStringList&) : KoFilter()
+{
+}
+
+KisPDFImport::~KisPDFImport()
+{
+}
+
+KisPDFImport::ConversiontqStatus KisPDFImport::convert(const TQCString& , const TQCString& )
+{
+ TQString filename = m_chain -> inputFile();
+ kdDebug(41008) << "Importing using PDFImport!" << filename << endl;
+
+ if (filename.isEmpty())
+ return KoFilter::FileNotFound;
+
+
+ KURL url;
+ url.setPath(filename);
+
+ if (!KIO::NetAccess::exists(url, false, tqApp -> mainWidget())) {
+ return KoFilter::FileNotFound;
+ }
+
+ // We're not set up to handle asynchronous loading at the moment.
+ TQString tmpFile;
+ if (KIO::NetAccess::download(url, tmpFile, tqApp -> mainWidget())) {
+ url.setPath( tmpFile );
+ }
+
+ Poppler::Document* pdoc = Poppler::Document::load( TQFile::encodeName(url.path() ) );
+
+
+ if ( !pdoc)
+ {
+ kdDebug(41008) << "Error when reading the PDF" << endl;
+ return KoFilter::StorageCreationError;
+ }
+
+
+ while( pdoc->isLocked() )
+ {
+ TQCString password;
+ int result = KPasswordDialog::getPassword(password, i18n("A password is required to read that pdf"));
+ if (result == KPasswordDialog::Accepted)
+ {
+ pdoc->unlock(password);
+ } else {
+ kdDebug(41008) << "Password canceled" << endl;
+ return KoFilter::StorageCreationError;
+ }
+ }
+
+ KDialogBase* kdb = new KDialogBase(0, "", false, i18n("PDF Import Options"), KDialogBase::Ok | KDialogBase::Cancel);
+
+ KisPDFImportWidget* wdg = new KisPDFImportWidget(pdoc, kdb);
+ kdb->setMainWidget(wdg);
+ kapp->restoreOverrideCursor();
+ if(kdb->exec() == TQDialog::Rejected)
+ {
+ delete pdoc;
+ delete kdb;
+ return KoFilter::StorageCreationError; // FIXME Cancel doesn't exist :(
+ }
+
+ // Init kis's doc
+ KisDoc * doc = dynamic_cast<KisDoc*>(m_chain -> outputDocument());
+ if (!doc)
+ {
+ delete pdoc;
+ delete kdb;
+ return KoFilter::CreationError;
+ }
+
+ doc -> prepareForImport();
+ // Create the chalk image
+ KisColorSpace* cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA"), "");
+ int width = wdg->intWidth->value();
+ int height = wdg->intHeight->value();
+ KisImageSP img = new KisImage(doc->undoAdapter(), width, height, cs, "built image");
+ img->blockSignals(true); // Don't send out signals while we're building the image
+
+ // create a layer
+ TQValueList<int> pages = wdg->pages();
+ for(TQValueList<int>::const_iterator it = pages.begin(); it != pages.end(); ++it)
+ {
+ KisPaintLayer* layer = new KisPaintLayer(img, TQString(i18n("Page %1")).tqarg( TQString::number(*it) + 1), TQ_UINT8_MAX);
+ layer->paintDevice()->convertFromTQImage( pdoc->getPage( *it )->renderToImage(wdg->intHorizontal->value(), wdg->intVertical->value() ), "");
+ img->addLayer(layer, img->rootLayer(), 0);
+ }
+
+ img->blockSignals(false);
+ doc -> setCurrentImage( img);
+
+ KIO::NetAccess::removeTempFile(tmpFile);
+
+ delete pdoc;
+ delete kdb;
+ return KoFilter::OK;
+}
+
diff --git a/filters/chalk/pdf/kis_pdf_import.h b/filters/chalk/pdf/kis_pdf_import.h
new file mode 100644
index 00000000..ab4535b9
--- /dev/null
+++ b/filters/chalk/pdf/kis_pdf_import.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KIS_PDF_IMPORT_H
+#define KIS_PDF_IMPORT_H
+
+#include <KoFilter.h>
+
+class KisPDFImport : public KoFilter{
+ Q_OBJECT
+ TQ_OBJECT
+ public:
+ KisPDFImport(KoFilter *tqparent, const char *name, const TQStringList&);
+ virtual ~KisPDFImport();
+ public:
+ virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to);
+};
+
+#endif
diff --git a/filters/chalk/pdf/kis_pdf_import_widget.cpp b/filters/chalk/pdf/kis_pdf_import_widget.cpp
new file mode 100644
index 00000000..6919876f
--- /dev/null
+++ b/filters/chalk/pdf/kis_pdf_import_widget.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_pdf_import_widget.h"
+
+// poppler's headers
+#include <poppler-qt.h>
+
+// TQt's headers
+#include <tqradiobutton.h>
+
+// KDE's headers
+#include <kdebug.h>
+#include <klistbox.h>
+#include <knuminput.h>
+
+KisPDFImportWidget::KisPDFImportWidget(Poppler::Document* pdfDoc, TQWidget * tqparent, const char * name)
+ : PDFImportWidgetBase(tqparent, name), m_pdfDoc(pdfDoc)
+{
+ m_pages.push_back(0); // The first page is selected
+ updateMaxCanvasSize();
+
+ for(int i = 1; i <= m_pdfDoc->getNumPages(); i++)
+ {
+ listPages->insertItem(TQString::number( i ) );
+ }
+
+ connect(intWidth, TQT_SIGNAL( valueChanged ( int ) ), this, TQT_SLOT( updateHRes() ) );
+ connect(intHeight, TQT_SIGNAL( valueChanged ( int ) ), this, TQT_SLOT( updateHVer() ) );
+ connect(intHorizontal, TQT_SIGNAL( valueChanged ( int ) ), this, TQT_SLOT( updateWidth() ) );
+ connect(intVertical, TQT_SIGNAL( valueChanged ( int ) ), this, TQT_SLOT( updateHeight() ) );
+ connect(boolAllPages, TQT_SIGNAL( toggled ( bool ) ), this, TQT_SLOT( selectAllPages( bool ) ) );
+ connect(boolFirstPage, TQT_SIGNAL( toggled ( bool ) ), this, TQT_SLOT( selectFirstPage( bool ) ) );
+ connect(boolSelectionPage, TQT_SIGNAL( toggled ( bool ) ), this, TQT_SLOT( selectSelectionOfPages( bool ) ) );
+ connect(listPages, TQT_SIGNAL(selectionChanged () ), this, TQT_SLOT(updateSelectionOfPages()));
+}
+
+
+KisPDFImportWidget::~KisPDFImportWidget()
+{
+}
+
+void KisPDFImportWidget::selectAllPages(bool v)
+{
+ if(v)
+ {
+ m_pages.clear();
+ for(int i = 0; i < m_pdfDoc->getNumPages(); i++)
+ {
+ m_pages.push_back(i);
+ }
+ updateMaxCanvasSize();
+ }
+}
+void KisPDFImportWidget::selectFirstPage(bool v)
+{
+ if(v)
+ {
+ m_pages.clear();
+ m_pages.push_back(0); // The first page is selected
+ }
+}
+void KisPDFImportWidget::selectSelectionOfPages(bool v)
+{
+ if(v)
+ {
+ updateSelectionOfPages();
+ updateMaxCanvasSize();
+ }
+
+}
+
+void KisPDFImportWidget::updateSelectionOfPages()
+{
+ if(! boolSelectionPage->isChecked ()) boolSelectionPage->toggle();
+ m_pages.clear();
+ for(int i = 0; i < m_pdfDoc->getNumPages(); i++)
+ {
+ if(listPages->isSelected(i)) m_pages.push_back(i);
+ }
+}
+
+
+void KisPDFImportWidget::updateMaxCanvasSize() {
+ m_maxWidthInch = 0., m_maxHeightInch =0.;
+ for(TQValueList<int>::const_iterator it = m_pages.begin(); it != m_pages.end(); ++it)
+ {
+ Poppler::Page *p = m_pdfDoc->getPage(*it );
+ TQSize size = p->pageSize();
+ if(size.width() > m_maxWidthInch)
+ {
+ m_maxWidthInch = size.width();
+ }
+ if(size.height() > m_maxHeightInch)
+ {
+ m_maxHeightInch = size.height();
+ }
+ }
+ m_maxWidthInch /= 72.;
+ m_maxHeightInch /= 72.;
+ kdDebug() << m_maxWidthInch << " " << m_maxHeightInch << endl;
+ updateWidth();
+ updateHeight();
+}
+
+void KisPDFImportWidget::updateWidth()
+{
+ intWidth->blockSignals(true);
+ intWidth->setValue( (int) m_maxWidthInch * intHorizontal->value() + 1 );
+ intWidth->blockSignals(false);
+}
+void KisPDFImportWidget::updateHeight()
+{
+ intHeight->blockSignals(true);
+ intHeight->setValue( (int) m_maxHeightInch * intVertical->value() + 1 );
+ intHeight->blockSignals(false);
+}
+void KisPDFImportWidget::updateHRes()
+{
+ intHorizontal->blockSignals(true);
+ intHorizontal->setValue( (int) (intWidth->value() / m_maxWidthInch ) );
+ intHorizontal->blockSignals(false);
+}
+void KisPDFImportWidget::updateHVer()
+{
+ intVertical->blockSignals(true);
+ intVertical->setValue( (int) (intHeight->value() / m_maxHeightInch ) );
+ intVertical->blockSignals(false);
+}
+
+#include "kis_pdf_import_widget.moc"
diff --git a/filters/chalk/pdf/kis_pdf_import_widget.h b/filters/chalk/pdf/kis_pdf_import_widget.h
new file mode 100644
index 00000000..8fe806a8
--- /dev/null
+++ b/filters/chalk/pdf/kis_pdf_import_widget.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KIS_PDF_IMPORT_WIDGET_H
+#define KIS_PDF_IMPORT_WIDGET_H
+
+#include <pdfimportwidgetbase.h>
+
+namespace Poppler {
+class Document;
+}
+
+class KisPDFImportWidget : public PDFImportWidgetBase
+{
+ Q_OBJECT
+ TQ_OBJECT
+ public:
+ KisPDFImportWidget(Poppler::Document* pdfDoc, TQWidget * tqparent, const char * name = "");
+
+ ~KisPDFImportWidget();
+ public:
+ inline TQValueList<int> pages() { return m_pages; }
+ private slots:
+ void selectAllPages(bool v);
+ void selectFirstPage(bool v);
+ void selectSelectionOfPages(bool v);
+ void updateSelectionOfPages();
+ void updateWidth();
+ void updateHeight();
+ void updateHRes();
+ void updateHVer();
+ void updateMaxCanvasSize();
+ private:
+ Poppler::Document* m_pdfDoc;
+ TQValueList<int> m_pages;
+ double m_maxWidthInch, m_maxHeightInch;
+};
+
+#endif
diff --git a/filters/chalk/pdf/pdfimportwidgetbase.ui b/filters/chalk/pdf/pdfimportwidgetbase.ui
new file mode 100644
index 00000000..19da5d15
--- /dev/null
+++ b/filters/chalk/pdf/pdfimportwidgetbase.ui
@@ -0,0 +1,321 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>PDFImportWidgetBase</class>
+<widget class="TQWidget">
+ <property name="name">
+ <cstring>PDFImportWidgetBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>462</width>
+ <height>210</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>PDFImportWidget</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQGroupBox" row="0" column="1">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Dimensions</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Resolution:</string>
+ </property>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>tqlayout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="tqsizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>tqlayout2</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel" row="1" column="0">
+ <property name="name">
+ <cstring>intVerticalqsdf</cstring>
+ </property>
+ <property name="text">
+ <string>Vertical:</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="2">
+ <item>
+ <property name="text">
+ <string>Dots/inch</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kComboBox1</cstring>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>intHorizontal</cstring>
+ </property>
+ <property name="maxValue">
+ <number>999</number>
+ </property>
+ <property name="value">
+ <number>72</number>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>intVertical</cstring>
+ </property>
+ <property name="maxValue">
+ <number>999</number>
+ </property>
+ <property name="value">
+ <number>72</number>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Horizontal:</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="1" column="2">
+ <item>
+ <property name="text">
+ <string>Dots/inch</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kComboBox2</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="tqsizeHint">
+ <size>
+ <width>31</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Size:</string>
+ </property>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>tqlayout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="tqsizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>tqlayout3</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KIntSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>intHeight</cstring>
+ </property>
+ <property name="maxValue">
+ <number>99999</number>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="0" column="0">
+ <property name="name">
+ <cstring>intWidthzqffs</cstring>
+ </property>
+ <property name="text">
+ <string>Width:</string>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>intWidth</cstring>
+ </property>
+ <property name="maxValue">
+ <number>99999</number>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="1" column="0">
+ <property name="name">
+ <cstring>intHeightqsdfq</cstring>
+ </property>
+ <property name="text">
+ <string>Height:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="tqsizeHint">
+ <size>
+ <width>51</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="TQButtonGroup" row="0" column="0">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>Pages</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQRadioButton">
+ <property name="name">
+ <cstring>boolAllPages</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;All pages</string>
+ </property>
+ </widget>
+ <widget class="TQRadioButton">
+ <property name="name">
+ <cstring>boolFirstPage</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;First page</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="TQRadioButton">
+ <property name="name">
+ <cstring>boolSelectionPage</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Selection of page</string>
+ </property>
+ </widget>
+ <widget class="KListBox">
+ <property name="name">
+ <cstring>listPages</cstring>
+ </property>
+ <property name="selectionMode">
+ <enum>Multi</enum>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<tabstops>
+ <tabstop>boolFirstPage</tabstop>
+ <tabstop>listPages</tabstop>
+ <tabstop>intHorizontal</tabstop>
+ <tabstop>kComboBox1</tabstop>
+ <tabstop>intVertical</tabstop>
+ <tabstop>kComboBox2</tabstop>
+ <tabstop>intWidth</tabstop>
+ <tabstop>intHeight</tabstop>
+</tabstops>
+<tqlayoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kcombobox.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>klistbox.h</includehint>
+</includehints>
+</UI>
diff --git a/filters/chalk/png/Makefile.am b/filters/chalk/png/Makefile.am
new file mode 100644
index 00000000..fbee1638
--- /dev/null
+++ b/filters/chalk/png/Makefile.am
@@ -0,0 +1,44 @@
+kde_module_LTLIBRARIES = libchalkpngimport.la libchalkpngexport.la
+
+libchalkpngexport_la_LDFLAGS = $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalkpngexport_la_LIBADD = \
+ $(KOFFICE_LIBS) \
+ $(top_builddir)/chalk/libchalkcommon.la \
+ -lpng
+
+libchalkpngimport_la_LDFLAGS = $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalkpngimport_la_LIBADD = \
+ $(KOFFICE_LIBS) \
+ $(top_builddir)/chalk/libchalkcommon.la \
+ -lpng
+
+INCLUDES= \
+ -I$(srcdir) \
+ $(KOFFICE_INCLUDES) \
+ -I$(top_srcdir)/chalk \
+ -I$(top_srcdir)/chalk/core \
+ -I$(top_srcdir)/chalk/sdk \
+ -I$(top_srcdir)/chalk/core/tiles \
+ -I$(top_srcdir)/chalk/chalkcolor \
+ -I$(top_srcdir)/chalk/ui \
+ $(KOFFICE_INCLUDES) -I$(interfacedir) \
+ $(KOPAINTER_INCLUDES) \
+ $(all_includes)
+
+service_DATA = chalk_png_import.desktop chalk_png_export.desktop
+servicedir = $(kde_servicesdir)
+
+kdelnk_DATA = chalk_png.desktop
+kdelnkdir = $(kde_appsdir)/.hidden
+
+libchalkpngimport_la_SOURCES = kis_png_import.cc kis_png_converter.cc
+libchalkpngexport_la_SOURCES = kis_wdg_options_png.ui kis_png_export.cc kis_png_converter.cc
+
+METASOURCES = AUTO
+
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
diff --git a/filters/chalk/png/chalk_png.desktop b/filters/chalk/png/chalk_png.desktop
new file mode 100644
index 00000000..3605566b
--- /dev/null
+++ b/filters/chalk/png/chalk_png.desktop
@@ -0,0 +1,57 @@
+[Desktop Entry]
+Name=Chalk
+Name[hi]=के-रिता
+Name[km]= Chalk
+Name[lo]=ກຣິຕາ
+Name[ne]=क्रिता
+Exec=chalk %u
+GenericName=Painting and Image Editing Application
+GenericName[bg]=Редактор на графични изображения
+GenericName[ca]=Programa de dibuix i manipulació d'imatges
+GenericName[cs]=Malování a úpravy obrázků
+GenericName[cy]=Cymhwysiad Peintio Golygu Delweddau
+GenericName[da]=Male- og billedredigeringsprogram
+GenericName[de]=Mal- und Bildbearbeitungsprogramm
+GenericName[el]=Εφαρμογή επεξεργασίας εικόνων
+GenericName[eo]=Aplikaĵo por Pentrado kaj Bildredaktado
+GenericName[es]=Aplicación de pintura y de edición de imágenes
+GenericName[et]=Joonistamise ja pilditöötluse rakendus
+GenericName[eu]=Irudien marrazketa eta ediziorako aplikazioa
+GenericName[fa]=کاربرد ویرایش تصویر و نقاشی
+GenericName[fi]=Maalaus- ja kuvankäsitelyohjelma
+GenericName[fr]=Application de dessin et de manipulation d'images
+GenericName[fy]=Ofbyldingsmanipulaasje
+GenericName[gl]=Aplicación de Pintura e Manipulación de Imaxes
+GenericName[he]=יישום לציור ועריכת תמונות
+GenericName[hr]=Aplikacija za obradu slika i fotografija
+GenericName[hu]=Képszerkesztő
+GenericName[is]=Málun og myndritill
+GenericName[it]=Applicazione di disegno e di modifica delle immagini
+GenericName[ja]=描画と画像編集のためのアプリケーション
+GenericName[km]=កម្មវិធី​គូរ​គំនូរ និង​កែសម្រួល​រូបភាព
+GenericName[lv]=Zīmēšanas un attēlu apstrādes programma
+GenericName[nb]=Program for tegning og bilderedigering
+GenericName[nds]=Programm för't Malen un Bildbewerken
+GenericName[ne]=पेन्टीङ्ग र छवि सम्पादन अनुप्रयोग
+GenericName[nl]=Afbeeldingsmanipulatie
+GenericName[pl]=Program do edycji zdjęć oraz rysunków
+GenericName[pt]=Aplicação de Pintura e Edição de Imagens
+GenericName[pt_BR]=Aplicação de Pintura e Edição de Imagens
+GenericName[ru]=Растровые изображения
+GenericName[se]=Málen- ja govvagieđahallanprográmma
+GenericName[sk]=Program pre tvorbu a úpravu obrázkov
+GenericName[sl]=Program za risanje in obdelavo slik
+GenericName[sr]=Програм за цртање и уређивање слика
+GenericName[sr@Latn]=Program za crtanje i uređivanje slika
+GenericName[sv]=Målnings- och bildredigeringsprogram
+GenericName[uk]=Програма для малювання і редагування зображень
+GenericName[uz]=Rasmlar bilan ishlaydigan dastur
+GenericName[uz@cyrillic]=Расмлар билан ишлайдиган дастур
+GenericName[zh_CN]=绘图和图像编辑应用程序
+GenericName[zh_TW]=繪圖與影像處理程式
+MimeType=image/png
+Type=Application
+Icon=chalk
+Categories=
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Multi
diff --git a/filters/chalk/png/chalk_png_export.desktop b/filters/chalk/png/chalk_png_export.desktop
new file mode 100644
index 00000000..e4f6711b
--- /dev/null
+++ b/filters/chalk/png/chalk_png_export.desktop
@@ -0,0 +1,51 @@
+[Desktop Entry]
+Name=Chalk PNG Export Filter
+Name[bg]=Филтър за експортиране от Chalk в PNG
+Name[br]=Sil ezporzh PNG evit Chalk
+Name[ca]=Filtre d'exportació PNG per a Chalk
+Name[da]=Chalk PNG-eksportfilter
+Name[de]=Chalk PNG-Exportfilter
+Name[el]=Φίλτρο εξαγωγής PNG του Chalk
+Name[eo]=Chalk PNG-eksportfiltrilo
+Name[es]=Filtro de exportación a PNG de Chalk
+Name[et]=Chalk PNG ekspordifilter
+Name[fa]=پالایۀ صادرات Chalk PNG
+Name[fi]=Chalk PNG -viestisuodin
+Name[fr]=Filtre d'exportation PNG de Chalk
+Name[fy]=Chalk PNG Eksportfilter
+Name[ga]=Scagaire Easpórtála PNG Chalk
+Name[gl]=Filtro de Exportación de PNG para Chalk
+Name[he]=Chalk PNG מסנן יצוא
+Name[hr]=Chalk PNG filtar izvoza
+Name[hu]=Chalk PNG exportszűrő
+Name[is]=Chalk PNG útflutningssía
+Name[it]=Filtro di esportazione PNG per Chalk
+Name[ja]=Chalk PNG エクスポートフィルタ
+Name[km]=តម្រង​នាំចេញ PNG សម្រាប់ Chalk
+Name[lt]=Chalk PNG eksportavimo filtras
+Name[lv]=Chalk PNG eksporta filtrs
+Name[nb]=PNG-eksportfilter for Chalk
+Name[nds]=PNG-Exportfilter för Chalk
+Name[ne]=क्रिता पीएनजी निर्यात फिल्टर
+Name[nl]=Chalk PNG Exportfilter
+Name[pl]=Filtr eksportu do formatu PNG dla Chalk
+Name[pt]=Filtro de Exportação de PNG para o Chalk
+Name[pt_BR]=Filtro de Exportação de PNG para o Chalk
+Name[ru]=Фильтр экспорта рисунков Chalk в PNG
+Name[se]=Chalk PNG-olggosfievrridansilli
+Name[sk]=Exportný filter Chalk PNG
+Name[sl]=Izvozni filter PNG za Krito
+Name[sr]=Chalk-ин филтер за извоз у PNG
+Name[sr@Latn]=Chalk-in filter za izvoz u PNG
+Name[sv]=Chalk PNG-exportfilter
+Name[uk]=Фільтр експорту PNG для Chalk
+Name[uz]=Chalk PNG eksport filteri
+Name[uz@cyrillic]=Chalk PNG экспорт филтери
+Name[zh_CN]=Chalk PNG 导出过滤器
+Name[zh_TW]=Chalk PNG 匯出過濾程式
+X-KDE-Export=image/png
+ServiceTypes=KOfficeFilter
+Type=Service
+X-KDE-Import=application/x-chalk
+X-KDE-Weight=1
+X-KDE-Library=libchalkpngexport
diff --git a/filters/chalk/png/chalk_png_import.desktop b/filters/chalk/png/chalk_png_import.desktop
new file mode 100644
index 00000000..94b1c90f
--- /dev/null
+++ b/filters/chalk/png/chalk_png_import.desktop
@@ -0,0 +1,51 @@
+[Desktop Entry]
+Type=Service
+Name=Chalk PNG Import Filter
+Name[bg]=Филтър за импортиране от PNG в Chalk
+Name[br]=Sil enporzh PNG evit Chalk
+Name[ca]=Filtre d'importació PNG per a Chalk
+Name[da]=Chalk PNG-importfilter
+Name[de]=Chalk PNG-Importfilter
+Name[el]=Φίλτρο εισαγωγής PNG του Chalk
+Name[eo]=Chalk PNG-importfiltrilo
+Name[es]=Filtro de importación a PNG de Chalk
+Name[et]=Chalk PNG impordifilter
+Name[fa]=پالایۀ واردات Chalk PNG
+Name[fi]=Chalk PNG -tuontisuodin
+Name[fr]=Filtre d'importation PNG de Chalk
+Name[fy]=Chalk PNG Ymportfilter
+Name[ga]=Scagaire Iompórtála PNG Chalk
+Name[gl]=Filtro de Importación de PNG para Chalk
+Name[he]=Chalk PNG מסנן יבוא
+Name[hr]=Chalk PNG filtar uvoza
+Name[hu]=Chalk PNG importszűrő
+Name[is]=Chalk PNG innflutningssía
+Name[it]=Filtro di importazione PNG per Chalk
+Name[ja]=Chalk PNG インポートフィルタ
+Name[km]=តម្រង​នាំចូល PNG សម្រាប់ Chalk
+Name[lt]=Chalk PNG importavimo filtras
+Name[lv]=Chalk PNG importa filtrs
+Name[nb]=PNG-importfilter for Chalk
+Name[nds]=PNG-Importfilter för Chalk
+Name[ne]=क्रिता पीएनजी आयात फिल्टर
+Name[nl]=Chalk PNG Importfilter
+Name[pl]=Filtr importu z formatu PNG dla Chalk
+Name[pt]=Filtro de Importação de PNG para o Chalk
+Name[pt_BR]=Filtro de Importação de PNG para o Chalk
+Name[ru]=Фильтр импорта рисунков PNG в Chalk
+Name[se]=Chalk PNG-olggosfievrridansilli
+Name[sk]=PNG filter pre import do Chalk
+Name[sl]=Uvozni filter PNG za Krito
+Name[sr]=Chalk-ин филтер за увоз из PNG-а
+Name[sr@Latn]=Chalk-in filter za uvoz iz PNG-a
+Name[sv]=Chalk PNG-importfilter
+Name[uk]=Фільтр імпорту PNG для Chalk
+Name[uz]=Chalk PNG import filteri
+Name[uz@cyrillic]=Chalk PNG импорт филтери
+Name[zh_CN]=Chalk PNG 导入过滤器
+Name[zh_TW]=Chalk PNG 匯入過濾程式
+X-KDE-Export=application/x-chalk
+X-KDE-Import=image/png
+X-KDE-Weight=1
+X-KDE-Library=libchalkpngimport
+ServiceTypes=KOfficeFilter
diff --git a/filters/chalk/png/configure.in.bot b/filters/chalk/png/configure.in.bot
new file mode 100644
index 00000000..cda5270f
--- /dev/null
+++ b/filters/chalk/png/configure.in.bot
@@ -0,0 +1,8 @@
+if test -z "$LIBPNG"; then
+ echo ""
+ echo "You're missing libpng (binaries and/or headers), chalk won't be able"
+ echo "to import/export png"
+ echo ""
+ all_tests=bad
+fi
+
diff --git a/filters/chalk/png/kis_png_converter.cc b/filters/chalk/png/kis_png_converter.cc
new file mode 100644
index 00000000..b7c48b50
--- /dev/null
+++ b/filters/chalk/png/kis_png_converter.cc
@@ -0,0 +1,794 @@
+/*
+ * Copyright (c) 2005-2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+ // A big thank to Glenn Randers-Pehrson for it's wonderfull documentation of libpng available at http://www.libpng.org/pub/png/libpng-1.2.5-manual.html
+#include "kis_png_converter.h"
+
+#include <stdio.h>
+
+#include <tqfile.h>
+
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+
+#include <KoDocumentInfo.h>
+
+#include <kio/netaccess.h>
+
+#include <kis_abstract_colorspace.h>
+#include <kis_colorspace_factory_registry.h>
+#include <kis_doc.h>
+#include <kis_image.h>
+#include <kis_iterators_pixel.h>
+#include <kis_layer.h>
+#include <kis_meta_registry.h>
+#include <kis_profile.h>
+#include <kis_paint_layer.h>
+#include <kis_group_layer.h>
+
+namespace {
+
+ const TQ_UINT8 PIXEL_BLUE = 0;
+ const TQ_UINT8 PIXEL_GREEN = 1;
+ const TQ_UINT8 PIXEL_RED = 2;
+ const TQ_UINT8 PIXEL_ALPHA = 3;
+
+
+ int getColorTypeforColorSpace( KisColorSpace * cs , bool alpha)
+ {
+ if ( cs->id() == KisID("GRAYA") || cs->id() == KisID("GRAYA16") )
+ {
+ return alpha ? PNG_COLOR_TYPE_GRAY_ALPHA : PNG_COLOR_TYPE_GRAY;
+ }
+ if ( cs->id() == KisID("RGBA") || cs->id() == KisID("RGBA16") )
+ {
+ return alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB;
+ }
+
+ KMessageBox::error(0, i18n("Cannot export images in %1.\n").tqarg(cs->id().name()) ) ;
+ return -1;
+
+ }
+
+
+ TQString getColorSpaceForColorType(int color_type,int color_nb_bits) {
+ if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ switch(color_nb_bits)
+ {
+ case 8:
+ return "GRAYA";
+ case 16:
+ return "GRAYA16";
+ }
+ } else if(color_type == PNG_COLOR_TYPE_RGB_ALPHA || color_type == PNG_COLOR_TYPE_RGB) {
+ switch(color_nb_bits)
+ {
+ case 8:
+ return "RGBA";
+ case 16:
+ return "RGBA16";
+ }
+ } else if(color_type == PNG_COLOR_TYPE_PALETTE) {
+ return "RGBA"; // <-- we will convert the index image to RGBA
+ }
+ return "";
+ }
+
+
+ void fillText(png_text* p_text, char* key, TQString& text)
+ {
+ p_text->compression = PNG_TEXT_COMPRESSION_zTXt;
+ p_text->key = key;
+ char* textc = new char[text.length()+1];
+ strcpy(textc, text.ascii());
+ p_text->text = textc;
+ p_text->text_length = text.length()+1;
+ }
+
+}
+
+KisPNGConverter::KisPNGConverter(KisDoc *doc, KisUndoAdapter *adapter)
+{
+ Q_ASSERT(doc);
+ Q_ASSERT(adapter);
+
+ m_doc = doc;
+ m_adapter = adapter;
+ m_stop = false;
+ m_max_row = 0;
+ m_img = 0;
+}
+
+KisPNGConverter::~KisPNGConverter()
+{
+}
+
+class KisPNGStream {
+ public:
+ KisPNGStream(TQ_UINT8* buf, TQ_UINT32 depth ) : m_posinc(8),m_depth(depth), m_buf(buf) { *m_buf = 0;};
+ int nextValue()
+ {
+ if( m_posinc == 0)
+ {
+ m_posinc = 8;
+ m_buf++;
+ }
+ m_posinc -= m_depth;
+ return (( (*m_buf) >> (m_posinc) ) & ( ( 1 << m_depth ) - 1 ) );
+ }
+ void setNextValue(int v)
+ {
+ if( m_posinc == 0)
+ {
+ m_posinc = 8;
+ m_buf++;
+ *m_buf = 0;
+ }
+ m_posinc -= m_depth;
+ *m_buf = (v << m_posinc) | *m_buf;
+ }
+ private:
+ TQ_UINT32 m_posinc, m_depth;
+ TQ_UINT8* m_buf;
+};
+
+KisImageBuilder_Result KisPNGConverter::decode(const KURL& uri)
+{
+ kdDebug(41008) << "Start decoding PNG File" << endl;
+ // open the file
+ kdDebug(41008) << TQFile::encodeName(uri.path()) << " " << uri.path() << " " << uri << endl;
+ FILE *fp = fopen(TQFile::encodeName(uri.path()), "rb");
+ if (!fp)
+ {
+ return (KisImageBuilder_RESULT_NOT_EXIST);
+ }
+ png_byte signature[8];
+ fread(signature, 1, 8, fp);
+ if (!png_check_sig(signature, 8))
+ {
+ return (KisImageBuilder_RESULT_BAD_FETCH);
+ }
+
+ // Initialize the internal structures
+ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL);
+ if (!KisImageBuilder_RESULT_FAILURE)
+ return (KisImageBuilder_RESULT_FAILURE);
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+ return (KisImageBuilder_RESULT_FAILURE);
+ }
+
+ png_infop end_info = png_create_info_struct(png_ptr);
+ if (!end_info)
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+ return (KisImageBuilder_RESULT_FAILURE);
+ }
+
+ // Catch errors
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ fclose(fp);
+ return (KisImageBuilder_RESULT_FAILURE);
+ }
+
+ png_init_io(png_ptr, fp);
+ png_set_sig_bytes(png_ptr, 8);
+
+ // read all PNG info up to image data
+ png_read_info(png_ptr, info_ptr);
+
+ // Read information about the png
+ png_uint_32 width, height;
+ int color_nb_bits, color_type, interlace_type;
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &color_nb_bits, &color_type, &interlace_type, NULL, NULL);
+ kdDebug(41008) << "it's an " << color_nb_bits << " depth image" << endl;
+
+ // swap byteorder on little endian machines.
+ #ifndef WORDS_BIGENDIAN
+ if (color_nb_bits > 8 )
+ png_set_swap(png_ptr);
+ #endif
+
+ // Determine the colorspace
+ TQString csName = getColorSpaceForColorType(color_type, color_nb_bits);
+ if(csName.isEmpty()) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
+ }
+ bool hasalpha = (color_type == PNG_COLOR_TYPE_RGB_ALPHA || color_type == PNG_COLOR_TYPE_GRAY_ALPHA);
+
+ // Read image profile
+ png_charp profile_name, profile_data;
+ int compression_type;
+ png_uint_32 proflen;
+ int number_of_passes = 1;
+
+ if (interlace_type == PNG_INTERLACE_ADAM7)
+ number_of_passes = png_set_interlace_handling(png_ptr);
+
+ KisProfile* profile = 0;
+ if(png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &proflen))
+ {
+ TQByteArray profile_rawdata;
+ // XXX: Hardcoded for icc type -- is that correct for us?
+ if (TQString::compare(profile_name, "icc") == 0) {
+ profile_rawdata.resize(proflen);
+ memcpy(profile_rawdata.data(), profile_data, proflen);
+ profile = new KisProfile(profile_rawdata);
+ Q_CHECK_PTR(profile);
+ if (profile) {
+ kdDebug(41008) << "profile name: " << profile->productName() << " profile description: " << profile->productDescription() << " information sur le produit: " << profile->productInfo() << endl;
+ if(!profile->isSuitableForOutput())
+ {
+ kdDebug(41008) << "the profile is not suitable for output and therefore cannot be used in chalk, we need to convert the image to a standard profile" << endl; // TODO: in ko2 popup a selection menu to inform the user
+ }
+ }
+ }
+ }
+
+ // Retrieve a pointer to the colorspace
+ KisColorSpace* cs;
+ if (profile && profile->isSuitableForOutput())
+ {
+ kdDebug(41008) << "image has embedded profile: " << profile -> productName() << "\n";
+ cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(csName, profile);
+ }
+ else
+ cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName,""),"");
+
+ if(cs == 0)
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
+ }
+
+ // Create the cmsTransform if needed
+ cmsHTRANSFORM transform = 0;
+ if(profile && !profile->isSuitableForOutput())
+ {
+ transform = cmsCreateTransform(profile->profile(), cs->colorSpaceType(),
+ cs->getProfile()->profile() , cs->colorSpaceType(),
+ INTENT_PERCEPTUAL, 0);
+ }
+
+ // Read comments/texts...
+ png_text* text_ptr;
+ int num_comments;
+ png_get_text(png_ptr, info_ptr, &text_ptr, &num_comments);
+ KoDocumentInfo * info = m_doc->documentInfo();
+ KoDocumentInfoAbout * aboutPage = static_cast<KoDocumentInfoAbout *>(info->page( "about" ));
+ KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor *>(info->page( "author"));
+ kdDebug(41008) << "There are " << num_comments << " comments in the text" << endl;
+ for(int i = 0; i < num_comments; i++)
+ {
+ kdDebug(41008) << "key is " << text_ptr[i].key << " containing " << text_ptr[i].text << endl;
+ if(TQString::compare(text_ptr[i].key, "title") == 0)
+ {
+ aboutPage->setTitle(text_ptr[i].text);
+ } else if(TQString::compare(text_ptr[i].key, "abstract") == 0)
+ {
+ aboutPage->setAbstract(text_ptr[i].text);
+ } else if(TQString::compare(text_ptr[i].key, "author") == 0)
+ {
+ authorPage->setFullName(text_ptr[i].text);
+ }
+ }
+
+ // Read image data
+ png_bytep row_pointer = 0;
+ try
+ {
+ png_uint_32 rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+ row_pointer = new png_byte[rowbytes];
+ }
+ catch(std::bad_alloc& e)
+ {
+ // new png_byte[] may raise such an exception if the image
+ // is invalid / to large.
+ kdDebug(41008) << "bad alloc: " << e.what() << endl;
+ // Free only the already allocated png_byte instances.
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ return (KisImageBuilder_RESULT_FAILURE);
+ }
+
+ // Read the palette if the file is indexed
+ png_colorp palette ;
+ int num_palette;
+ if(color_type == PNG_COLOR_TYPE_PALETTE) {
+ png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
+ }
+// png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL );
+// png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr); // By using this function libpng will take care of freeing memory
+// png_read_image(png_ptr, row_pointers);
+
+ // Finish reading the file
+// png_read_end(png_ptr, end_info);
+// fclose(fp);
+
+ // Creating the KisImageSP
+ if( ! m_img) {
+ m_img = new KisImage(m_doc->undoAdapter(), width, height, cs, "built image");
+ m_img->blockSignals(true); // Don't send out signals while we're building the image
+ Q_CHECK_PTR(m_img);
+ if(profile && !profile->isSuitableForOutput())
+ {
+ m_img -> addAnnotation( profile->annotation() );
+ }
+ }
+
+ KisPaintLayer* layer = new KisPaintLayer(m_img, m_img -> nextLayerName(), TQ_UINT8_MAX);
+ for (int i = 0; i < number_of_passes; i++)
+ {
+ for (png_uint_32 y = 0; y < height; y++) {
+ KisHLineIterator it = layer -> paintDevice() -> createHLineIterator(0, y, width, true);
+ png_read_rows(png_ptr, &row_pointer, NULL, 1);
+
+ switch(color_type)
+ {
+ case PNG_COLOR_TYPE_GRAY:
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ if(color_nb_bits == 16)
+ {
+ TQ_UINT16 *src = reinterpret_cast<TQ_UINT16 *>(row_pointer);
+ while (!it.isDone()) {
+ TQ_UINT16 *d = reinterpret_cast<TQ_UINT16 *>(it.rawData());
+ d[0] = *(src++);
+ if(transform) cmsDoTransform(transform, d, d, 1);
+ if(hasalpha) d[1] = *(src++);
+ else d[1] = TQ_UINT16_MAX;
+ ++it;
+ }
+ } else {
+ TQ_UINT8 *src = row_pointer;
+ while (!it.isDone()) {
+ TQ_UINT8 *d = it.rawData();
+ d[0] = *(src++);
+ if(transform) cmsDoTransform(transform, d, d, 1);
+ if(hasalpha) d[1] = *(src++);
+ else d[1] = TQ_UINT8_MAX;
+ ++it;
+ }
+ }
+ //FIXME:should be able to read 1 and 4 bits depth and scale them to 8 bits
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ if(color_nb_bits == 16)
+ {
+ TQ_UINT16 *src = reinterpret_cast<TQ_UINT16 *>(row_pointer);
+ while (!it.isDone()) {
+ TQ_UINT16 *d = reinterpret_cast<TQ_UINT16 *>(it.rawData());
+ d[2] = *(src++);
+ d[1] = *(src++);
+ d[0] = *(src++);
+ if(transform) cmsDoTransform(transform, d, d, 1);
+ if(hasalpha) d[3] = *(src++);
+ else d[3] = TQ_UINT16_MAX;
+ ++it;
+ }
+ } else {
+ TQ_UINT8 *src = row_pointer;
+ while (!it.isDone()) {
+ TQ_UINT8 *d = it.rawData();
+ d[2] = *(src++);
+ d[1] = *(src++);
+ d[0] = *(src++);
+ if(transform) cmsDoTransform(transform, d, d, 1);
+ if(hasalpha) d[3] = *(src++);
+ else d[3] = TQ_UINT8_MAX;
+ ++it;
+ }
+ }
+ break;
+ case PNG_COLOR_TYPE_PALETTE:
+ {
+ KisPNGStream stream(row_pointer, color_nb_bits);
+ while (!it.isDone()) {
+ TQ_UINT8 *d = it.rawData();
+ png_color c = palette[ stream.nextValue() ];
+ d[2] = c.red;
+ d[1] = c.green;
+ d[0] = c.blue;
+ d[3] = TQ_UINT8_MAX;
+ ++it;
+ }
+ }
+ break;
+ default:
+ return KisImageBuilder_RESULT_UNSUPPORTED;
+ }
+ }
+ }
+ m_img->addLayer(layer, m_img->rootLayer(), 0);
+
+ png_read_end(png_ptr, end_info);
+ fclose(fp);
+
+ // Freeing memory
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+
+ delete [] row_pointer;
+
+ return KisImageBuilder_RESULT_OK;
+
+}
+
+KisImageBuilder_Result KisPNGConverter::buildImage(const KURL& uri)
+{
+ kdDebug(41008) << TQFile::encodeName(uri.path()) << " " << uri.path() << " " << uri << endl;
+ if (uri.isEmpty())
+ return KisImageBuilder_RESULT_NO_URI;
+
+ if (!KIO::NetAccess::exists(uri, false, tqApp -> mainWidget())) {
+ return KisImageBuilder_RESULT_NOT_EXIST;
+ }
+
+ // We're not set up to handle asynchronous loading at the moment.
+ KisImageBuilder_Result result = KisImageBuilder_RESULT_FAILURE;
+ TQString tmpFile;
+
+ if (KIO::NetAccess::download(uri, tmpFile, tqApp -> mainWidget())) {
+ KURL uriTF;
+ uriTF.setPath( tmpFile );
+ result = decode(uriTF);
+ KIO::NetAccess::removeTempFile(tmpFile);
+ }
+
+ return result;
+}
+
+
+KisImageSP KisPNGConverter::image()
+{
+ return m_img;
+}
+
+KisImageBuilder_Result KisPNGConverter::buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, int compression, bool interlace, bool alpha)
+{
+ kdDebug(41008) << "Start writing PNG File" << endl;
+ if (!layer)
+ return KisImageBuilder_RESULT_INVALID_ARG;
+
+ KisImageSP img = layer -> image();
+ if (!img)
+ return KisImageBuilder_RESULT_EMPTY;
+
+ if (uri.isEmpty())
+ return KisImageBuilder_RESULT_NO_URI;
+
+ if (!uri.isLocalFile())
+ return KisImageBuilder_RESULT_NOT_LOCAL;
+ // Open file for writing
+ FILE *fp = fopen(TQFile::encodeName(uri.path()), "wb");
+ if (!fp)
+ {
+ return (KisImageBuilder_RESULT_FAILURE);
+ }
+ int height = img->height();
+ int width = img->width();
+ // Initialize structures
+ png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL);
+ if (!png_ptr)
+ {
+ KIO::del(uri);
+ return (KisImageBuilder_RESULT_FAILURE);
+ }
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ KIO::del(uri);
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+ return (KisImageBuilder_RESULT_FAILURE);
+ }
+
+ // If an error occurs during writing, libpng will jump here
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ KIO::del(uri);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ fclose(fp);
+ return (KisImageBuilder_RESULT_FAILURE);
+ }
+ // Initialize the writing
+ png_init_io(png_ptr, fp);
+ // Setup the progress function
+// FIXME png_set_write_status_fn(png_ptr, progress);
+// setProgressTotalSteps(100/*height*/);
+
+
+ /* set the zlib compression level */
+ png_set_compression_level(png_ptr, compression);
+
+ /* set other zlib parameters */
+ png_set_compression_mem_level(png_ptr, 8);
+ png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
+ png_set_compression_window_bits(png_ptr, 15);
+ png_set_compression_method(png_ptr, 8);
+ png_set_compression_buffer_size(png_ptr, 8192);
+
+ int color_nb_bits = 8 * layer->paintDevice()->pixelSize() / layer->paintDevice()->nChannels();
+ int color_type = getColorTypeforColorSpace(layer->paintDevice()->colorSpace(), alpha);
+
+ if(color_type == -1)
+ {
+ return KisImageBuilder_RESULT_UNSUPPORTED;
+ }
+
+ // Try to compute a table of color if the colorspace is RGB8f
+ png_colorp palette ;
+ int num_palette = 0;
+ if(!alpha && layer->paintDevice()->colorSpace()->id() == KisID("RGBA") )
+ { // png doesn't handle indexed images and alpha, and only have indexed for RGB8
+ palette = new png_color[255];
+ KisRectIteratorPixel it = layer->paintDevice()->createRectIterator(0,0, img->width(), img->height(), false);
+ bool toomuchcolor = false;
+ while( !it.isDone() )
+ {
+ const TQ_UINT8* c = it.rawData();
+ bool findit = false;
+ for(int i = 0; i < num_palette; i++)
+ {
+ if(palette[i].red == c[2] &&
+ palette[i].green == c[1] &&
+ palette[i].blue == c[0] )
+ {
+ findit = true;
+ break;
+ }
+ }
+ if(!findit)
+ {
+ if( num_palette == 255)
+ {
+ toomuchcolor = true;
+ break;
+ }
+ palette[num_palette].red = c[2];
+ palette[num_palette].green = c[1];
+ palette[num_palette].blue = c[0];
+ num_palette++;
+ }
+ ++it;
+ }
+ if(!toomuchcolor)
+ {
+ kdDebug(41008) << "Found a palette of " << num_palette << " colors" << endl;
+ color_type = PNG_COLOR_TYPE_PALETTE;
+ if( num_palette <= 2)
+ {
+ color_nb_bits = 1;
+ } else if( num_palette <= 4)
+ {
+ color_nb_bits = 2;
+ } else if( num_palette <= 16)
+ {
+ color_nb_bits = 4;
+ } else {
+ color_nb_bits = 8;
+ }
+ } else {
+ delete palette;
+ }
+ }
+
+ int interlacetype = interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
+
+ png_set_IHDR(png_ptr, info_ptr,
+ width,
+ height,
+ color_nb_bits,
+ color_type, interlacetype,
+ PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+ png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE);
+ // set the palette
+ if( color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_set_PLTE(png_ptr, info_ptr, palette, num_palette);
+ }
+ // Save annotation
+ vKisAnnotationSP_it it = annotationsStart;
+ while(it != annotationsEnd) {
+ if (!(*it) || (*it) -> type() == TQString()) {
+ kdDebug(41008) << "Warning: empty annotation" << endl;
+ ++it;
+ continue;
+ }
+
+ kdDebug(41008) << "Trying to store annotation of type " << (*it) -> type() << " of size " << (*it) -> annotation() . size() << endl;
+
+ if ((*it) -> type().startsWith("chalk_attribute:")) { // Attribute
+ // FIXME: it should be possible to save chalk_attributes in the "CHUNKs"
+ kdDebug(41008) << "can't save this annotation : " << (*it) -> type() << endl;
+ } else { // Profile
+ char* name = new char[(*it)->type().length()+1];
+ strcpy(name, (*it)->type().ascii());
+ png_set_iCCP(png_ptr, info_ptr, name, PNG_COMPRESSION_TYPE_BASE, (char*)(*it)->annotation().data(), (*it) -> annotation() . size());
+ }
+ ++it;
+ }
+
+ // read comments from the document information
+ png_text texts[3];
+ int nbtexts = 0;
+ KoDocumentInfo * info = m_doc->documentInfo();
+ KoDocumentInfoAbout * aboutPage = static_cast<KoDocumentInfoAbout *>(info->page( "about" ));
+ TQString title = aboutPage->title();
+ if(!title.isEmpty())
+ {
+ fillText(texts+nbtexts, "title", title);
+ nbtexts++;
+ }
+ TQString abstract = aboutPage->abstract();
+ if(!abstract.isEmpty())
+ {
+ fillText(texts+nbtexts, "abstract", abstract);
+ nbtexts++;
+ }
+ KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor *>(info->page( "author" ));
+ TQString author = authorPage->fullName();
+ if(!author.isEmpty())
+ {
+ fillText(texts+nbtexts, "author", author);
+ nbtexts++;
+ }
+
+ png_set_text(png_ptr, info_ptr, texts, nbtexts);
+
+ // Save the information to the file
+ png_write_info(png_ptr, info_ptr);
+ png_write_flush(png_ptr);
+
+ // swap byteorder on little endian machines.
+ #ifndef WORDS_BIGENDIAN
+ if (color_nb_bits > 8 )
+ png_set_swap(png_ptr);
+ #endif
+
+ // Write the PNG
+// png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
+
+ // Fill the data structure
+ png_byte** row_pointers= new png_byte*[height];
+
+ for (int y = 0; y < height; y++) {
+ KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, y, width, false);
+ row_pointers[y] = new png_byte[width*layer->paintDevice()->pixelSize()];
+ switch(color_type)
+ {
+ case PNG_COLOR_TYPE_GRAY:
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ if(color_nb_bits == 16)
+ {
+ TQ_UINT16 *dst = reinterpret_cast<TQ_UINT16 *>(row_pointers[y]);
+ while (!it.isDone()) {
+ const TQ_UINT16 *d = reinterpret_cast<const TQ_UINT16 *>(it.rawData());
+ *(dst++) = d[0];
+ if(alpha) *(dst++) = d[1];
+ ++it;
+ }
+ } else {
+ TQ_UINT8 *dst = row_pointers[y];
+ while (!it.isDone()) {
+ const TQ_UINT8 *d = it.rawData();
+ *(dst++) = d[0];
+ if(alpha) *(dst++) = d[1];
+ ++it;
+ }
+ }
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ if(color_nb_bits == 16)
+ {
+ TQ_UINT16 *dst = reinterpret_cast<TQ_UINT16 *>(row_pointers[y]);
+ while (!it.isDone()) {
+ const TQ_UINT16 *d = reinterpret_cast<const TQ_UINT16 *>(it.rawData());
+ *(dst++) = d[2];
+ *(dst++) = d[1];
+ *(dst++) = d[0];
+ if(alpha) *(dst++) = d[3];
+ ++it;
+ }
+ } else {
+ TQ_UINT8 *dst = row_pointers[y];
+ while (!it.isDone()) {
+ const TQ_UINT8 *d = it.rawData();
+ *(dst++) = d[2];
+ *(dst++) = d[1];
+ *(dst++) = d[0];
+ if(alpha) *(dst++) = d[3];
+ ++it;
+ }
+ }
+ break;
+ case PNG_COLOR_TYPE_PALETTE:
+ {
+ TQ_UINT8 *dst = row_pointers[y];
+ KisPNGStream writestream(dst, color_nb_bits);
+ while (!it.isDone()) {
+ const TQ_UINT8 *d = it.rawData();
+ int i;
+ for(i = 0; i < num_palette; i++)
+ {
+ if(palette[i].red == d[2] &&
+ palette[i].green == d[1] &&
+ palette[i].blue == d[0] )
+ {
+ break;
+ }
+ }
+ writestream.setNextValue(i);
+ ++it;
+ }
+ }
+ break;
+ default:
+ kdDebug(41008) << "Unsupported color type for writting : " << color_type << endl;
+ KIO::del(uri);
+ return KisImageBuilder_RESULT_UNSUPPORTED;
+ }
+ }
+
+ png_write_image(png_ptr, row_pointers);
+
+
+ // Writting is over
+ png_write_end(png_ptr, info_ptr);
+
+ // Free memory
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ for (int y = 0; y < height; y++) {
+ delete[] row_pointers[y];
+ }
+ delete[] row_pointers;
+
+ if( color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ delete palette;
+ }
+
+ fclose(fp);
+
+ return KisImageBuilder_RESULT_OK;
+}
+
+
+void KisPNGConverter::cancel()
+{
+ m_stop = true;
+}
+
+void KisPNGConverter::progress(png_structp png_ptr, png_uint_32 row_number, int pass)
+{
+ if(png_ptr == NULL || row_number > PNG_MAX_UINT || pass > 7) return;
+// setProgress(row_number);
+}
+
+
+#include "kis_png_converter.moc"
+
diff --git a/filters/chalk/png/kis_png_converter.h b/filters/chalk/png/kis_png_converter.h
new file mode 100644
index 00000000..a4f1140b
--- /dev/null
+++ b/filters/chalk/png/kis_png_converter.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _KIS_PNG_CONVERTER_H_
+#define _KIS_PNG_CONVERTER_H_
+
+#include <png.h>
+
+#include <tqvaluevector.h>
+
+#include <kio/job.h>
+
+#include <kis_progress_subject.h>
+
+#include "kis_types.h"
+#include "kis_global.h"
+#include "kis_annotation.h"
+class KisDoc;
+class KisUndoAdapter;
+
+/**
+ * Image import/export plugins can use these results to report about success or failure.
+ */
+enum KisImageBuilder_Result {
+ KisImageBuilder_RESULT_FAILURE = -400,
+ KisImageBuilder_RESULT_NOT_EXIST = -300,
+ KisImageBuilder_RESULT_NOT_LOCAL = -200,
+ KisImageBuilder_RESULT_BAD_FETCH = -100,
+ KisImageBuilder_RESULT_INVALID_ARG = -50,
+ KisImageBuilder_RESULT_OK = 0,
+ KisImageBuilder_RESULT_PROGRESS = 1,
+ KisImageBuilder_RESULT_EMPTY = 100,
+ KisImageBuilder_RESULT_BUSY = 150,
+ KisImageBuilder_RESULT_NO_URI = 200,
+ KisImageBuilder_RESULT_UNSUPPORTED = 300,
+ KisImageBuilder_RESULT_INTR = 400,
+ KisImageBuilder_RESULT_PATH = 500,
+ KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE = 600
+};
+
+class KisPNGConverter : public KisProgressSubject {
+ Q_OBJECT
+ TQ_OBJECT
+ public:
+ KisPNGConverter(KisDoc *doc, KisUndoAdapter *adapter);
+ virtual ~KisPNGConverter();
+ public:
+ KisImageBuilder_Result buildImage(const KURL& uri);
+ KisImageBuilder_Result buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, int compression, bool interlace, bool alpha);
+ /** Retrieve the constructed image
+ */
+ KisImageSP image();
+ public slots:
+ virtual void cancel();
+ private:
+ KisImageBuilder_Result decode(const KURL& uri);
+ void progress(png_structp png_ptr, png_uint_32 row_number, int pass);
+ private:
+ png_uint_32 m_max_row;
+ KisImageSP m_img;
+ KisDoc *m_doc;
+ KisUndoAdapter *m_adapter;
+ bool m_stop;
+};
+
+#endif
diff --git a/filters/chalk/png/kis_png_export.cc b/filters/chalk/png/kis_png_export.cc
new file mode 100644
index 00000000..8154866a
--- /dev/null
+++ b/filters/chalk/png/kis_png_export.cc
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2005-2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_png_export.h"
+
+#include <tqcheckbox.h>
+#include <tqslider.h>
+
+#include <kapplication.h>
+#include <kdialogbase.h>
+#include <kgenericfactory.h>
+
+#include <KoFilterChain.h>
+
+#include <kis_colorspace.h>
+#include <kis_doc.h>
+#include <kis_image.h>
+#include <kis_iterators_pixel.h>
+#include <kis_paint_layer.h>
+#include <kis_progress_display_interface.h>
+
+#include "kis_png_converter.h"
+#include "kis_wdg_options_png.h"
+
+typedef KGenericFactory<KisPNGExport, KoFilter> KisPNGExportFactory;
+K_EXPORT_COMPONENT_FACTORY(libchalkpngexport, KisPNGExportFactory("kofficefilters"))
+
+KisPNGExport::KisPNGExport(KoFilter *, const char *, const TQStringList&) : KoFilter()
+{
+}
+
+KisPNGExport::~KisPNGExport()
+{
+}
+
+KoFilter::ConversiontqStatus KisPNGExport::convert(const TQCString& from, const TQCString& to)
+{
+ kdDebug(41008) << "Png export! From: " << from << ", To: " << to << "\n";
+
+ KisDoc *output = dynamic_cast<KisDoc*>(m_chain->inputDocument());
+ TQString filename = m_chain->outputFile();
+
+ if (!output)
+ return KoFilter::CreationError;
+
+
+ if (filename.isEmpty()) return KoFilter::FileNotFound;
+
+ if (from != "application/x-chalk")
+ return KoFilter::NotImplemented;
+
+
+ KDialogBase* kdb = new KDialogBase(0, "", false, i18n("PNG Export Options"), KDialogBase::Ok | KDialogBase::Cancel);
+
+ KisImageSP img = output->currentImage();
+ KisPaintDeviceSP pd = new KisPaintDevice(*img->projection());
+ KisPaintLayerSP l = new KisPaintLayer(img, "projection", OPACITY_OPAQUE, pd);
+
+ KisRectIteratorPixel it = l->paintDevice()->createRectIterator(0,0, img->width(), img->height(), false);
+ KisColorSpace* cs = l->paintDevice()->colorSpace();
+ bool isThereAlpha = false;
+ while( !it.isDone() )
+ {
+ if(cs->getAlpha( it.rawData() ) != 255)
+ {
+ isThereAlpha = true;
+ break;
+ }
+ ++it;
+ }
+
+ KisWdgOptionsPNG* wdg = new KisWdgOptionsPNG(kdb);
+ wdg->alpha->setChecked(isThereAlpha);
+ wdg->alpha->setEnabled(isThereAlpha);
+ kdb->setMainWidget(wdg);
+ kapp->restoreOverrideCursor();
+ if(kdb->exec() == TQDialog::Rejected)
+ {
+ return KoFilter::OK; // FIXME Cancel doesn't exist :(
+ }
+
+ bool alpha = wdg->alpha->isChecked();
+ bool interlace = wdg->interlacing->isChecked();
+ int compression = wdg->compressionLevel->value();
+
+ delete kdb;
+
+
+ KURL url;
+ url.setPath(filename);
+
+ KisPNGConverter kpc(output, output->undoAdapter());
+
+ vKisAnnotationSP_it beginIt = img->beginAnnotations();
+ vKisAnnotationSP_it endIt = img->endAnnotations();
+ KisImageBuilder_Result res;
+
+
+ if ( (res = kpc.buildFile(url, l, beginIt, endIt, compression, interlace, alpha)) == KisImageBuilder_RESULT_OK) {
+ kdDebug(41008) << "success !" << endl;
+ return KoFilter::OK;
+ }
+ kdDebug(41008) << " Result = " << res << endl;
+ return KoFilter::InternalError;
+}
+
+#include <kis_png_export.moc>
+
diff --git a/filters/chalk/png/kis_png_export.h b/filters/chalk/png/kis_png_export.h
new file mode 100644
index 00000000..d962523d
--- /dev/null
+++ b/filters/chalk/png/kis_png_export.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _KIS_PNG_EXPORT_H_
+#define _KIS_PNG_EXPORT_H_
+
+#include <KoFilter.h>
+
+class KisPNGExport : public KoFilter {
+ Q_OBJECT
+ TQ_OBJECT
+ public:
+ KisPNGExport(KoFilter *tqparent, const char *name, const TQStringList&);
+ virtual ~KisPNGExport();
+ public:
+ virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to);
+};
+
+#endif
diff --git a/filters/chalk/png/kis_png_import.cc b/filters/chalk/png/kis_png_import.cc
new file mode 100644
index 00000000..ccfe4388
--- /dev/null
+++ b/filters/chalk/png/kis_png_import.cc
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_png_import.h"
+
+#include <kgenericfactory.h>
+
+#include <KoFilterChain.h>
+
+#include <kis_doc.h>
+#include <kis_image.h>
+#include <kis_progress_display_interface.h>
+#include <kis_view.h>
+
+#include "kis_png_converter.h"
+
+typedef KGenericFactory<KisPNGImport, KoFilter> PNGImportFactory;
+K_EXPORT_COMPONENT_FACTORY(libchalkpngimport, PNGImportFactory("kofficefilters"))
+
+KisPNGImport::KisPNGImport(KoFilter *, const char *, const TQStringList&) : KoFilter()
+{
+}
+
+KisPNGImport::~KisPNGImport()
+{
+}
+
+KoFilter::ConversiontqStatus KisPNGImport::convert(const TQCString&, const TQCString& to)
+{
+ kdDebug(41008) << "Importing using PNGImport!\n";
+
+ if (to != "application/x-chalk")
+ return KoFilter::BadMimeType;
+
+ KisDoc * doc = dynamic_cast<KisDoc*>(m_chain -> outputDocument());
+ KisView * view = static_cast<KisView*>(doc -> views().getFirst());
+
+ TQString filename = m_chain -> inputFile();
+
+ if (!doc)
+ return KoFilter::CreationError;
+
+ doc -> prepareForImport();
+
+
+ if (!filename.isEmpty()) {
+
+ KURL url;
+ url.setPath(filename);
+
+ if (url.isEmpty())
+ return KoFilter::FileNotFound;
+
+ KisPNGConverter ib(doc, doc -> undoAdapter());
+
+ if (view != 0)
+ view -> canvasSubject() -> progressDisplay() -> setSubject(&ib, false, true);
+
+ switch (ib.buildImage(url)) {
+ case KisImageBuilder_RESULT_UNSUPPORTED:
+ return KoFilter::NotImplemented;
+ break;
+ case KisImageBuilder_RESULT_INVALID_ARG:
+ return KoFilter::BadMimeType;
+ break;
+ case KisImageBuilder_RESULT_NO_URI:
+ case KisImageBuilder_RESULT_NOT_LOCAL:
+ return KoFilter::FileNotFound;
+ break;
+ case KisImageBuilder_RESULT_BAD_FETCH:
+ case KisImageBuilder_RESULT_EMPTY:
+ return KoFilter::ParsingError;
+ break;
+ case KisImageBuilder_RESULT_FAILURE:
+ return KoFilter::InternalError;
+ break;
+ case KisImageBuilder_RESULT_OK:
+ doc -> setCurrentImage( ib.image());
+ return KoFilter::OK;
+ default:
+ break;
+ }
+
+ }
+ return KoFilter::StorageCreationError;
+}
+
+#include <kis_png_import.moc>
+
diff --git a/filters/chalk/png/kis_png_import.h b/filters/chalk/png/kis_png_import.h
new file mode 100644
index 00000000..d0b8502a
--- /dev/null
+++ b/filters/chalk/png/kis_png_import.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef _KIS_PNG_IMPORT_H_
+#define _KIS_PNG_IMPORT_H_
+
+#include <KoFilter.h>
+
+class KisPNGImport : public KoFilter {
+ Q_OBJECT
+ TQ_OBJECT
+ public:
+ KisPNGImport(KoFilter *tqparent, const char *name, const TQStringList&);
+ virtual ~KisPNGImport();
+ public:
+ virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to);
+};
+
+#endif
diff --git a/filters/chalk/png/kis_wdg_options_png.ui b/filters/chalk/png/kis_wdg_options_png.ui
new file mode 100644
index 00000000..405db2fe
--- /dev/null
+++ b/filters/chalk/png/kis_wdg_options_png.ui
@@ -0,0 +1,183 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KisWdgOptionsPNG</class>
+<widget class="TQWidget">
+ <property name="name">
+ <cstring>KisWdgOptionsPNG</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>286</width>
+ <height>106</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Options of Your PNG</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="TQLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tqlayout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Compress:</string>
+ </property>
+ <property name="tqalignment">
+ <set>AlignTop</set>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Note: the compression level does not change the quality of the result</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Adjust the compression time. Better compression takes longer.
+&lt;br&gt;Note: the compression level does not change the quality of the result.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>tqlayout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQSlider">
+ <property name="name">
+ <cstring>compressionLevel</cstring>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="maxValue">
+ <number>9</number>
+ </property>
+ <property name="pageStep">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>9</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="tickmarks">
+ <enum>Below</enum>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Note: the compression level doesn't change the quality of the result</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Adjust the compression time. Better compression takes longer.
+&lt;br&gt;Note: the compression level doesn't change the quality of the result.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>tqlayout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Fast</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Adjust the compression time. Better compression takes longer.
+&lt;br&gt;Note: the compression level doesn't change the quality of the result.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Small</string>
+ </property>
+ <property name="tqalignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Adjust the compression time. Better compression takes longer.
+&lt;br&gt;Note: the compression level doesn't change the quality of the result.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer row="3" column="0">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="tqsizeHint">
+ <size>
+ <width>20</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>interlacing</cstring>
+ </property>
+ <property name="text">
+ <string>Interlacing</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Use interlacing when publishing on the Internet</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Interlacing is useful if you intend to publish your image on the Internet.&lt;br&gt;
+Enabling interlacing will cause the image to be displayed by the browser even while downloading.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="TQCheckBox" row="2" column="0">
+ <property name="name">
+ <cstring>alpha</cstring>
+ </property>
+ <property name="text">
+ <string>Store alpha channel (transparency)</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Disable to get smaller files if your image has no transparency</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;The Portable Network Graphics (PNG) file format allows transparency in your image to be stored by saving an alpha channel.
+You can uncheck the box if you are not using transparency and you want to make the resulting file smaller .&lt;br&gt;Always saving the alpha channel is recommended.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<tqlayoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/filters/chalk/raw/Makefile.am b/filters/chalk/raw/Makefile.am
new file mode 100644
index 00000000..2a814a56
--- /dev/null
+++ b/filters/chalk/raw/Makefile.am
@@ -0,0 +1,35 @@
+AM_CPPFLAGS= \
+ -I$(srcdir) \
+ -I$(top_srcdir)/chalk \
+ -I$(top_srcdir)/chalk/core \
+ -I$(top_srcdir)/chalk/sdk \
+ -I$(top_srcdir)/chalk/chalkcolor \
+ -I$(top_srcdir)/chalk/ui \
+ -I$(top_srcdir)/filters/chalk/magick \
+ $(KOFFICE_INCLUDES) \
+ $(all_includes)
+
+kde_module_LTLIBRARIES = libchalk_raw_import.la
+
+libchalk_raw_import_la_LDFLAGS = $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalk_raw_import_la_LIBADD = \
+ $(KOFFICE_LIBS) \
+ $(raw_LIBS) \
+ $(top_builddir)/chalk/libchalkcommon.la
+
+
+service_DATA = chalk_raw_import.desktop
+servicedir = $(kde_servicesdir)
+
+kdelnk_DATA = chalk_raw.desktop
+kdelnkdir = $(kde_appsdir)/.hidden
+
+libchalk_raw_import_la_SOURCES = kis_raw_import.cpp wdgrawimport.ui
+
+METASOURCES = AUTO
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+
+
diff --git a/filters/chalk/raw/chalk_raw.desktop b/filters/chalk/raw/chalk_raw.desktop
new file mode 100644
index 00000000..d03d0b6f
--- /dev/null
+++ b/filters/chalk/raw/chalk_raw.desktop
@@ -0,0 +1,57 @@
+[Desktop Entry]
+Name=Chalk
+Name[hi]=के-रिता
+Name[km]= Chalk
+Name[lo]=ກຣິຕາ
+Name[ne]=क्रिता
+Exec=chalk %u
+GenericName=Painting and Image Editing Application
+GenericName[bg]=Редактор на графични изображения
+GenericName[ca]=Programa de dibuix i manipulació d'imatges
+GenericName[cs]=Malování a úpravy obrázků
+GenericName[cy]=Cymhwysiad Peintio Golygu Delweddau
+GenericName[da]=Male- og billedredigeringsprogram
+GenericName[de]=Mal- und Bildbearbeitungsprogramm
+GenericName[el]=Εφαρμογή επεξεργασίας εικόνων
+GenericName[eo]=Aplikaĵo por Pentrado kaj Bildredaktado
+GenericName[es]=Aplicación de pintura y de edición de imágenes
+GenericName[et]=Joonistamise ja pilditöötluse rakendus
+GenericName[eu]=Irudien marrazketa eta ediziorako aplikazioa
+GenericName[fa]=کاربرد ویرایش تصویر و نقاشی
+GenericName[fi]=Maalaus- ja kuvankäsitelyohjelma
+GenericName[fr]=Application de dessin et de manipulation d'images
+GenericName[fy]=Ofbyldingsmanipulaasje
+GenericName[gl]=Aplicación de Pintura e Manipulación de Imaxes
+GenericName[he]=יישום לציור ועריכת תמונות
+GenericName[hr]=Aplikacija za obradu slika i fotografija
+GenericName[hu]=Képszerkesztő
+GenericName[is]=Málun og myndritill
+GenericName[it]=Applicazione di disegno e di modifica delle immagini
+GenericName[ja]=描画と画像編集のためのアプリケーション
+GenericName[km]=កម្មវិធី​គូរ​គំនូរ និង​កែសម្រួល​រូបភាព
+GenericName[lv]=Zīmēšanas un attēlu apstrādes programma
+GenericName[nb]=Program for tegning og bilderedigering
+GenericName[nds]=Programm för't Malen un Bildbewerken
+GenericName[ne]=पेन्टीङ्ग र छवि सम्पादन अनुप्रयोग
+GenericName[nl]=Afbeeldingsmanipulatie
+GenericName[pl]=Program do edycji zdjęć oraz rysunków
+GenericName[pt]=Aplicação de Pintura e Edição de Imagens
+GenericName[pt_BR]=Aplicação de Pintura e Edição de Imagens
+GenericName[ru]=Растровые изображения
+GenericName[se]=Málen- ja govvagieđahallanprográmma
+GenericName[sk]=Program pre tvorbu a úpravu obrázkov
+GenericName[sl]=Program za risanje in obdelavo slik
+GenericName[sr]=Програм за цртање и уређивање слика
+GenericName[sr@Latn]=Program za crtanje i uređivanje slika
+GenericName[sv]=Målnings- och bildredigeringsprogram
+GenericName[uk]=Програма для малювання і редагування зображень
+GenericName[uz]=Rasmlar bilan ishlaydigan dastur
+GenericName[uz@cyrillic]=Расмлар билан ишлайдиган дастур
+GenericName[zh_CN]=绘图和图像编辑应用程序
+GenericName[zh_TW]=繪圖與影像處理程式
+MimeType=image/x-raw
+Type=Application
+Icon=chalk
+Categories=
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Multi
diff --git a/filters/chalk/raw/chalk_raw_import.desktop b/filters/chalk/raw/chalk_raw_import.desktop
new file mode 100644
index 00000000..9c3a039d
--- /dev/null
+++ b/filters/chalk/raw/chalk_raw_import.desktop
@@ -0,0 +1,51 @@
+[Desktop Entry]
+Type=Service
+Name=Chalk RAW Import Filter
+Name[bg]=Филтър за импортиране на RAW в Chalk
+Name[br]=Sil enporzh RAW evit Chalk
+Name[ca]=Filtre d'importació RAW per a Chalk
+Name[da]=Chalk RAW-importfilter
+Name[de]=Chalk RAW-Importfilter
+Name[el]=Φίλτρο εισαγωγής RAW του Chalk
+Name[eo]=Chalk RAW-importfiltrilo
+Name[es]=Filtro de importación a RAW de Chalk
+Name[et]=Chalk toorpiltide impordifilter
+Name[fa]=پالایۀ واردات Chalk RAW
+Name[fi]=Chalk RAW -tuontisuodin
+Name[fr]=Filtre d'importation RAW de Chalk
+Name[fy]=Chalk RAW Ymportfilter
+Name[ga]=Scagaire Iompórtála RAW Chalk
+Name[gl]=Filtro de Importación RAW para Chalk
+Name[he]=Chalk RAW מסנן יבוא
+Name[hr]=Chalk RAW filtar uvoza
+Name[hu]=Chalk RAW importszűrő
+Name[is]=Chalk RAW innflutningssía
+Name[it]=Filtro di importazione di formati grezzi per Chalk
+Name[ja]=Chalk RAW インポートフィルタ
+Name[km]=តម្រង​នាំចូល RAW សម្រាប់ Chalk
+Name[lt]=Chalk RAW importavimo filtras
+Name[lv]=Chalk RAW importa filtrs
+Name[nb]=RAW importfilter for Chalk
+Name[nds]=RAW-Importfilter för Chalk
+Name[ne]=क्रिता RAW आयात फिल्टर
+Name[nl]=Chalk RAW Importfilter
+Name[pl]=Filtr importu formatu RAW dla Chalk
+Name[pt]=Filtro de Importação RAW para o Chalk
+Name[pt_BR]=Filtro de Importação RAW para o Chalk
+Name[ru]=Фильтр импорта рисунков RAW в Chalk
+Name[se]=Chalk RAW-sisafievrridansilli
+Name[sk]=RAW filter pre import do Chalk
+Name[sl]=Uvozni filter RAW za Krito
+Name[sr]=Chalk-ин филтер за увоз из RAW-а
+Name[sr@Latn]=Chalk-in filter za uvoz iz RAW-a
+Name[sv]=Chalk RAW-importfilter
+Name[uk]=Фільтр імпорту RAW для Chalk
+Name[uz]=Chalk RAW import filteri
+Name[uz@cyrillic]=Chalk RAW импорт филтери
+Name[zh_CN]=Chalk RAW 导入过滤器
+Name[zh_TW]=Chalk RAW 匯入過濾程式
+X-KDE-Export=application/x-chalk
+X-KDE-Import=image/x-raw
+X-KDE-Weight=1
+X-KDE-Library=libchalk_raw_import
+ServiceTypes=KOfficeFilter
diff --git a/filters/chalk/raw/dcraw.1 b/filters/chalk/raw/dcraw.1
new file mode 100644
index 00000000..10a690b8
--- /dev/null
+++ b/filters/chalk/raw/dcraw.1
@@ -0,0 +1,182 @@
+.\"
+.\" Man page for dcraw (Raw Photo Decoder)
+.\"
+.\" Copyright (c) 2005 by David Coffin
+.\"
+.\" You may distribute without restriction.
+.\"
+.\" David Coffin
+.\" dcoffin a cybercom o net
+.\" http://www.cybercom.net/~dcoffin
+.\"
+.TH dcraw 1 "September 29, 2005"
+.LO 1
+.SH NAME
+dcraw - convert raw digital photos to PPM format
+.SH SYNOPSIS
+.B dcraw
+[\fIOPTION\fR]... [\fIFILE\fR]...
+.SH DESCRIPTION
+.B dcraw
+converts raw digital photos to
+.BR ppm (5)
+format.
+.SH OPTIONS
+.TP
+.B -v
+Print verbose messages. The default is to print only warnings
+and errors.
+.TP
+.B -z
+Change the access and modification times of a JPEG or raw file to
+when the photo was taken, assuming that the camera clock was set
+to Universal Time.
+.TP
+.B -i
+Identify files but don't decode them.
+Exit status is 0 if
+.B dcraw
+can decode the last file, 1 if it can't.
+.TP
+.B ""
+.B dcraw
+cannot decode JPEG files!!
+.TP
+.B -c
+Write binary image data to standard output.
+By default,
+.B dcraw
+creates files with a ".ppm" extension.
+.TP
+.B -d
+Show the raw data as a grayscale image with no interpolation.
+Good for photographing black-and-white documents.
+.TP
+.B -q [0-3]
+Set the interpolation quality (default is 3):
+
+.B \t0
+\ \ Bilinear (very fast, low quality)
+.br
+.B \t1
+\ \ Reserved
+.br
+.B \t2
+\ \ Variable Number of Gradients (VNG)
+.br
+.B \t3
+\ \ Adaptive Homogeneity-Directed (AHD)
+.TP
+.B -h
+Output a half-size image. Twice as fast as
+.BR -q\ 0 .
+.TP
+.B -f
+Interpolate RGB as four colors. This blurs the image a little,
+but it eliminates false 2x2 mesh patterns.
+.TP
+.B -B sigma_domain sigma_range
+Use a bilateral filter to smooth noise while preserving edges.
+.B sigma_domain
+is in units of pixels, while
+.B sigma_range
+is in units of CIELab colorspace.
+Try
+.B -B\ 2\ 4
+to start.
+.TP
+.B -a
+Automatic color balance. The default is to use a fixed
+color balance based on a white card photographed in sunlight.
+.TP
+.B -w
+Use the color balance specified by the camera.
+If this can't be found,
+.B dcraw
+prints a warning and reverts to the default.
+.TP
+.B -r red_mul -l blue_mul
+Further adjust the color balance by multiplying the red and
+blue output channels by these values. Both default to 1.0.
+.TP
+.B -b brightness
+Change the output brightness. Default is 1.0.
+.TP
+.B -k black
+Set the black point. Default depends on the camera.
+.TP
+.B -n
+By default,
+.B dcraw
+clips all colors to prevent pink hues in the highlights.
+Combine this option with
+.B -b 0.25
+to leave the image data completely unclipped.
+.TP
+.B -m
+Write raw camera colors to the output file. By default,
+.B dcraw
+converts to sRGB colorspace.
+.TP
+.B -j
+For Fuji\ Super\ CCD cameras, show the image tilted 45 degrees
+so that each output pixel corresponds to one raw pixel.
+.TP
+.B -s
+For Fuji\ Super\ CCD\ SR cameras, use the secondary sensors, in
+effect underexposing the image by four stops to reveal detail
+in the highlights.
+.TP
+.B ""
+For all other cameras,
+.B -j
+and
+.B -s
+are silently ignored.
+.TP
+.B -t [0-7]
+Flip the output image. The most common flips are 5
+(90 degrees CCW) and 6 (90 degrees clockwise). By default,
+dcraw tries to use the flip specified by the camera.
+.RB \^" -t\ 0 \^"
+forces
+.B dcraw
+not to flip images.
+.TP
+.B -2
+Write eight bits per color value with a 99th-percentile white
+point and the standard 0.45 gamma curve. Double the height if
+necessary to correct the aspect ratio. This is the default.
+.TP
+.B -4
+Write sixteen bits per color value. Output is linear with
+input -- no white point, no gamma, same aspect ratio.
+.TP
+.B -3
+Same image as
+.BR -4 ,
+written in Adobe PhotoShop format. File extension is ".psd".
+.SH "SEE ALSO"
+.BR ppm (5),
+.BR ppm2tiff (1),
+.BR pnmtotiff (1),
+.BR pnmtopng (1),
+.BR gphoto2 (1),
+.BR djpeg (1)
+.SH BUGS
+The
+.B -w
+option does not work with many cameras.
+.P
+No attempt is made to save camera settings or thumbnail images.
+.P
+The author stubbornly refuses to add more output formats.
+.P
+Don't expect
+.B dcraw
+to produce the same images as software provided by the camera
+vendor. Sometimes
+.B dcraw
+gives better results!
+.SH AUTHOR
+Written by David Coffin, dcoffin a cybercom o net
diff --git a/filters/chalk/raw/dcraw.c b/filters/chalk/raw/dcraw.c
new file mode 100644
index 00000000..e92c1d3c
--- /dev/null
+++ b/filters/chalk/raw/dcraw.c
@@ -0,0 +1,5999 @@
+/*
+ dcraw.c -- Dave Coffin's raw photo decoder
+ Copyright 1997-2005 by Dave Coffin, dcoffin a cybercom o net
+
+ This is a command-line ANSI C program to convert raw photos from
+ any digital camera on any computer running any operating system.
+
+ Attention! Some parts of this program are restricted under the
+ terms of the GNU General Public License. Such code is enclosed
+ in "BEGIN GPL BLOCK" and "END GPL BLOCK" declarations.
+ Any code not declared GPL is free for all uses.
+
+ Starting in Revision 1.237, the code to support Foveon cameras
+ is under GPL.
+
+ To lawfully redistribute dcraw.c, you must either (a) include
+ full source code for all executable files containing restricted
+ functions, (b) remove these functions, re-implement them, or
+ copy them from an earlier, non-GPL Revision of dcraw.c, or (c)
+ purchase a license from the author.
+
+ $Revision: 1.296 $
+ $Date: 2005/11/04 07:11:14 $
+ */
+
+#define _GNU_SOURCE
+#define _USE_MATH_DEFINES
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+/*
+ By defining NO_JPEG, you lose only the ability to
+ decode compressed .KDC files from the Kodak DC120.
+ */
+#ifndef NO_JPEG
+#include <jpeglib.h>
+#endif
+
+#ifdef __CYGWIN__
+#include <io.h>
+#endif
+#ifdef WIN32
+#include <sys/utime.h>
+#include <winsock2.h>
+#pragma comment(lib, "ws2_32.lib")
+#define strcasecmp stricmp
+typedef __int64 INT64;
+typedef unsigned __int64 UINT64;
+#else
+#include <unistd.h>
+#include <utime.h>
+#include <netinet/in.h>
+typedef long long INT64;
+typedef unsigned long long UINT64;
+#endif
+
+#ifdef LJPEG_DECODE
+#error Please compile dcraw.c by itself.
+#error Do not link it with ljpeg_decode.
+#endif
+
+#ifndef LONG_BIT
+#define LONG_BIT (8 * sizeof (long))
+#endif
+
+#define ushort UshORt
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+
+/*
+ All global variables are defined here, and all functions that
+ access them are prefixed with "CLASS". Note that a thread-safe
+ C++ class cannot have non-const static local variables.
+ */
+FILE *ifp;
+short order;
+char *ifname, make[64], model[70], model2[64], *meta_data;
+float flash_used, canon_5814;
+time_t timestamp;
+unsigned shot_order, kodak_cbpp;
+int data_offset, meta_offset, meta_length, nikon_curve_offset;
+int tiff_bps, tiff_data_compression, kodak_data_compression;
+int raw_height, raw_width, top_margin, left_margin;
+int height, width, fuji_width, colors, tiff_samples;
+int black, maximum, clip_max, clip_color=1;
+int iheight, iwidth, shrink;
+int dng_version, is_foveon, raw_color, use_gamma;
+int flip, xmag, ymag;
+int zero_after_ff;
+unsigned filters;
+ushort (*image)[4], white[8][8], curve[0x1000];
+void (*load_raw)();
+float bright=1, red_scale=1, blue_scale=1, sigma_d=0, sigma_r=0;
+int four_color_rgb=0, document_mode=0;
+int verbose=0, use_auto_wb=0, use_camera_wb=0, use_camera_rgb=0;
+int fuji_layout, fuji_secondary, use_secondary=0;
+float cam_mul[4], pre_mul[4], rgb_cam[3][4]; /* RGB from camera color */
+const double xyz_rgb[3][3] = { /* XYZ from RGB */
+ { 0.412453, 0.357580, 0.180423 },
+ { 0.212671, 0.715160, 0.072169 },
+ { 0.019334, 0.119193, 0.950227 } };
+#define camera_red cam_mul[0]
+#define camera_blue cam_mul[2]
+int histogram[3][0x2000];
+void write_ppm(FILE *);
+void (*write_fun)(FILE *) = write_ppm;
+jmp_buf failure;
+
+#define USE_LCMS
+#ifdef USE_LCMS
+#include <lcms.h>
+int profile_offset, profile_length;
+#endif
+
+struct decode {
+ struct decode *branch[2];
+ int leaf;
+} first_decode[2048], *second_decode, *free_decode;
+
+#define CLASS
+
+#define FORC3 for (c=0; c < 3; c++)
+#define FORC4 for (c=0; c < 4; c++)
+#define FORCC for (c=0; c < colors; c++)
+
+#define SQR(x) ((x)*(x))
+#define ABS(x) (((int)(x) ^ ((int)(x) >> 31)) - ((int)(x) >> 31))
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define LIM(x,min,max) MAX(min,MIN(x,max))
+#define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y))
+#define CLIP(x) LIM(x,0,clip_max)
+
+/*
+ In order to inline this calculation, I make the risky
+ assumption that all filter patterns can be described
+ by a repeating pattern of eight rows and two columns
+
+ Return values are either 0/1/2/3 = G/M/C/Y or 0/1/2/3 = R/G1/B/G2
+ */
+#define FC(row,col) \
+ (filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)
+
+#define BAYER(row,col) \
+ image[((row) >> shrink)*iwidth + ((col) >> shrink)][FC(row,col)]
+
+/*
+ PowerShot 600 PowerShot A50 PowerShot Pro70 Pro90 & G1
+ 0xe1e4e1e4: 0x1b4e4b1e: 0x1e4b4e1b: 0xb4b4b4b4:
+
+ 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5
+ 0 G M G M G M 0 C Y C Y C Y 0 Y C Y C Y C 0 G M G M G M
+ 1 C Y C Y C Y 1 M G M G M G 1 M G M G M G 1 Y C Y C Y C
+ 2 M G M G M G 2 Y C Y C Y C 2 C Y C Y C Y
+ 3 C Y C Y C Y 3 G M G M G M 3 G M G M G M
+ 4 C Y C Y C Y 4 Y C Y C Y C
+ PowerShot A5 5 G M G M G M 5 G M G M G M
+ 0x1e4e1e4e: 6 Y C Y C Y C 6 C Y C Y C Y
+ 7 M G M G M G 7 M G M G M G
+ 0 1 2 3 4 5
+ 0 C Y C Y C Y
+ 1 G M G M G M
+ 2 C Y C Y C Y
+ 3 M G M G M G
+
+ All RGB cameras use one of these Bayer grids:
+
+ 0x16161616: 0x61616161: 0x49494949: 0x94949494:
+
+ 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5
+ 0 B G B G B G 0 G R G R G R 0 G B G B G B 0 R G R G R G
+ 1 G R G R G R 1 B G B G B G 1 R G R G R G 1 G B G B G B
+ 2 B G B G B G 2 G R G R G R 2 G B G B G B 2 R G R G R G
+ 3 G R G R G R 3 B G B G B G 3 R G R G R G 3 G B G B G B
+ */
+
+#ifndef __GLIBC__
+char *memmem (char *haystack, size_t haystacklen,
+ char *needle, size_t needlelen)
+{
+ char *c;
+ for (c = haystack; c <= haystack + haystacklen - needlelen; c++)
+ if (!memcmp (c, needle, needlelen))
+ return c;
+ return NULL;
+}
+#endif
+
+void CLASS merror (void *ptr, char *where)
+{
+ if (ptr) return;
+ fprintf (stderr, "%s: Out of memory in %s\n", ifname, where);
+ longjmp (failure, 1);
+}
+
+ushort CLASS sget2 (uchar *s)
+{
+ if (order == 0x4949) /* "II" means little-endian */
+ return s[0] | s[1] << 8;
+ else /* "MM" means big-endian */
+ return s[0] << 8 | s[1];
+}
+
+ushort CLASS get2()
+{
+ uchar str[2] = { 0xff,0xff };
+ fread (str, 1, 2, ifp);
+ return sget2(str);
+}
+
+int CLASS sget4 (uchar *s)
+{
+ if (order == 0x4949)
+ return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
+ else
+ return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3];
+}
+#define sget4(s) sget4((uchar *)s)
+
+int CLASS get4()
+{
+ uchar str[4] = { 0xff,0xff,0xff,0xff };
+ fread (str, 1, 4, ifp);
+ return sget4(str);
+}
+
+double CLASS getrat()
+{
+ double num = get4();
+ return num / get4();
+}
+
+float CLASS int_to_float (int i)
+{
+ union { int i; float f; } u;
+ u.i = i;
+ return u.f;
+}
+
+void CLASS read_shorts (ushort *pixel, int count)
+{
+ fread (pixel, 2, count, ifp);
+ if ((order == 0x4949) == (ntohs(0x1234) == 0x1234))
+ swab (pixel, pixel, count*2);
+}
+
+void CLASS canon_600_fixed_wb (int temp)
+{
+ static const short mul[4][5] = {
+ { 667, 358,397,565,452 },
+ { 731, 390,367,499,517 },
+ { 1119, 396,348,448,537 },
+ { 1399, 485,431,508,688 } };
+ int lo, hi, i;
+ float frac=0;
+
+ for (lo=4; --lo; )
+ if (*mul[lo] <= temp) break;
+ for (hi=0; hi < 3; hi++)
+ if (*mul[hi] >= temp) break;
+ if (lo != hi)
+ frac = (float) (temp - *mul[lo]) / (*mul[hi] - *mul[lo]);
+ for (i=1; i < 5; i++)
+ pre_mul[i-1] = 1 / (frac * mul[hi][i] + (1-frac) * mul[lo][i]);
+}
+
+/* Return values: 0 = white 1 = near white 2 = not white */
+int CLASS canon_600_color (int ratio[2], int mar)
+{
+ int clipped=0, target, miss;
+
+ if (flash_used) {
+ if (ratio[1] < -104)
+ { ratio[1] = -104; clipped = 1; }
+ if (ratio[1] > 12)
+ { ratio[1] = 12; clipped = 1; }
+ } else {
+ if (ratio[1] < -264 || ratio[1] > 461) return 2;
+ if (ratio[1] < -50)
+ { ratio[1] = -50; clipped = 1; }
+ if (ratio[1] > 307)
+ { ratio[1] = 307; clipped = 1; }
+ }
+ target = flash_used || ratio[1] < 197
+ ? -38 - (398 * ratio[1] >> 10)
+ : -123 + (48 * ratio[1] >> 10);
+ if (target - mar <= ratio[0] &&
+ target + 20 >= ratio[0] && !clipped) return 0;
+ miss = target - ratio[0];
+ if (abs(miss) >= mar*4) return 2;
+ if (miss < -20) miss = -20;
+ if (miss > mar) miss = mar;
+ ratio[0] = target - miss;
+ return 1;
+}
+
+void CLASS canon_600_auto_wb ()
+{
+ int mar, row, col, i, j, st, count[] = { 0,0 };
+ int test[8], total[2][8], ratio[2][2], stat[2];
+
+ memset (&total, 0, sizeof total);
+ i = canon_5814 + 0.5;
+ if (i < 10) mar = 150;
+ else if (i > 12) mar = 20;
+ else mar = 280 - 20 * i;
+ if (flash_used) mar = 80;
+ for (row=14; row < height-14; row+=4)
+ for (col=10; col < width; col+=2) {
+ for (i=0; i < 8; i++)
+ test[(i & 4) + FC(row+(i >> 1),col+(i & 1))] =
+ BAYER(row+(i >> 1),col+(i & 1));
+ for (i=0; i < 8; i++)
+ if (test[i] < 150 || test[i] > 1500) goto next;
+ for (i=0; i < 4; i++)
+ if (abs(test[i] - test[i+4]) > 50) goto next;
+ for (i=0; i < 2; i++) {
+ for (j=0; j < 4; j+=2)
+ ratio[i][j >> 1] = ((test[i*4+j+1]-test[i*4+j]) << 10) / test[i*4+j];
+ stat[i] = canon_600_color (ratio[i], mar);
+ }
+ if ((st = stat[0] | stat[1]) > 1) goto next;
+ for (i=0; i < 2; i++)
+ if (stat[i])
+ for (j=0; j < 2; j++)
+ test[i*4+j*2+1] = test[i*4+j*2] * (0x400 + ratio[i][j]) >> 10;
+ for (i=0; i < 8; i++)
+ total[st][i] += test[i];
+ count[st]++;
+next: continue;
+ }
+ if (count[0] | count[1]) {
+ st = count[0]*200 < count[1];
+ for (i=0; i < 4; i++)
+ pre_mul[i] = 1.0 / (total[st][i] + total[st][i+4]);
+ }
+}
+
+void CLASS canon_600_coeff ()
+{
+ static const short table[6][12] = {
+ { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 },
+ { -1203,1715,-1136,1648, 1388,-876,267,245, -1641,2153,3921,-3409 },
+ { -615,1127,-1563,2075, 1437,-925,509,3, -756,1268,2519,-2007 },
+ { -190,702,-1886,2398, 2153,-1641,763,-251, -452,964,3040,-2528 },
+ { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 },
+ { -807,1319,-1785,2297, 1388,-876,769,-257, -230,742,2067,-1555 } };
+ int t=0, i, c;
+ float mc, yc;
+
+ mc = pre_mul[1] / pre_mul[2];
+ yc = pre_mul[3] / pre_mul[2];
+ if (mc > 1 && mc <= 1.28 && yc < 0.8789) t=1;
+ if (mc > 1.28 && mc <= 2) {
+ if (yc < 0.8789) t=3;
+ else if (yc <= 2) t=4;
+ }
+ if (flash_used) t=5;
+ for (raw_color = i=0; i < 3; i++)
+ FORCC rgb_cam[i][c] = table[t][i*4 + c] / 1024.0;
+}
+
+void CLASS canon_600_load_raw()
+{
+ uchar data[1120], *dp;
+ ushort pixel[896], *pix;
+ int irow, row, col, val;
+ static const short mul[4][2] =
+ { { 1141,1145 }, { 1128,1109 }, { 1178,1149 }, { 1128,1109 } };
+
+ for (irow=row=0; irow < height; irow++)
+ {
+ fread (data, 1120, 1, ifp);
+ for (dp=data, pix=pixel; dp < data+1120; dp+=10, pix+=8)
+ {
+ pix[0] = (dp[0] << 2) + (dp[1] >> 6 );
+ pix[1] = (dp[2] << 2) + (dp[1] >> 4 & 3);
+ pix[2] = (dp[3] << 2) + (dp[1] >> 2 & 3);
+ pix[3] = (dp[4] << 2) + (dp[1] & 3);
+ pix[4] = (dp[5] << 2) + (dp[9] & 3);
+ pix[5] = (dp[6] << 2) + (dp[9] >> 2 & 3);
+ pix[6] = (dp[7] << 2) + (dp[9] >> 4 & 3);
+ pix[7] = (dp[8] << 2) + (dp[9] >> 6 );
+ }
+ for (col=0; col < width; col++)
+ BAYER(row,col) = pixel[col];
+ for (col=width; col < 896; col++)
+ black += pixel[col];
+ if ((row+=2) > height) row = 1;
+ }
+ black = black / ((896 - width) * height) - 4;
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col++) {
+ val = (BAYER(row,col) - black) * mul[row & 3][col & 1] >> 9;
+ if (val < 0) val = 0;
+ BAYER(row,col) = val;
+ }
+ canon_600_fixed_wb(1311);
+ canon_600_auto_wb();
+ canon_600_coeff();
+ maximum = (0x3ff - black) * 1109 >> 9;
+ black = 0;
+}
+
+void CLASS canon_a5_load_raw()
+{
+ uchar data[1940], *dp;
+ ushort pixel[1552], *pix;
+ int row, col;
+
+ for (row=0; row < height; row++) {
+ fread (data, raw_width * 10 / 8, 1, ifp);
+ for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=10, pix+=8)
+ {
+ pix[0] = (dp[1] << 2) + (dp[0] >> 6);
+ pix[1] = (dp[0] << 4) + (dp[3] >> 4);
+ pix[2] = (dp[3] << 6) + (dp[2] >> 2);
+ pix[3] = (dp[2] << 8) + (dp[5] );
+ pix[4] = (dp[4] << 2) + (dp[7] >> 6);
+ pix[5] = (dp[7] << 4) + (dp[6] >> 4);
+ pix[6] = (dp[6] << 6) + (dp[9] >> 2);
+ pix[7] = (dp[9] << 8) + (dp[8] );
+ }
+ for (col=0; col < width; col++)
+ BAYER(row,col) = (pixel[col] & 0x3ff);
+ for (col=width; col < raw_width; col++)
+ black += pixel[col] & 0x3ff;
+ }
+ if (raw_width > width)
+ black /= (raw_width - width) * height;
+ maximum = 0x3ff;
+}
+
+/*
+ getbits(-1) initializes the buffer
+ getbits(n) where 0 <= n <= 25 returns an n-bit integer
+ */
+unsigned CLASS getbits (int nbits)
+{
+ static unsigned bitbuf=0;
+ static int vbits=0, reset=0;
+ unsigned c;
+
+ if (nbits == -1)
+ return bitbuf = vbits = reset = 0;
+ if (nbits == 0 || reset) return 0;
+ while (vbits < nbits) {
+ c = fgetc(ifp);
+ if ((reset = zero_after_ff && c == 0xff && fgetc(ifp))) return 0;
+ bitbuf = (bitbuf << 8) + c;
+ vbits += 8;
+ }
+ vbits -= nbits;
+ return bitbuf << (32-nbits-vbits) >> (32-nbits);
+}
+
+void CLASS init_decoder ()
+{
+ memset (first_decode, 0, sizeof first_decode);
+ free_decode = first_decode;
+}
+
+/*
+ Construct a decode tree according the specification in *source.
+ The first 16 bytes specify how many codes should be 1-bit, 2-bit
+ 3-bit, etc. Bytes after that are the leaf values.
+
+ For example, if the source is
+
+ { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0,
+ 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff },
+
+ then the code is
+
+ 00 0x04
+ 010 0x03
+ 011 0x05
+ 100 0x06
+ 101 0x02
+ 1100 0x07
+ 1101 0x01
+ 11100 0x08
+ 11101 0x09
+ 11110 0x00
+ 111110 0x0a
+ 1111110 0x0b
+ 1111111 0xff
+ */
+uchar * CLASS make_decoder (const uchar *source, int level)
+{
+ struct decode *cur;
+ static int leaf;
+ int i, next;
+
+ if (level==0) leaf=0;
+ cur = free_decode++;
+ if (free_decode > first_decode+2048) {
+ fprintf (stderr, "%s: decoder table overflow\n", ifname);
+ longjmp (failure, 2);
+ }
+ for (i=next=0; i <= leaf && next < 16; )
+ i += source[next++];
+ if (i > leaf) {
+ if (level < next) {
+ cur->branch[0] = free_decode;
+ make_decoder (source, level+1);
+ cur->branch[1] = free_decode;
+ make_decoder (source, level+1);
+ } else
+ cur->leaf = source[16 + leaf++];
+ }
+ return (uchar *) source + 16 + leaf;
+}
+
+void CLASS crw_init_tables (unsigned table)
+{
+ static const uchar first_tree[3][29] = {
+ { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0,
+ 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff },
+ { 0,2,2,3,1,1,1,1,2,0,0,0,0,0,0,0,
+ 0x03,0x02,0x04,0x01,0x05,0x00,0x06,0x07,0x09,0x08,0x0a,0x0b,0xff },
+ { 0,0,6,3,1,1,2,0,0,0,0,0,0,0,0,0,
+ 0x06,0x05,0x07,0x04,0x08,0x03,0x09,0x02,0x00,0x0a,0x01,0x0b,0xff },
+ };
+ static const uchar second_tree[3][180] = {
+ { 0,2,2,2,1,4,2,1,2,5,1,1,0,0,0,139,
+ 0x03,0x04,0x02,0x05,0x01,0x06,0x07,0x08,
+ 0x12,0x13,0x11,0x14,0x09,0x15,0x22,0x00,0x21,0x16,0x0a,0xf0,
+ 0x23,0x17,0x24,0x31,0x32,0x18,0x19,0x33,0x25,0x41,0x34,0x42,
+ 0x35,0x51,0x36,0x37,0x38,0x29,0x79,0x26,0x1a,0x39,0x56,0x57,
+ 0x28,0x27,0x52,0x55,0x58,0x43,0x76,0x59,0x77,0x54,0x61,0xf9,
+ 0x71,0x78,0x75,0x96,0x97,0x49,0xb7,0x53,0xd7,0x74,0xb6,0x98,
+ 0x47,0x48,0x95,0x69,0x99,0x91,0xfa,0xb8,0x68,0xb5,0xb9,0xd6,
+ 0xf7,0xd8,0x67,0x46,0x45,0x94,0x89,0xf8,0x81,0xd5,0xf6,0xb4,
+ 0x88,0xb1,0x2a,0x44,0x72,0xd9,0x87,0x66,0xd4,0xf5,0x3a,0xa7,
+ 0x73,0xa9,0xa8,0x86,0x62,0xc7,0x65,0xc8,0xc9,0xa1,0xf4,0xd1,
+ 0xe9,0x5a,0x92,0x85,0xa6,0xe7,0x93,0xe8,0xc1,0xc6,0x7a,0x64,
+ 0xe1,0x4a,0x6a,0xe6,0xb3,0xf1,0xd3,0xa5,0x8a,0xb2,0x9a,0xba,
+ 0x84,0xa4,0x63,0xe5,0xc5,0xf3,0xd2,0xc4,0x82,0xaa,0xda,0xe4,
+ 0xf2,0xca,0x83,0xa3,0xa2,0xc3,0xea,0xc2,0xe2,0xe3,0xff,0xff },
+ { 0,2,2,1,4,1,4,1,3,3,1,0,0,0,0,140,
+ 0x02,0x03,0x01,0x04,0x05,0x12,0x11,0x06,
+ 0x13,0x07,0x08,0x14,0x22,0x09,0x21,0x00,0x23,0x15,0x31,0x32,
+ 0x0a,0x16,0xf0,0x24,0x33,0x41,0x42,0x19,0x17,0x25,0x18,0x51,
+ 0x34,0x43,0x52,0x29,0x35,0x61,0x39,0x71,0x62,0x36,0x53,0x26,
+ 0x38,0x1a,0x37,0x81,0x27,0x91,0x79,0x55,0x45,0x28,0x72,0x59,
+ 0xa1,0xb1,0x44,0x69,0x54,0x58,0xd1,0xfa,0x57,0xe1,0xf1,0xb9,
+ 0x49,0x47,0x63,0x6a,0xf9,0x56,0x46,0xa8,0x2a,0x4a,0x78,0x99,
+ 0x3a,0x75,0x74,0x86,0x65,0xc1,0x76,0xb6,0x96,0xd6,0x89,0x85,
+ 0xc9,0xf5,0x95,0xb4,0xc7,0xf7,0x8a,0x97,0xb8,0x73,0xb7,0xd8,
+ 0xd9,0x87,0xa7,0x7a,0x48,0x82,0x84,0xea,0xf4,0xa6,0xc5,0x5a,
+ 0x94,0xa4,0xc6,0x92,0xc3,0x68,0xb5,0xc8,0xe4,0xe5,0xe6,0xe9,
+ 0xa2,0xa3,0xe3,0xc2,0x66,0x67,0x93,0xaa,0xd4,0xd5,0xe7,0xf8,
+ 0x88,0x9a,0xd7,0x77,0xc4,0x64,0xe2,0x98,0xa5,0xca,0xda,0xe8,
+ 0xf3,0xf6,0xa9,0xb2,0xb3,0xf2,0xd2,0x83,0xba,0xd3,0xff,0xff },
+ { 0,0,6,2,1,3,3,2,5,1,2,2,8,10,0,117,
+ 0x04,0x05,0x03,0x06,0x02,0x07,0x01,0x08,
+ 0x09,0x12,0x13,0x14,0x11,0x15,0x0a,0x16,0x17,0xf0,0x00,0x22,
+ 0x21,0x18,0x23,0x19,0x24,0x32,0x31,0x25,0x33,0x38,0x37,0x34,
+ 0x35,0x36,0x39,0x79,0x57,0x58,0x59,0x28,0x56,0x78,0x27,0x41,
+ 0x29,0x77,0x26,0x42,0x76,0x99,0x1a,0x55,0x98,0x97,0xf9,0x48,
+ 0x54,0x96,0x89,0x47,0xb7,0x49,0xfa,0x75,0x68,0xb6,0x67,0x69,
+ 0xb9,0xb8,0xd8,0x52,0xd7,0x88,0xb5,0x74,0x51,0x46,0xd9,0xf8,
+ 0x3a,0xd6,0x87,0x45,0x7a,0x95,0xd5,0xf6,0x86,0xb4,0xa9,0x94,
+ 0x53,0x2a,0xa8,0x43,0xf5,0xf7,0xd4,0x66,0xa7,0x5a,0x44,0x8a,
+ 0xc9,0xe8,0xc8,0xe7,0x9a,0x6a,0x73,0x4a,0x61,0xc7,0xf4,0xc6,
+ 0x65,0xe9,0x72,0xe6,0x71,0x91,0x93,0xa6,0xda,0x92,0x85,0x62,
+ 0xf3,0xc5,0xb2,0xa4,0x84,0xba,0x64,0xa5,0xb3,0xd2,0x81,0xe5,
+ 0xd3,0xaa,0xc4,0xca,0xf2,0xb1,0xe4,0xd1,0x83,0x63,0xea,0xc3,
+ 0xe2,0x82,0xf1,0xa3,0xc2,0xa1,0xc1,0xe3,0xa2,0xe1,0xff,0xff }
+ };
+ if (table > 2) table = 2;
+ init_decoder();
+ make_decoder ( first_tree[table], 0);
+ second_decode = free_decode;
+ make_decoder (second_tree[table], 0);
+}
+
+/*
+ Return 0 if the image starts with compressed data,
+ 1 if it starts with uncompressed low-order bits.
+
+ In Canon compressed data, 0xff is always followed by 0x00.
+ */
+int CLASS canon_has_lowbits()
+{
+ uchar test[0x4000];
+ int ret=1, i;
+
+ fseek (ifp, 0, SEEK_SET);
+ fread (test, 1, sizeof test, ifp);
+ for (i=540; i < sizeof test - 1; i++)
+ if (test[i] == 0xff) {
+ if (test[i+1]) return 1;
+ ret=0;
+ }
+ return ret;
+}
+
+void CLASS canon_compressed_load_raw()
+{
+ ushort *pixel, *prow;
+ int lowbits, i, row, r, col, save, val;
+ unsigned irow, icol;
+ struct decode *decode, *dindex;
+ int block, diffbuf[64], leaf, len, diff, carry=0, pnum=0, base[2];
+ uchar c;
+
+ pixel = calloc (raw_width*8, sizeof *pixel);
+ merror (pixel, "canon_compressed_load_raw()");
+ lowbits = canon_has_lowbits();
+ if (!lowbits) maximum = 0x3ff;
+ fseek (ifp, 540 + lowbits*raw_height*raw_width/4, SEEK_SET);
+ zero_after_ff = 1;
+ getbits(-1);
+ for (row = 0; row < raw_height; row += 8) {
+ for (block=0; block < raw_width >> 3; block++) {
+ memset (diffbuf, 0, sizeof diffbuf);
+ decode = first_decode;
+ for (i=0; i < 64; i++ ) {
+ for (dindex=decode; dindex->branch[0]; )
+ dindex = dindex->branch[getbits(1)];
+ leaf = dindex->leaf;
+ decode = second_decode;
+ if (leaf == 0 && i) break;
+ if (leaf == 0xff) continue;
+ i += leaf >> 4;
+ len = leaf & 15;
+ if (len == 0) continue;
+ diff = getbits(len);
+ if ((diff & (1 << (len-1))) == 0)
+ diff -= (1 << len) - 1;
+ if (i < 64) diffbuf[i] = diff;
+ }
+ diffbuf[0] += carry;
+ carry = diffbuf[0];
+ for (i=0; i < 64; i++ ) {
+ if (pnum++ % raw_width == 0)
+ base[0] = base[1] = 512;
+ pixel[(block << 6) + i] = ( base[i & 1] += diffbuf[i] );
+ }
+ }
+ if (lowbits) {
+ save = ftell(ifp);
+ fseek (ifp, 26 + row*raw_width/4, SEEK_SET);
+ for (prow=pixel, i=0; i < raw_width*2; i++) {
+ c = fgetc(ifp);
+ for (r=0; r < 8; r+=2, prow++) {
+ val = (*prow << 2) + ((c >> r) & 3);
+ if (raw_width == 2672 && val < 512) val += 2;
+ *prow = val;
+ }
+ }
+ fseek (ifp, save, SEEK_SET);
+ }
+ for (r=0; r < 8; r++) {
+ irow = row - top_margin + r;
+ if (irow >= height) continue;
+ for (col = 0; col < raw_width; col++) {
+ icol = col - left_margin;
+ if (icol < width)
+ BAYER(irow,icol) = pixel[r*raw_width+col];
+ else
+ black += pixel[r*raw_width+col];
+ }
+ }
+ }
+ free (pixel);
+ if (raw_width > width)
+ black /= (raw_width - width) * height;
+}
+
+/*
+ Not a full implementation of Lossless JPEG, just
+ enough to decode Canon, Kodak and Adobe DNG images.
+ */
+struct jhead {
+ int bits, high, wide, clrs, restart, vpred[4];
+ struct decode *huff[4];
+ ushort *row;
+};
+
+int CLASS ljpeg_start (struct jhead *jh)
+{
+ int i, tag, len;
+ uchar data[256], *dp;
+
+ init_decoder();
+ for (i=0; i < 4; i++)
+ jh->huff[i] = free_decode;
+ jh->restart = INT_MAX;
+ fread (data, 2, 1, ifp);
+ if (data[0] != 0xff || data[1] != 0xd8) return 0;
+ do {
+ fread (data, 2, 2, ifp);
+ tag = data[0] << 8 | data[1];
+ len = (data[2] << 8 | data[3]) - 2;
+ if (tag <= 0xff00 || len > 255) return 0;
+ fread (data, 1, len, ifp);
+ switch (tag) {
+ case 0xffc3:
+ jh->bits = data[0];
+ jh->high = data[1] << 8 | data[2];
+ jh->wide = data[3] << 8 | data[4];
+ jh->clrs = data[5];
+ break;
+ case 0xffc4:
+ for (dp = data; dp < data+len && *dp < 4; ) {
+ jh->huff[*dp] = free_decode;
+ dp = make_decoder (++dp, 0);
+ }
+ break;
+ case 0xffdd:
+ jh->restart = data[0] << 8 | data[1];
+ }
+ } while (tag != 0xffda);
+ jh->row = calloc (jh->wide*jh->clrs, 2);
+ merror (jh->row, " jpeg_start()");
+ zero_after_ff = 1;
+ return 1;
+}
+
+int CLASS ljpeg_diff (struct decode *dindex)
+{
+ int len, diff;
+
+ while (dindex->branch[0])
+ dindex = dindex->branch[getbits(1)];
+ len = dindex->leaf;
+ if (len == 16 && (!dng_version || dng_version >= 0x1010000))
+ return -32768;
+ diff = getbits(len);
+ if ((diff & (1 << (len-1))) == 0)
+ diff -= (1 << len) - 1;
+ return diff;
+}
+
+void CLASS ljpeg_row (int jrow, struct jhead *jh)
+{
+ int col, c, diff;
+ ushort *outp=jh->row;
+
+ if (jrow * jh->wide % jh->restart == 0) {
+ FORC4 jh->vpred[c] = 1 << (jh->bits-1);
+ if (jrow) get2(); /* Eat the FF Dx marker */
+ getbits(-1);
+ }
+ for (col=0; col < jh->wide; col++)
+ for (c=0; c < jh->clrs; c++) {
+ diff = ljpeg_diff (jh->huff[c]);
+ *outp = col ? outp[-jh->clrs]+diff : (jh->vpred[c] += diff);
+ outp++;
+ }
+}
+
+void CLASS lossless_jpeg_load_raw()
+{
+ int jwide, jrow, jcol, val, jidx, i, row, col;
+ struct jhead jh;
+ int min=INT_MAX;
+
+ if (!ljpeg_start (&jh)) return;
+ jwide = jh.wide * jh.clrs;
+
+ for (jrow=0; jrow < jh.high; jrow++) {
+ ljpeg_row (jrow, &jh);
+ for (jcol=0; jcol < jwide; jcol++) {
+ val = jh.row[jcol];
+ if (jh.bits <= 12)
+ val = curve[val];
+ jidx = jrow*jwide + jcol;
+ if (raw_width == 5108) {
+ i = jidx / (1680*jh.high);
+ if (i < 2) {
+ row = jidx / 1680 % jh.high;
+ col = jidx % 1680 + i*1680;
+ } else {
+ jidx -= 2*1680*jh.high;
+ row = jidx / 1748;
+ col = jidx % 1748 + 2*1680;
+ }
+ } else if (raw_width == 4476 || raw_width == 3516) {
+ row = jidx / (raw_width/2);
+ col = jidx % (raw_width/2);
+ if (row >= raw_height) {
+ row -= raw_height;
+ col += raw_width/2;
+ }
+ } else {
+ row = jidx / raw_width;
+ col = jidx % raw_width;
+ }
+ if ((unsigned) (row-top_margin) >= height) continue;
+ if ((unsigned) (col-left_margin) < width) {
+ BAYER(row-top_margin,col-left_margin) = val;
+ if (min > val) min = val;
+ } else
+ black += val;
+ }
+ }
+ free (jh.row);
+ if (raw_width > width)
+ black /= (raw_width - width) * height;
+ if (!strcasecmp(make,"KODAK"))
+ black = min;
+}
+
+void CLASS adobe_copy_pixel (int row, int col, ushort **rp)
+{
+ unsigned r, c;
+
+ r = row -= top_margin;
+ c = col -= left_margin;
+ if (fuji_secondary && use_secondary) (*rp)++;
+ if (filters) {
+ if (fuji_width) {
+ r = row + fuji_width - 1 - (col >> 1);
+ c = row + ((col+1) >> 1);
+ }
+ if (r < height && c < width)
+ BAYER(r,c) = **rp < 0x1000 ? curve[**rp] : **rp;
+ *rp += 1 + fuji_secondary;
+ } else {
+ if (r < height && c < width)
+ for (c=0; c < tiff_samples; c++)
+ image[row*width+col][c] = (*rp)[c] < 0x1000 ? curve[(*rp)[c]]:(*rp)[c];
+ *rp += tiff_samples;
+ }
+ if (fuji_secondary && use_secondary) (*rp)--;
+}
+
+void CLASS adobe_dng_load_raw_lj()
+{
+ int save, twide, trow=0, tcol=0, jrow, jcol;
+ struct jhead jh;
+ ushort *rp;
+
+ while (1) {
+ save = ftell(ifp);
+ fseek (ifp, get4(), SEEK_SET);
+ if (!ljpeg_start (&jh)) break;
+ if (trow >= raw_height) break;
+ if (jh.high > raw_height-trow)
+ jh.high = raw_height-trow;
+ twide = jh.wide;
+ if (filters) twide *= jh.clrs;
+ else colors = jh.clrs;
+ if (fuji_secondary) twide /= 2;
+ if (twide > raw_width-tcol)
+ twide = raw_width-tcol;
+
+ for (jrow=0; jrow < jh.high; jrow++) {
+ ljpeg_row (jrow, &jh);
+ for (rp=jh.row, jcol=0; jcol < twide; jcol++)
+ adobe_copy_pixel (trow+jrow, tcol+jcol, &rp);
+ }
+ fseek (ifp, save+4, SEEK_SET);
+ if ((tcol += twide) >= raw_width) {
+ tcol = 0;
+ trow += jh.high;
+ }
+ free (jh.row);
+ }
+}
+
+void CLASS adobe_dng_load_raw_nc()
+{
+ ushort *pixel, *rp;
+ int row, col;
+
+ pixel = calloc (raw_width * tiff_samples, sizeof *pixel);
+ merror (pixel, "adobe_dng_load_raw_nc()");
+ for (row=0; row < raw_height; row++) {
+ if (tiff_bps == 16)
+ read_shorts (pixel, raw_width * tiff_samples);
+ else {
+ getbits(-1);
+ for (col=0; col < raw_width * tiff_samples; col++)
+ pixel[col] = getbits(tiff_bps);
+ }
+ for (rp=pixel, col=0; col < raw_width; col++)
+ adobe_copy_pixel (row, col, &rp);
+ }
+ free (pixel);
+}
+
+void CLASS nikon_compressed_load_raw()
+{
+ static const uchar nikon_tree[] = {
+ 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0,
+ 5,4,3,6,2,7,1,0,8,9,11,10,12
+ };
+ int csize, row, col, i, diff;
+ ushort vpred[4], hpred[2], *curve;
+
+ init_decoder();
+ make_decoder (nikon_tree, 0);
+
+ fseek (ifp, nikon_curve_offset, SEEK_SET);
+ read_shorts (vpred, 4);
+ csize = get2();
+ curve = calloc (csize, sizeof *curve);
+ merror (curve, "nikon_compressed_load_raw()");
+ read_shorts (curve, csize);
+
+ fseek (ifp, data_offset, SEEK_SET);
+ getbits(-1);
+
+ for (row=0; row < height; row++)
+ for (col=0; col < raw_width; col++)
+ {
+ diff = ljpeg_diff (first_decode);
+ if (col < 2) {
+ i = 2*(row & 1) + (col & 1);
+ vpred[i] += diff;
+ hpred[col] = vpred[i];
+ } else
+ hpred[col & 1] += diff;
+ if ((unsigned) (col-left_margin) >= width) continue;
+ diff = hpred[col & 1];
+ if (diff >= csize) diff = csize-1;
+ BAYER(row,col-left_margin) = curve[diff];
+ }
+ free (curve);
+}
+
+void CLASS nikon_load_raw()
+{
+ int irow, row, col, i;
+
+ getbits(-1);
+ for (irow=0; irow < height; irow++) {
+ row = irow;
+ if (model[0] == 'E') {
+ row = irow * 2 % height + irow / (height/2);
+ if (row == 1 && data_offset == 0) {
+ fseek (ifp, 0, SEEK_END);
+ fseek (ifp, ftell(ifp)/2, SEEK_SET);
+ getbits(-1);
+ }
+ }
+ for (col=0; col < raw_width; col++) {
+ i = getbits(12);
+ if ((unsigned) (col-left_margin) < width)
+ BAYER(row,col-left_margin) = i;
+ if (tiff_data_compression == 34713 && (col % 10) == 9)
+ getbits(8);
+ }
+ }
+}
+
+/*
+ Figure out if a NEF file is compressed. These fancy heuristics
+ are only needed for the D100, thanks to a bug in some cameras
+ that tags all images as "compressed".
+ */
+int CLASS nikon_is_compressed()
+{
+ uchar test[256];
+ int i;
+
+ if (tiff_data_compression != 34713)
+ return 0;
+ if (strcmp(model,"D100"))
+ return 1;
+ fseek (ifp, data_offset, SEEK_SET);
+ fread (test, 1, 256, ifp);
+ for (i=15; i < 256; i+=16)
+ if (test[i]) return 1;
+ return 0;
+}
+
+/*
+ Returns 1 for a Coolpix 990, 0 for a Coolpix 995.
+ */
+int CLASS nikon_e990()
+{
+ int i, histo[256];
+ const uchar often[] = { 0x00, 0x55, 0xaa, 0xff };
+
+ memset (histo, 0, sizeof histo);
+ fseek (ifp, 2064*1540*3/4, SEEK_SET);
+ for (i=0; i < 2000; i++)
+ histo[fgetc(ifp)]++;
+ for (i=0; i < 4; i++)
+ if (histo[often[i]] > 400)
+ return 1;
+ return 0;
+}
+
+/*
+ Returns 1 for a Coolpix 2100, 0 for anything else.
+ */
+int CLASS nikon_e2100()
+{
+ uchar t[12];
+ int i;
+
+ fseek (ifp, 0, SEEK_SET);
+ for (i=0; i < 1024; i++) {
+ fread (t, 1, 12, ifp);
+ if (((t[2] & t[4] & t[7] & t[9]) >> 4
+ & t[1] & t[6] & t[8] & t[11] & 3) != 3)
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ Returns 0 for a Pentax Optio 33WR,
+ 1 for a Nikon E3700,
+ 2 for an Olympus C740UZ.
+ */
+int CLASS nikon_3700()
+{
+ int i, sum[] = { 0, 0 };
+ uchar tail[952];
+
+ fseek (ifp, -sizeof tail, SEEK_END);
+ fread (tail, 1, sizeof tail, ifp);
+ for (i=0; i < sizeof tail; i++)
+ sum[(i>>2) & 1] += tail[i];
+ if (sum[1] > 4*sum[0]) return 2;
+ return sum[0] > 4*sum[1];
+}
+
+/*
+ Separates a Minolta DiMAGE Z2 from a Nikon E4300.
+ */
+int CLASS minolta_z2()
+{
+ int i;
+ char tail[424];
+
+ fseek (ifp, -sizeof tail, SEEK_END);
+ fread (tail, 1, sizeof tail, ifp);
+ for (i=0; i < sizeof tail; i++)
+ if (tail[i]) return 1;
+ return 0;
+}
+
+/* Here raw_width is in bytes, not pixels. */
+void CLASS nikon_e900_load_raw()
+{
+ int offset=0, irow, row, col;
+
+ for (irow=0; irow < height; irow++) {
+ row = irow * 2 % height;
+ if (row == 1)
+ offset = - (-offset & -4096);
+ fseek (ifp, offset, SEEK_SET);
+ offset += raw_width;
+ getbits(-1);
+ for (col=0; col < width; col++)
+ BAYER(row,col) = getbits(10);
+ }
+}
+
+void CLASS nikon_e2100_load_raw()
+{
+ uchar data[3456], *dp;
+ ushort pixel[2304], *pix;
+ int row, col;
+
+ for (row=0; row <= height; row+=2) {
+ if (row == height) {
+ fseek (ifp, ((width==1616) << 13) - (-ftell(ifp) & -2048), SEEK_SET);
+ row = 1;
+ }
+ fread (data, 1, width*3/2, ifp);
+ for (dp=data, pix=pixel; pix < pixel+width; dp+=12, pix+=8) {
+ pix[0] = (dp[2] >> 4) + (dp[ 3] << 4);
+ pix[1] = (dp[2] << 8) + dp[ 1];
+ pix[2] = (dp[7] >> 4) + (dp[ 0] << 4);
+ pix[3] = (dp[7] << 8) + dp[ 6];
+ pix[4] = (dp[4] >> 4) + (dp[ 5] << 4);
+ pix[5] = (dp[4] << 8) + dp[11];
+ pix[6] = (dp[9] >> 4) + (dp[10] << 4);
+ pix[7] = (dp[9] << 8) + dp[ 8];
+ }
+ for (col=0; col < width; col++)
+ BAYER(row,col) = (pixel[col] & 0xfff);
+ }
+}
+
+/*
+ The Fuji Super CCD is just a Bayer grid rotated 45 degrees.
+ */
+void CLASS fuji_load_raw()
+{
+ ushort *pixel;
+ int row, col, r, c;
+
+ pixel = calloc (raw_width, sizeof *pixel);
+ merror (pixel, "fuji_load_raw()");
+ for (row=0; row < raw_height; row++) {
+ read_shorts (pixel, raw_width);
+ for (col=0; col < fuji_width << !fuji_layout; col++) {
+ if (fuji_layout) {
+ r = fuji_width - 1 - col + (row >> 1);
+ c = col + ((row+1) >> 1);
+ } else {
+ r = fuji_width - 1 + row - (col >> 1);
+ c = row + ((col+1) >> 1);
+ }
+ BAYER(r,c) = pixel[col];
+ }
+ }
+ free (pixel);
+}
+
+void CLASS rollei_load_raw()
+{
+ uchar pixel[10];
+ unsigned iten=0, isix, i, buffer=0, row, col, todo[16];
+
+ isix = raw_width * raw_height * 5 / 8;
+ while (fread (pixel, 1, 10, ifp) == 10) {
+ for (i=0; i < 10; i+=2) {
+ todo[i] = iten++;
+ todo[i+1] = pixel[i] << 8 | pixel[i+1];
+ buffer = pixel[i] >> 2 | buffer << 6;
+ }
+ for ( ; i < 16; i+=2) {
+ todo[i] = isix++;
+ todo[i+1] = buffer >> (14-i)*5;
+ }
+ for (i=0; i < 16; i+=2) {
+ row = todo[i] / raw_width - top_margin;
+ col = todo[i] % raw_width - left_margin;
+ if (row < height && col < width)
+ BAYER(row,col) = (todo[i+1] & 0x3ff);
+ }
+ }
+ maximum = 0x3ff;
+}
+
+void CLASS phase_one_load_raw()
+{
+ int row, col, a, b;
+ ushort *pixel, akey, bkey, tqmask;
+
+ fseek (ifp, nikon_curve_offset, SEEK_SET);
+ akey = get2();
+ bkey = get2();
+ tqmask = tiff_data_compression == 1 ? 0x5555:0x1354;
+ fseek (ifp, data_offset + top_margin*raw_width*2, SEEK_SET);
+ pixel = calloc (raw_width, sizeof *pixel);
+ merror (pixel, "phase_one_load_raw()");
+ for (row=0; row < height; row++) {
+ read_shorts (pixel, raw_width);
+ for (col=0; col < raw_width; col+=2) {
+ a = pixel[col+0] ^ akey;
+ b = pixel[col+1] ^ bkey;
+ pixel[col+0] = (a & tqmask) | (b & ~tqmask);
+ pixel[col+1] = (b & tqmask) | (a & ~tqmask);
+ }
+ for (col=0; col < width; col++)
+ BAYER(row,col) = pixel[col+left_margin];
+ }
+ free (pixel);
+ maximum = 0xffff;
+}
+
+unsigned CLASS ph1_bits (int nbits)
+{
+ static UINT64 bitbuf=0;
+ static int vbits=0;
+
+ if (nbits == 0)
+ return bitbuf = vbits = 0;
+ if (vbits < nbits) {
+ bitbuf = bitbuf << 32 | (unsigned) get4();
+ vbits += 32;
+ }
+ vbits -= nbits;
+ return bitbuf << (64 - nbits - vbits) >> (64 - nbits);
+}
+
+void CLASS phase_one_load_raw_c()
+{
+ static const int length[] = { 8,7,6,9,11,10,5,12,14,13 };
+ int len[2], pred[2], row, col, ncols, i, j;
+ ushort *pixel;
+
+ ncols = (raw_width + 7) & -8;
+ pixel = calloc (ncols, sizeof *pixel);
+ merror (pixel, "phase_one_load_raw_c()");
+ for (row=0; row < raw_height; row++) {
+ ph1_bits(0);
+ pred[0] = pred[1] = 0;
+ for (col=0; col < ncols; col++) {
+ if (col >= (raw_width & -8))
+ len[0] = len[1] = 14;
+ else if ((col & 7) == 0)
+ for (i=0; i < 2; i++) {
+ for (j=0; j < 5 && !ph1_bits(1); j++);
+ if (j--) len[i] = length[j*2 + ph1_bits(1)];
+ }
+ if ((i = len[col & 1]) == 14)
+ pixel[col] = pred[col & 1] = ph1_bits(16);
+ else
+ pixel[col] = pred[col & 1] += ph1_bits(i) + 1 - (1 << (i - 1));
+ }
+ if ((unsigned) (row-top_margin) < height)
+ for (col=0; col < width; col++)
+ BAYER(row-top_margin,col) = pixel[col+left_margin];
+ }
+ free (pixel);
+ maximum = 0x3fff;
+}
+
+void CLASS leaf_load_raw()
+{
+ ushort *pixel;
+ int r, c, row, col;
+
+ pixel = calloc (raw_width, sizeof *pixel);
+ merror (pixel, "leaf_load_raw()");
+ for (r=0; r < height-32; r+=32)
+ FORC3 for (row=r; row < r+32; row++) {
+ read_shorts (pixel, raw_width);
+ for (col=0; col < width; col++)
+ image[row*width+col][c] = pixel[col];
+ }
+ free (pixel);
+}
+
+/* Here raw_width is in bytes, not pixels. */
+void CLASS packed_12_load_raw()
+{
+ int row, col;
+
+ getbits(-1);
+ for (row=0; row < height; row++) {
+ for (col=0; col < width; col++)
+ BAYER(row,col) = getbits(12);
+ for (col = width*3/2; col < raw_width; col++)
+ getbits(8);
+ }
+}
+
+void CLASS unpacked_load_raw()
+{
+ ushort *pixel;
+ int row, col;
+
+ pixel = calloc (raw_width, sizeof *pixel);
+ merror (pixel, "unpacked_load_raw()");
+ for (row=0; row < height; row++) {
+ read_shorts (pixel, raw_width);
+ for (col=0; col < width; col++)
+ BAYER(row,col) = pixel[col];
+ }
+ free (pixel);
+}
+
+void CLASS olympus_e300_load_raw()
+{
+ uchar *data, *dp;
+ ushort *pixel, *pix;
+ int dwide, row, col;
+
+ dwide = raw_width * 16 / 10;
+ data = malloc (dwide + raw_width*2);
+ merror (data, "olympus_e300_load_raw()");
+ pixel = (ushort *) (data + dwide);
+ for (row=0; row < height; row++) {
+ fread (data, 1, dwide, ifp);
+ for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=3, pix+=2) {
+ if (((dp-data) & 15) == 15) dp++;
+ pix[0] = dp[1] << 8 | dp[0];
+ pix[1] = dp[2] << 4 | dp[1] >> 4;
+ }
+ for (col=0; col < width; col++)
+ BAYER(row,col) = (pixel[col] & 0xfff);
+ for (col=width+4; col < raw_width; col++)
+ black += pixel[col] & 0xfff;
+ }
+ black /= (raw_width - width - 4) * height;
+ free (data);
+}
+
+void CLASS olympus_cseries_load_raw()
+{
+ int irow, row, col;
+
+ for (irow=0; irow < height; irow++) {
+ row = irow * 2 % height + irow / (height/2);
+ if (row < 2) {
+ fseek (ifp, data_offset - row*(-width*height*3/4 & -2048), SEEK_SET);
+ getbits(-1);
+ }
+ for (col=0; col < width; col++)
+ BAYER(row,col) = getbits(12);
+ }
+}
+
+void CLASS minolta_rd175_load_raw()
+{
+ uchar pixel[768];
+ unsigned irow, box, row, col;
+
+ for (irow=0; irow < 1481; irow++) {
+ fread (pixel, 1, 768, ifp);
+ box = irow / 82;
+ row = irow % 82 * 12 + ((box < 12) ? box | 1 : (box-12)*2);
+ switch (irow) {
+ case 1477: case 1479: continue;
+ case 1476: row = 984; break;
+ case 1480: row = 985; break;
+ case 1478: row = 985; box = 1;
+ }
+ if ((box < 12) && (box & 1)) {
+ for (col=0; col < 1533; col++, row ^= 1)
+ if (col != 1) BAYER(row,col) = (col+1) & 2 ?
+ pixel[col/2-1] + pixel[col/2+1] : pixel[col/2] << 1;
+ BAYER(row,1) = pixel[1] << 1;
+ BAYER(row,1533) = pixel[765] << 1;
+ } else
+ for (col=row & 1; col < 1534; col+=2)
+ BAYER(row,col) = pixel[col/2] << 1;
+ }
+ maximum = 0xff << 1;
+}
+
+void CLASS eight_bit_load_raw()
+{
+ uchar *pixel;
+ int row, col;
+
+ pixel = calloc (raw_width, sizeof *pixel);
+ merror (pixel, "eight_bit_load_raw()");
+ for (row=0; row < height; row++) {
+ fread (pixel, 1, raw_width, ifp);
+ for (col=0; col < width; col++)
+ BAYER(row,col) = pixel[col];
+ }
+ free (pixel);
+ maximum = 0xff;
+}
+
+void CLASS casio_qv5700_load_raw()
+{
+ uchar data[3232], *dp;
+ ushort pixel[2576], *pix;
+ int row, col;
+
+ for (row=0; row < height; row++) {
+ fread (data, 1, 3232, ifp);
+ for (dp=data, pix=pixel; dp < data+3220; dp+=5, pix+=4) {
+ pix[0] = (dp[0] << 2) + (dp[1] >> 6);
+ pix[1] = (dp[1] << 4) + (dp[2] >> 4);
+ pix[2] = (dp[2] << 6) + (dp[3] >> 2);
+ pix[3] = (dp[3] << 8) + (dp[4] );
+ }
+ for (col=0; col < width; col++)
+ BAYER(row,col) = (pixel[col] & 0x3ff);
+ }
+ maximum = 0x3fc;
+}
+
+void CLASS nucore_load_raw()
+{
+ ushort *pixel;
+ int irow, row, col;
+
+ pixel = calloc (width, 2);
+ merror (pixel, "nucore_load_raw()");
+ for (irow=0; irow < height; irow++) {
+ read_shorts (pixel, width);
+ row = irow/2 + height/2 * (irow & 1);
+ for (col=0; col < width; col++)
+ BAYER(row,col) = pixel[col];
+ }
+ free (pixel);
+}
+
+const int * CLASS make_decoder_int (const int *source, int level)
+{
+ struct decode *cur;
+
+ cur = free_decode++;
+ if (level < source[0]) {
+ cur->branch[0] = free_decode;
+ source = make_decoder_int (source, level+1);
+ cur->branch[1] = free_decode;
+ source = make_decoder_int (source, level+1);
+ } else {
+ cur->leaf = source[1];
+ source += 2;
+ }
+ return source;
+}
+
+int CLASS radc_token (int tree)
+{
+ int t;
+ static struct decode *dstart[18], *dindex;
+ static const int *s, source[] = {
+ 1,1, 2,3, 3,4, 4,2, 5,7, 6,5, 7,6, 7,8,
+ 1,0, 2,1, 3,3, 4,4, 5,2, 6,7, 7,6, 8,5, 8,8,
+ 2,1, 2,3, 3,0, 3,2, 3,4, 4,6, 5,5, 6,7, 6,8,
+ 2,0, 2,1, 2,3, 3,2, 4,4, 5,6, 6,7, 7,5, 7,8,
+ 2,1, 2,4, 3,0, 3,2, 3,3, 4,7, 5,5, 6,6, 6,8,
+ 2,3, 3,1, 3,2, 3,4, 3,5, 3,6, 4,7, 5,0, 5,8,
+ 2,3, 2,6, 3,0, 3,1, 4,4, 4,5, 4,7, 5,2, 5,8,
+ 2,4, 2,7, 3,3, 3,6, 4,1, 4,2, 4,5, 5,0, 5,8,
+ 2,6, 3,1, 3,3, 3,5, 3,7, 3,8, 4,0, 5,2, 5,4,
+ 2,0, 2,1, 3,2, 3,3, 4,4, 4,5, 5,6, 5,7, 4,8,
+ 1,0, 2,2, 2,-2,
+ 1,-3, 1,3,
+ 2,-17, 2,-5, 2,5, 2,17,
+ 2,-7, 2,2, 2,9, 2,18,
+ 2,-18, 2,-9, 2,-2, 2,7,
+ 2,-28, 2,28, 3,-49, 3,-9, 3,9, 4,49, 5,-79, 5,79,
+ 2,-1, 2,13, 2,26, 3,39, 4,-16, 5,55, 6,-37, 6,76,
+ 2,-26, 2,-13, 2,1, 3,-39, 4,16, 5,-55, 6,-76, 6,37
+ };
+
+ if (free_decode == first_decode)
+ for (s=source, t=0; t < 18; t++) {
+ dstart[t] = free_decode;
+ s = make_decoder_int (s, 0);
+ }
+ if (tree == 18) {
+ if (kodak_cbpp == 243)
+ return (getbits(6) << 2) + 2; /* most DC50 photos */
+ else
+ return (getbits(5) << 3) + 4; /* DC40, Fotoman Pixtura */
+ }
+ for (dindex = dstart[tree]; dindex->branch[0]; )
+ dindex = dindex->branch[getbits(1)];
+ return dindex->leaf;
+}
+
+#define FORYX for (y=1; y < 3; y++) for (x=col+1; x >= col; x--)
+
+#define PREDICTOR (c ? (buf[c][y-1][x] + buf[c][y][x+1]) / 2 \
+: (buf[c][y-1][x+1] + 2*buf[c][y-1][x] + buf[c][y][x+1]) / 4)
+
+void CLASS kodak_radc_load_raw()
+{
+ int row, col, tree, nreps, rep, step, i, c, s, r, x, y, val;
+ short last[3] = { 16,16,16 }, mul[3], buf[3][3][386];
+
+ init_decoder();
+ getbits(-1);
+ for (i=0; i < sizeof(buf)/sizeof(short); i++)
+ buf[0][0][i] = 2048;
+ for (row=0; row < height; row+=4) {
+ FORC3 mul[c] = getbits(6);
+ FORC3 {
+ val = ((0x1000000/last[c] + 0x7ff) >> 12) * mul[c];
+ s = val > 65564 ? 10:12;
+ x = ~(-1 << (s-1));
+ val <<= 12-s;
+ for (i=0; i < sizeof(buf[0])/sizeof(short); i++)
+ buf[c][0][i] = (buf[c][0][i] * val + x) >> s;
+ last[c] = mul[c];
+ for (r=0; r <= !c; r++) {
+ buf[c][1][width/2] = buf[c][2][width/2] = mul[c] << 7;
+ for (tree=1, col=width/2; col > 0; ) {
+ if ((tree = radc_token(tree))) {
+ col -= 2;
+ if (tree == 8)
+ FORYX buf[c][y][x] = radc_token(tree+10) * mul[c];
+ else
+ FORYX buf[c][y][x] = radc_token(tree+10) * 16 + PREDICTOR;
+ } else
+ do {
+ nreps = (col > 2) ? radc_token(9) + 1 : 1;
+ for (rep=0; rep < 8 && rep < nreps && col > 0; rep++) {
+ col -= 2;
+ FORYX buf[c][y][x] = PREDICTOR;
+ if (rep & 1) {
+ step = radc_token(10) << 4;
+ FORYX buf[c][y][x] += step;
+ }
+ }
+ } while (nreps == 9);
+ }
+ for (y=0; y < 2; y++)
+ for (x=0; x < width/2; x++) {
+ val = (buf[c][y+1][x] << 4) / mul[c];
+ if (val < 0) val = 0;
+ if (c)
+ BAYER(row+y*2+c-1,x*2+2-c) = val;
+ else
+ BAYER(row+r*2+y,x*2+y) = val;
+ }
+ memcpy (buf[c][0]+!c, buf[c][2], sizeof buf[c][0]-2*!c);
+ }
+ }
+ for (y=row; y < row+4; y++)
+ for (x=0; x < width; x++)
+ if ((x+y) & 1) {
+ val = (BAYER(y,x)-2048)*2 + (BAYER(y,x-1)+BAYER(y,x+1))/2;
+ if (val < 0) val = 0;
+ BAYER(y,x) = val;
+ }
+ }
+ maximum = 10000;
+}
+
+#undef FORYX
+#undef PREDICTOR
+
+#ifdef NO_JPEG
+void CLASS kodak_jpeg_load_raw() {}
+#else
+
+METHODDEF(boolean)
+fill_input_buffer (j_decompress_ptr cinfo)
+{
+ static uchar jpeg_buffer[4096];
+ size_t nbytes;
+
+ nbytes = fread (jpeg_buffer, 1, 4096, ifp);
+ swab (jpeg_buffer, jpeg_buffer, nbytes);
+ cinfo->src->next_input_byte = jpeg_buffer;
+ cinfo->src->bytes_in_buffer = nbytes;
+ return TRUE;
+}
+
+void CLASS kodak_jpeg_load_raw()
+{
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ JSAMPARRAY buf;
+ JSAMPLE (*pixel)[3];
+ int row, col;
+
+ cinfo.err = jpeg_std_error (&jerr);
+ jpeg_create_decompress (&cinfo);
+ jpeg_stdio_src (&cinfo, ifp);
+ cinfo.src->fill_input_buffer = fill_input_buffer;
+ jpeg_read_header (&cinfo, TRUE);
+ jpeg_start_decompress (&cinfo);
+ if ((cinfo.output_width != width ) ||
+ (cinfo.output_height*2 != height ) ||
+ (cinfo.output_components != 3 )) {
+ fprintf (stderr, "%s: incorrect JPEG dimensions\n", ifname);
+ jpeg_destroy_decompress (&cinfo);
+ longjmp (failure, 3);
+ }
+ buf = (*cinfo.mem->alloc_sarray)
+ ((j_common_ptr) &cinfo, JPOOL_IMAGE, width*3, 1);
+
+ while (cinfo.output_scanline < cinfo.output_height) {
+ row = cinfo.output_scanline * 2;
+ jpeg_read_scanlines (&cinfo, buf, 1);
+ pixel = (void *) buf[0];
+ for (col=0; col < width; col+=2) {
+ BAYER(row+0,col+0) = pixel[col+0][1] << 1;
+ BAYER(row+1,col+1) = pixel[col+1][1] << 1;
+ BAYER(row+0,col+1) = pixel[col][0] + pixel[col+1][0];
+ BAYER(row+1,col+0) = pixel[col][2] + pixel[col+1][2];
+ }
+ }
+ jpeg_finish_decompress (&cinfo);
+ jpeg_destroy_decompress (&cinfo);
+ maximum = 0xff << 1;
+}
+
+#endif
+
+void CLASS kodak_dc120_load_raw()
+{
+ static const int mul[4] = { 162, 192, 187, 92 };
+ static const int add[4] = { 0, 636, 424, 212 };
+ uchar pixel[848];
+ int row, shift, col;
+
+ for (row=0; row < height; row++) {
+ fread (pixel, 848, 1, ifp);
+ shift = row * mul[row & 3] + add[row & 3];
+ for (col=0; col < width; col++)
+ BAYER(row,col) = (ushort) pixel[(col + shift) % 848];
+ }
+ maximum = 0xff;
+}
+
+void CLASS kodak_easy_load_raw()
+{
+ uchar *pixel;
+ unsigned row, col, icol;
+
+ if (raw_width > width)
+ black = 0;
+ pixel = calloc (raw_width, sizeof *pixel);
+ merror (pixel, "kodak_easy_load_raw()");
+ for (row=0; row < height; row++) {
+ fread (pixel, 1, raw_width, ifp);
+ for (col=0; col < raw_width; col++) {
+ icol = col - left_margin;
+ if (icol < width)
+ BAYER(row,icol) = (ushort) curve[pixel[col]];
+ else
+ black += curve[pixel[col]];
+ }
+ }
+ free (pixel);
+ if (raw_width > width)
+ black /= (raw_width - width) * height;
+ if (!strncmp(model,"DC2",3))
+ black = 0;
+ maximum = curve[0xff];
+}
+
+void CLASS kodak_compressed_load_raw()
+{
+ uchar c, blen[256];
+ ushort raw[6];
+ unsigned row, col, len, save, i, israw=0, bits=0, pred[2];
+ INT64 bitbuf=0;
+ int diff;
+
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col++)
+ {
+ if ((col & 255) == 0) { /* Get the bit-lengths of the */
+ len = width - col; /* next 256 pixel values */
+ if (len > 256) len = 256;
+ save = ftell(ifp);
+ for (israw=i=0; i < len; i+=2) {
+ c = fgetc(ifp);
+ if ((blen[i+0] = c & 15) > 12 ||
+ (blen[i+1] = c >> 4) > 12 )
+ israw = 1;
+ }
+ bitbuf = bits = pred[0] = pred[1] = 0;
+ if (len % 8 == 4) {
+ bitbuf = fgetc(ifp) << 8;
+ bitbuf += fgetc(ifp);
+ bits = 16;
+ }
+ if (israw)
+ fseek (ifp, save, SEEK_SET);
+ }
+ if (israw) { /* If the data is not compressed */
+ switch (col & 7) {
+ case 0:
+ read_shorts (raw, 6);
+ diff = raw[0] >> 12 << 8 | raw[2] >> 12 << 4 | raw[4] >> 12;
+ break;
+ case 1:
+ diff = raw[1] >> 12 << 8 | raw[3] >> 12 << 4 | raw[5] >> 12;
+ break;
+ default:
+ diff = raw[(col & 7) - 2] & 0xfff;
+ }
+ } else { /* If the data is compressed */
+ len = blen[col & 255]; /* Number of bits for this pixel */
+ if (bits < len) { /* Got enough bits in the buffer? */
+ for (i=0; i < 32; i+=8)
+ bitbuf += (INT64) fgetc(ifp) << (bits+(i^8));
+ bits += 32;
+ }
+ diff = bitbuf & (0xffff >> (16-len)); /* Pull bits from buffer */
+ bitbuf >>= len;
+ bits -= len;
+ if ((diff & (1 << (len-1))) == 0)
+ diff -= (1 << len) - 1;
+ pred[col & 1] += diff;
+ diff = pred[col & 1];
+ }
+ BAYER(row,col) = curve[diff];
+ }
+}
+
+void CLASS kodak_yuv_load_raw()
+{
+ uchar c, blen[384];
+ unsigned row, col, len, bits=0;
+ INT64 bitbuf=0;
+ int i, li=0, si, diff, six[6], y[4], cb=0, cr=0, rgb[3];
+ ushort *ip;
+
+ for (row=0; row < height; row+=2)
+ for (col=0; col < width; col+=2) {
+ if ((col & 127) == 0) {
+ len = (width - col + 1) * 3 & -4;
+ if (len > 384) len = 384;
+ for (i=0; i < len; ) {
+ c = fgetc(ifp);
+ blen[i++] = c & 15;
+ blen[i++] = c >> 4;
+ }
+ li = bitbuf = bits = y[1] = y[3] = cb = cr = 0;
+ if (len % 8 == 4) {
+ bitbuf = fgetc(ifp) << 8;
+ bitbuf += fgetc(ifp);
+ bits = 16;
+ }
+ }
+ for (si=0; si < 6; si++) {
+ len = blen[li++];
+ if (bits < len) {
+ for (i=0; i < 32; i+=8)
+ bitbuf += (INT64) fgetc(ifp) << (bits+(i^8));
+ bits += 32;
+ }
+ diff = bitbuf & (0xffff >> (16-len));
+ bitbuf >>= len;
+ bits -= len;
+ if ((diff & (1 << (len-1))) == 0)
+ diff -= (1 << len) - 1;
+ six[si] = diff;
+ }
+ y[0] = six[0] + y[1];
+ y[1] = six[1] + y[0];
+ y[2] = six[2] + y[3];
+ y[3] = six[3] + y[2];
+ cb += six[4];
+ cr += six[5];
+ for (i=0; i < 4; i++) {
+ ip = image[(row+(i >> 1))*width + col+(i & 1)];
+ rgb[0] = y[i] + cr;
+ rgb[1] = y[i];
+ rgb[2] = y[i] + cb;
+ FORC3 if (rgb[c] > 0) ip[c] = curve[rgb[c]];
+ }
+ }
+}
+
+void CLASS sony_decrypt (unsigned *data, int len, int start, int key)
+{
+ static unsigned pad[128], p;
+
+ if (start) {
+ for (p=0; p < 4; p++)
+ pad[p] = key = key * 48828125 + 1;
+ pad[3] = pad[3] << 1 | (pad[0]^pad[2]) >> 31;
+ for (p=4; p < 127; p++)
+ pad[p] = (pad[p-4]^pad[p-2]) << 1 | (pad[p-3]^pad[p-1]) >> 31;
+ for (p=0; p < 127; p++)
+ pad[p] = htonl(pad[p]);
+ }
+ while (len--)
+ *data++ ^= pad[p++ & 127] = pad[(p+1) & 127] ^ pad[(p+65) & 127];
+}
+
+void CLASS sony_load_raw()
+{
+ uchar head[40];
+ ushort *pixel;
+ unsigned i, key, row, col;
+
+ fseek (ifp, 200896, SEEK_SET);
+ fseek (ifp, (unsigned) fgetc(ifp)*4 - 1, SEEK_CUR);
+ order = 0x4d4d;
+ key = get4();
+ fseek (ifp, 164600, SEEK_SET);
+ fread (head, 1, 40, ifp);
+ sony_decrypt ((void *) head, 10, 1, key);
+ for (i=26; i-- > 22; )
+ key = key << 8 | head[i];
+ fseek (ifp, data_offset, SEEK_SET);
+ pixel = calloc (raw_width, sizeof *pixel);
+ merror (pixel, "sony_load_raw()");
+ for (row=0; row < height; row++) {
+ fread (pixel, 2, raw_width, ifp);
+ sony_decrypt ((void *) pixel, raw_width/2, !row, key);
+ for (col=9; col < left_margin; col++)
+ black += ntohs(pixel[col]);
+ for (col=0; col < width; col++)
+ BAYER(row,col) = ntohs(pixel[col+left_margin]);
+ }
+ free (pixel);
+ if (left_margin > 9)
+ black /= (left_margin-9) * height;
+ maximum = 0x3ff0;
+}
+
+#define HOLE(row) ((holes >> (((row) - raw_height) & 7)) & 1)
+
+/* Kudos to Rich Taylor for figuring out SMaL's compression algorithm. */
+void CLASS smal_decode_segment (unsigned seg[2][2], int holes)
+{
+ uchar hist[3][13] = {
+ { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 },
+ { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 },
+ { 3, 3, 0, 0, 63, 47, 31, 15, 0 } };
+ int low, high=0xff, carry=0, nbits=8;
+ int s, count, bin, next, i, sym[3];
+ uchar diff, pred[]={0,0};
+ ushort data=0, range=0;
+ unsigned pix, row, col;
+
+ fseek (ifp, seg[0][1]+1, SEEK_SET);
+ getbits(-1);
+ for (pix=seg[0][0]; pix < seg[1][0]; pix++) {
+ for (s=0; s < 3; s++) {
+ data = data << nbits | getbits(nbits);
+ if (carry < 0)
+ carry = (nbits += carry+1) < 1 ? nbits-1 : 0;
+ while (--nbits >= 0)
+ if ((data >> nbits & 0xff) == 0xff) break;
+ if (nbits > 0)
+ data = ((data & ((1 << (nbits-1)) - 1)) << 1) |
+ ((data + (((data & (1 << (nbits-1)))) << 1)) & (-1 << nbits));
+ if (nbits >= 0) {
+ data += getbits(1);
+ carry = nbits - 8;
+ }
+ count = ((((data-range+1) & 0xffff) << 2) - 1) / (high >> 4);
+ for (bin=0; hist[s][bin+5] > count; bin++);
+ low = hist[s][bin+5] * (high >> 4) >> 2;
+ if (bin) high = hist[s][bin+4] * (high >> 4) >> 2;
+ high -= low;
+ for (nbits=0; high << nbits < 128; nbits++);
+ range = (range+low) << nbits;
+ high <<= nbits;
+ next = hist[s][1];
+ if (++hist[s][2] > hist[s][3]) {
+ next = (next+1) & hist[s][0];
+ hist[s][3] = (hist[s][next+4] - hist[s][next+5]) >> 2;
+ hist[s][2] = 1;
+ }
+ if (hist[s][hist[s][1]+4] - hist[s][hist[s][1]+5] > 1) {
+ if (bin < hist[s][1])
+ for (i=bin; i < hist[s][1]; i++) hist[s][i+5]--;
+ else if (next <= bin)
+ for (i=hist[s][1]; i < bin; i++) hist[s][i+5]++;
+ }
+ hist[s][1] = next;
+ sym[s] = bin;
+ }
+ diff = sym[2] << 5 | sym[1] << 2 | (sym[0] & 3);
+ if (sym[0] & 4)
+ diff = diff ? -diff : 0x80;
+ if (ftell(ifp) + 12 >= seg[1][1])
+ diff = 0;
+ pred[pix & 1] += diff;
+ row = pix / raw_width - top_margin;
+ col = pix % raw_width - left_margin;
+ if (row < height && col < width)
+ BAYER(row,col) = pred[pix & 1];
+ if (!(pix & 1) && HOLE(row)) pix += 2;
+ }
+ maximum = 0xff;
+}
+
+void CLASS smal_v6_load_raw()
+{
+ unsigned seg[2][2];
+
+ fseek (ifp, 16, SEEK_SET);
+ seg[0][0] = 0;
+ seg[0][1] = get2();
+ seg[1][0] = raw_width * raw_height;
+ seg[1][1] = INT_MAX;
+ smal_decode_segment (seg, 0);
+ use_gamma = 0;
+}
+
+int CLASS median4 (int *p)
+{
+ int min, max, sum, i;
+
+ min = max = sum = p[0];
+ for (i=1; i < 4; i++) {
+ sum += p[i];
+ if (min > p[i]) min = p[i];
+ if (max < p[i]) max = p[i];
+ }
+ return (sum - min - max) >> 1;
+}
+
+void CLASS fill_holes (int holes)
+{
+ int row, col, val[4];
+
+ for (row=2; row < height-2; row++) {
+ if (!HOLE(row)) continue;
+ for (col=1; col < width-1; col+=4) {
+ val[0] = BAYER(row-1,col-1);
+ val[1] = BAYER(row-1,col+1);
+ val[2] = BAYER(row+1,col-1);
+ val[3] = BAYER(row+1,col+1);
+ BAYER(row,col) = median4(val);
+ }
+ for (col=2; col < width-2; col+=4)
+ if (HOLE(row-2) || HOLE(row+2))
+ BAYER(row,col) = (BAYER(row,col-2) + BAYER(row,col+2)) >> 1;
+ else {
+ val[0] = BAYER(row,col-2);
+ val[1] = BAYER(row,col+2);
+ val[2] = BAYER(row-2,col);
+ val[3] = BAYER(row+2,col);
+ BAYER(row,col) = median4(val);
+ }
+ }
+}
+
+void CLASS smal_v9_load_raw()
+{
+ unsigned seg[256][2], offset, nseg, holes, i;
+
+ fseek (ifp, 67, SEEK_SET);
+ offset = get4();
+ nseg = fgetc(ifp);
+ fseek (ifp, offset, SEEK_SET);
+ for (i=0; i < nseg*2; i++)
+ seg[0][i] = get4() + data_offset*(i & 1);
+ fseek (ifp, 78, SEEK_SET);
+ holes = fgetc(ifp);
+ fseek (ifp, 88, SEEK_SET);
+ seg[nseg][0] = raw_height * raw_width;
+ seg[nseg][1] = get4() + data_offset;
+ for (i=0; i < nseg; i++)
+ smal_decode_segment (seg+i, holes);
+ if (holes) fill_holes (holes);
+}
+
+/* BEGIN GPL BLOCK */
+
+void CLASS foveon_decoder (unsigned huff[1024], unsigned code)
+{
+ struct decode *cur;
+ int i, len;
+
+ cur = free_decode++;
+ if (free_decode > first_decode+2048) {
+ fprintf (stderr, "%s: decoder table overflow\n", ifname);
+ longjmp (failure, 2);
+ }
+ if (code)
+ for (i=0; i < 1024; i++)
+ if (huff[i] == code) {
+ cur->leaf = i;
+ return;
+ }
+ if ((len = code >> 27) > 26) return;
+ code = (len+1) << 27 | (code & 0x3ffffff) << 1;
+
+ cur->branch[0] = free_decode;
+ foveon_decoder (huff, code);
+ cur->branch[1] = free_decode;
+ foveon_decoder (huff, code+1);
+}
+
+void CLASS foveon_load_camf()
+{
+ unsigned key, i, val;
+
+ fseek (ifp, meta_offset, SEEK_SET);
+ key = get4();
+ fread (meta_data, 1, meta_length, ifp);
+ for (i=0; i < meta_length; i++) {
+ key = (key * 1597 + 51749) % 244944;
+ val = key * (INT64) 301593171 >> 24;
+ meta_data[i] ^= ((((key << 8) - val) >> 1) + val) >> 17;
+ }
+}
+
+void CLASS foveon_load_raw()
+{
+ struct decode *dindex;
+ short diff[1024], pred[3];
+ unsigned huff[1024], bitbuf=0;
+ int fixed, row, col, bit=-1, c, i;
+
+ fixed = get4();
+ read_shorts ((ushort *) diff, 1024);
+ if (!fixed) {
+ for (i=0; i < 1024; i++)
+ huff[i] = get4();
+ init_decoder();
+ foveon_decoder (huff, 0);
+ }
+ for (row=0; row < height; row++) {
+ memset (pred, 0, sizeof pred);
+ if (!bit && !fixed) get4();
+ for (col=bit=0; col < width; col++) {
+ if (fixed) {
+ bitbuf = get4();
+ FORC3 pred[2-c] += diff[bitbuf >> c*10 & 0x3ff];
+ }
+ else FORC3 {
+ for (dindex=first_decode; dindex->branch[0]; ) {
+ if ((bit = (bit-1) & 31) == 31)
+ for (i=0; i < 4; i++)
+ bitbuf = (bitbuf << 8) + fgetc(ifp);
+ dindex = dindex->branch[bitbuf >> bit & 1];
+ }
+ pred[c] += diff[dindex->leaf];
+ }
+ FORC3 image[row*width+col][c] = pred[c];
+ }
+ }
+ foveon_load_camf();
+ maximum = clip_max = 0xffff;
+}
+
+char * CLASS foveon_camf_param (char *block, char *param)
+{
+ unsigned idx, num;
+ char *pos, *cp, *dp;
+
+ for (idx=0; idx < meta_length; idx += sget4(pos+8)) {
+ pos = meta_data + idx;
+ if (strncmp (pos, "CMb", 3)) break;
+ if (pos[3] != 'P') continue;
+ if (strcmp (block, pos+sget4(pos+12))) continue;
+ cp = pos + sget4(pos+16);
+ num = sget4(cp);
+ dp = pos + sget4(cp+4);
+ while (num--) {
+ cp += 8;
+ if (!strcmp (param, dp+sget4(cp)))
+ return dp+sget4(cp+4);
+ }
+ }
+ return NULL;
+}
+
+void * CLASS foveon_camf_matrix (int dim[3], char *name)
+{
+ unsigned i, idx, type, ndim, size, *mat;
+ char *pos, *cp, *dp;
+
+ for (idx=0; idx < meta_length; idx += sget4(pos+8)) {
+ pos = meta_data + idx;
+ if (strncmp (pos, "CMb", 3)) break;
+ if (pos[3] != 'M') continue;
+ if (strcmp (name, pos+sget4(pos+12))) continue;
+ dim[0] = dim[1] = dim[2] = 1;
+ cp = pos + sget4(pos+16);
+ type = sget4(cp);
+ if ((ndim = sget4(cp+4)) > 3) break;
+ dp = pos + sget4(cp+8);
+ for (i=ndim; i--; ) {
+ cp += 12;
+ dim[i] = sget4(cp);
+ }
+ if ((size = dim[0]*dim[1]*dim[2]) > meta_length/4) break;
+ mat = malloc (size * 4);
+ merror (mat, "foveon_camf_matrix()");
+ for (i=0; i < size; i++)
+ if (type && type != 6)
+ mat[i] = sget4(dp + i*4);
+ else
+ mat[i] = sget4(dp + i*2) & 0xffff;
+ return mat;
+ }
+ fprintf (stderr, "%s: \"%s\" matrix not found!\n", ifname, name);
+ return NULL;
+}
+
+int CLASS foveon_fixed (void *ptr, int size, char *name)
+{
+ void *dp;
+ int dim[3];
+
+ dp = foveon_camf_matrix (dim, name);
+ if (!dp) return 0;
+ memcpy (ptr, dp, size*4);
+ free (dp);
+ return 1;
+}
+
+float CLASS foveon_avg (short *pix, int range[2], float cfilt)
+{
+ int i;
+ float val, min=FLT_MAX, max=-FLT_MAX, sum=0;
+
+ for (i=range[0]; i <= range[1]; i++) {
+ sum += val = pix[i*4] + (pix[i*4]-pix[(i-1)*4]) * cfilt;
+ if (min > val) min = val;
+ if (max < val) max = val;
+ }
+ return (sum - min - max) / (range[1] - range[0] - 1);
+}
+
+short * CLASS foveon_make_curve (double max, double mul, double filt)
+{
+ short *curve;
+ int i, size;
+ double x;
+
+ if (!filt) filt = 0.8;
+ size = 4*M_PI*max / filt;
+ curve = calloc (size+1, sizeof *curve);
+ merror (curve, "foveon_make_curve()");
+ curve[0] = size;
+ for (i=0; i < size; i++) {
+ x = i*filt/max/4;
+ curve[i+1] = (cos(x)+1)/2 * tanh(i*filt/mul) * mul + 0.5;
+ }
+ return curve;
+}
+
+void CLASS foveon_make_curves
+ (short **curvep, float dq[3], float div[3], float filt)
+{
+ double mul[3], max=0;
+ int c;
+
+ FORC3 mul[c] = dq[c]/div[c];
+ FORC3 if (max < mul[c]) max = mul[c];
+ FORC3 curvep[c] = foveon_make_curve (max, mul[c], filt);
+}
+
+int CLASS foveon_apply_curve (short *curve, int i)
+{
+ if (abs(i) >= curve[0]) return 0;
+ return i < 0 ? -curve[1-i] : curve[1+i];
+}
+
+#define image ((short (*)[4]) image)
+
+void CLASS foveon_interpolate()
+{
+ static const short hood[] = { -1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1 };
+ short *pix, prev[3], *curve[8], (*shrink)[3];
+ float cfilt=0, ddft[3][3][2], ppm[3][3][3];
+ float cam_xyz[3][3], correct[3][3], last[3][3], trans[3][3];
+ float chroma_dq[3], color_dq[3], diag[3][3], div[3];
+ float (*black)[3], (*sgain)[3], (*sgrow)[3];
+ float fsum[3], val, frow, num;
+ int row, col, c, i, j, diff, sgx, irow, sum, min, max, limit;
+ int dim[3], dscr[2][2], dstb[4], (*smrow[7])[3], total[4], ipix[3];
+ int work[3][3], smlast, smred, smred_p=0, dev[3];
+ int satlev[3], keep[4], active[4];
+ unsigned *badpix;
+ double dsum=0, trsum[3];
+ char str[128], *cp;
+
+ if (verbose)
+ fprintf (stderr, "Foveon interpolation...\n");
+
+ foveon_fixed (dscr, 4, "DarkShieldColRange");
+ foveon_fixed (ppm[0][0], 27, "PostPolyMatrix");
+ foveon_fixed (satlev, 3, "SaturationLevel");
+ foveon_fixed (keep, 4, "KeepImageArea");
+ foveon_fixed (active, 4, "ActiveImageArea");
+ foveon_fixed (chroma_dq, 3, "ChromaDQ");
+ foveon_fixed (color_dq, 3,
+ foveon_camf_param ("IncludeBlocks", "ColorDQ") ?
+ "ColorDQ" : "ColorDTQCamRGB");
+ if (foveon_camf_param ("IncludeBlocks", "ColumnFilter"))
+ foveon_fixed (&cfilt, 1, "ColumnFilter");
+
+ memset (ddft, 0, sizeof ddft);
+ if (!foveon_camf_param ("IncludeBlocks", "DarkDrift")
+ || !foveon_fixed (ddft[1][0], 12, "DarkDrift"))
+ for (i=0; i < 2; i++) {
+ foveon_fixed (dstb, 4, i ? "DarkShieldBottom":"DarkShieldTop");
+ for (row = dstb[1]; row <= dstb[3]; row++)
+ for (col = dstb[0]; col <= dstb[2]; col++)
+ FORC3 ddft[i+1][c][1] += (short) image[row*width+col][c];
+ FORC3 ddft[i+1][c][1] /= (dstb[3]-dstb[1]+1) * (dstb[2]-dstb[0]+1);
+ }
+
+ if (!(cp = foveon_camf_param ("WhiteBalanceIlluminants", model2)))
+ { fprintf (stderr, "%s: Invalid white balance \"%s\"\n", ifname, model2);
+ return; }
+ foveon_fixed (cam_xyz, 9, cp);
+ foveon_fixed (correct, 9,
+ foveon_camf_param ("WhiteBalanceCorrections", model2));
+ memset (last, 0, sizeof last);
+ for (i=0; i < 3; i++)
+ for (j=0; j < 3; j++)
+ FORC3 last[i][j] += correct[i][c] * cam_xyz[c][j];
+
+ sprintf (str, "%sRGBNeutral", model2);
+ if (foveon_camf_param ("IncludeBlocks", str))
+ foveon_fixed (div, 3, str);
+ else {
+ #define LAST(x,y) last[(i+x)%3][(c+y)%3]
+ for (i=0; i < 3; i++)
+ FORC3 diag[c][i] = LAST(1,1)*LAST(2,2) - LAST(1,2)*LAST(2,1);
+ #undef LAST
+ FORC3 div[c] = diag[c][0]*0.3127 + diag[c][1]*0.329 + diag[c][2]*0.3583;
+ }
+ num = 0;
+ FORC3 if (num < div[c]) num = div[c];
+ FORC3 div[c] /= num;
+
+ memset (trans, 0, sizeof trans);
+ for (i=0; i < 3; i++)
+ for (j=0; j < 3; j++)
+ FORC3 trans[i][j] += rgb_cam[i][c] * last[c][j] * div[j];
+ FORC3 trsum[c] = trans[c][0] + trans[c][1] + trans[c][2];
+ dsum = (6*trsum[0] + 11*trsum[1] + 3*trsum[2]) / 20;
+ for (i=0; i < 3; i++)
+ FORC3 last[i][c] = trans[i][c] * dsum / trsum[i];
+ memset (trans, 0, sizeof trans);
+ for (i=0; i < 3; i++)
+ for (j=0; j < 3; j++)
+ FORC3 trans[i][j] += (i==c ? 32 : -1) * last[c][j] / 30;
+
+ foveon_make_curves (curve, color_dq, div, cfilt);
+ FORC3 chroma_dq[c] /= 3;
+ foveon_make_curves (curve+3, chroma_dq, div, cfilt);
+ FORC3 dsum += chroma_dq[c] / div[c];
+ curve[6] = foveon_make_curve (dsum, dsum, cfilt);
+ curve[7] = foveon_make_curve (dsum*2, dsum*2, cfilt);
+
+ sgain = foveon_camf_matrix (dim, "SpatialGain");
+ if (!sgain) return;
+ sgrow = calloc (dim[1], sizeof *sgrow);
+ sgx = (width + dim[1]-2) / (dim[1]-1);
+
+ black = calloc (height, sizeof *black);
+ for (row=0; row < height; row++) {
+ for (i=0; i < 6; i++)
+ ddft[0][0][i] = ddft[1][0][i] +
+ row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]);
+ FORC3 black[row][c] =
+ ( foveon_avg (image[row*width]+c, dscr[0], cfilt) +
+ foveon_avg (image[row*width]+c, dscr[1], cfilt) * 3
+ - ddft[0][c][0] ) / 4 - ddft[0][c][1];
+ }
+ memcpy (black, black+8, sizeof *black*8);
+ memcpy (black+height-11, black+height-22, 11*sizeof *black);
+ memcpy (last, black, sizeof last);
+
+ for (row=1; row < height-1; row++) {
+ FORC3 if (last[1][c] > last[0][c]) {
+ if (last[1][c] > last[2][c])
+ black[row][c] = (last[0][c] > last[2][c]) ? last[0][c]:last[2][c];
+ } else
+ if (last[1][c] < last[2][c])
+ black[row][c] = (last[0][c] < last[2][c]) ? last[0][c]:last[2][c];
+ memmove (last, last+1, 2*sizeof last[0]);
+ memcpy (last[2], black[row+1], sizeof last[2]);
+ }
+ FORC3 black[row][c] = (last[0][c] + last[1][c])/2;
+ FORC3 black[0][c] = (black[1][c] + black[3][c])/2;
+
+ val = 1 - exp(-1/24.0);
+ memcpy (fsum, black, sizeof fsum);
+ for (row=1; row < height; row++)
+ FORC3 fsum[c] += black[row][c] =
+ (black[row][c] - black[row-1][c])*val + black[row-1][c];
+ memcpy (last[0], black[height-1], sizeof last[0]);
+ FORC3 fsum[c] /= height;
+ for (row = height; row--; )
+ FORC3 last[0][c] = black[row][c] =
+ (black[row][c] - fsum[c] - last[0][c])*val + last[0][c];
+
+ memset (total, 0, sizeof total);
+ for (row=2; row < height; row+=4)
+ for (col=2; col < width; col+=4) {
+ FORC3 total[c] += (short) image[row*width+col][c];
+ total[3]++;
+ }
+ for (row=0; row < height; row++)
+ FORC3 black[row][c] += fsum[c]/2 + total[c]/(total[3]*100.0);
+
+ for (row=0; row < height; row++) {
+ for (i=0; i < 6; i++)
+ ddft[0][0][i] = ddft[1][0][i] +
+ row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]);
+ pix = image[row*width];
+ memcpy (prev, pix, sizeof prev);
+ frow = row / (height-1.0) * (dim[2]-1);
+ if ((irow = frow) == dim[2]-1) irow--;
+ frow -= irow;
+ for (i=0; i < dim[1]; i++)
+ FORC3 sgrow[i][c] = sgain[ irow *dim[1]+i][c] * (1-frow) +
+ sgain[(irow+1)*dim[1]+i][c] * frow;
+ for (col=0; col < width; col++) {
+ FORC3 {
+ diff = pix[c] - prev[c];
+ prev[c] = pix[c];
+ ipix[c] = pix[c] + floor ((diff + (diff*diff >> 14)) * cfilt
+ - ddft[0][c][1] - ddft[0][c][0] * ((float) col/width - 0.5)
+ - black[row][c] );
+ }
+ FORC3 {
+ work[0][c] = ipix[c] * ipix[c] >> 14;
+ work[2][c] = ipix[c] * work[0][c] >> 14;
+ work[1][2-c] = ipix[(c+1) % 3] * ipix[(c+2) % 3] >> 14;
+ }
+ FORC3 {
+ for (val=i=0; i < 3; i++)
+ for ( j=0; j < 3; j++)
+ val += ppm[c][i][j] * work[i][j];
+ ipix[c] = floor ((ipix[c] + floor(val)) *
+ ( sgrow[col/sgx ][c] * (sgx - col%sgx) +
+ sgrow[col/sgx+1][c] * (col%sgx) ) / sgx / div[c]);
+ if (ipix[c] > 32000) ipix[c] = 32000;
+ pix[c] = ipix[c];
+ }
+ pix += 4;
+ }
+ }
+ free (black);
+ free (sgrow);
+ free (sgain);
+
+ if ((badpix = foveon_camf_matrix (dim, "BadPixels"))) {
+ for (i=0; i < dim[0]; i++) {
+ col = (badpix[i] >> 8 & 0xfff) - keep[0];
+ row = (badpix[i] >> 20 ) - keep[1];
+ if ((unsigned)(row-1) > height-3 || (unsigned)(col-1) > width-3)
+ continue;
+ memset (fsum, 0, sizeof fsum);
+ for (sum=j=0; j < 8; j++)
+ if (badpix[i] & (1 << j)) {
+ FORC3 fsum[c] += (short)
+ image[(row+hood[j*2])*width+col+hood[j*2+1]][c];
+ sum++;
+ }
+ if (sum) FORC3 image[row*width+col][c] = fsum[c]/sum;
+ }
+ free (badpix);
+ }
+
+ /* Array for 5x5 Gaussian averaging of red values */
+ smrow[6] = calloc (width*5, sizeof **smrow);
+ merror (smrow[6], "foveon_interpolate()");
+ for (i=0; i < 5; i++)
+ smrow[i] = smrow[6] + i*width;
+
+ /* Sharpen the reds against these Gaussian averages */
+ for (smlast=-1, row=2; row < height-2; row++) {
+ while (smlast < row+2) {
+ for (i=0; i < 6; i++)
+ smrow[(i+5) % 6] = smrow[i];
+ pix = image[++smlast*width+2];
+ for (col=2; col < width-2; col++) {
+ smrow[4][col][0] =
+ (pix[0]*6 + (pix[-4]+pix[4])*4 + pix[-8]+pix[8] + 8) >> 4;
+ pix += 4;
+ }
+ }
+ pix = image[row*width+2];
+ for (col=2; col < width-2; col++) {
+ smred = ( 6 * smrow[2][col][0]
+ + 4 * (smrow[1][col][0] + smrow[3][col][0])
+ + smrow[0][col][0] + smrow[4][col][0] + 8 ) >> 4;
+ if (col == 2)
+ smred_p = smred;
+ i = pix[0] + ((pix[0] - ((smred*7 + smred_p) >> 3)) >> 3);
+ if (i > 32000) i = 32000;
+ pix[0] = i;
+ smred_p = smred;
+ pix += 4;
+ }
+ }
+
+ /* Adjust the brighter pixels for better linearity */
+ min = 0xffff;
+ FORC3 {
+ i = satlev[c] / div[c];
+ if (min > i) min = i;
+ }
+ limit = min * 9 >> 4;
+ for (pix=image[0]; pix < image[height*width]; pix+=4) {
+ if (pix[0] <= limit || pix[1] <= limit || pix[2] <= limit)
+ continue;
+ min = max = pix[0];
+ for (c=1; c < 3; c++) {
+ if (min > pix[c]) min = pix[c];
+ if (max < pix[c]) max = pix[c];
+ }
+ if (min >= limit*2) {
+ pix[0] = pix[1] = pix[2] = max;
+ } else {
+ i = 0x4000 - ((min - limit) << 14) / limit;
+ i = 0x4000 - (i*i >> 14);
+ i = i*i >> 14;
+ FORC3 pix[c] += (max - pix[c]) * i >> 14;
+ }
+ }
+/*
+ Because photons that miss one detector often hit another,
+ the sum R+G+B is much less noisy than the individual colors.
+ So smooth the hues without smoothing the total.
+ */
+ for (smlast=-1, row=2; row < height-2; row++) {
+ while (smlast < row+2) {
+ for (i=0; i < 6; i++)
+ smrow[(i+5) % 6] = smrow[i];
+ pix = image[++smlast*width+2];
+ for (col=2; col < width-2; col++) {
+ FORC3 smrow[4][col][c] = (pix[c-4]+2*pix[c]+pix[c+4]+2) >> 2;
+ pix += 4;
+ }
+ }
+ pix = image[row*width+2];
+ for (col=2; col < width-2; col++) {
+ FORC3 dev[c] = -foveon_apply_curve (curve[7], pix[c] -
+ ((smrow[1][col][c] + 2*smrow[2][col][c] + smrow[3][col][c]) >> 2));
+ sum = (dev[0] + dev[1] + dev[2]) >> 3;
+ FORC3 pix[c] += dev[c] - sum;
+ pix += 4;
+ }
+ }
+ for (smlast=-1, row=2; row < height-2; row++) {
+ while (smlast < row+2) {
+ for (i=0; i < 6; i++)
+ smrow[(i+5) % 6] = smrow[i];
+ pix = image[++smlast*width+2];
+ for (col=2; col < width-2; col++) {
+ FORC3 smrow[4][col][c] =
+ (pix[c-8]+pix[c-4]+pix[c]+pix[c+4]+pix[c+8]+2) >> 2;
+ pix += 4;
+ }
+ }
+ pix = image[row*width+2];
+ for (col=2; col < width-2; col++) {
+ for (total[3]=375, sum=60, c=0; c < 3; c++) {
+ for (total[c]=i=0; i < 5; i++)
+ total[c] += smrow[i][col][c];
+ total[3] += total[c];
+ sum += pix[c];
+ }
+ if (sum < 0) sum = 0;
+ j = total[3] > 375 ? (sum << 16) / total[3] : sum * 174;
+ FORC3 pix[c] += foveon_apply_curve (curve[6],
+ ((j*total[c] + 0x8000) >> 16) - pix[c]);
+ pix += 4;
+ }
+ }
+
+ /* Transform the image to a different colorspace */
+ for (pix=image[0]; pix < image[height*width]; pix+=4) {
+ FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]);
+ sum = (pix[0]+pix[1]+pix[1]+pix[2]) >> 2;
+ FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]-sum);
+ FORC3 {
+ for (dsum=i=0; i < 3; i++)
+ dsum += trans[c][i] * pix[i];
+ if (dsum < 0) dsum = 0;
+ if (dsum > 24000) dsum = 24000;
+ ipix[c] = dsum + 0.5;
+ }
+ FORC3 pix[c] = ipix[c];
+ }
+
+ /* Smooth the image bottom-to-top and save at 1/4 scale */
+ shrink = calloc ((width/4) * (height/4), sizeof *shrink);
+ merror (shrink, "foveon_interpolate()");
+ for (row = height/4; row--; )
+ for (col=0; col < width/4; col++) {
+ ipix[0] = ipix[1] = ipix[2] = 0;
+ for (i=0; i < 4; i++)
+ for (j=0; j < 4; j++)
+ FORC3 ipix[c] += image[(row*4+i)*width+col*4+j][c];
+ FORC3
+ if (row+2 > height/4)
+ shrink[row*(width/4)+col][c] = ipix[c] >> 4;
+ else
+ shrink[row*(width/4)+col][c] =
+ (shrink[(row+1)*(width/4)+col][c]*1840 + ipix[c]*141 + 2048) >> 12;
+ }
+ /* From the 1/4-scale image, smooth right-to-left */
+ for (row=0; row < (height & ~3); row++) {
+ ipix[0] = ipix[1] = ipix[2] = 0;
+ if ((row & 3) == 0)
+ for (col = width & ~3 ; col--; )
+ FORC3 smrow[0][col][c] = ipix[c] =
+ (shrink[(row/4)*(width/4)+col/4][c]*1485 + ipix[c]*6707 + 4096) >> 13;
+
+ /* Then smooth left-to-right */
+ ipix[0] = ipix[1] = ipix[2] = 0;
+ for (col=0; col < (width & ~3); col++)
+ FORC3 smrow[1][col][c] = ipix[c] =
+ (smrow[0][col][c]*1485 + ipix[c]*6707 + 4096) >> 13;
+
+ /* Smooth top-to-bottom */
+ if (row == 0)
+ memcpy (smrow[2], smrow[1], sizeof **smrow * width);
+ else
+ for (col=0; col < (width & ~3); col++)
+ FORC3 smrow[2][col][c] =
+ (smrow[2][col][c]*6707 + smrow[1][col][c]*1485 + 4096) >> 13;
+
+ /* Adjust the chroma toward the smooth values */
+ for (col=0; col < (width & ~3); col++) {
+ for (i=j=30, c=0; c < 3; c++) {
+ i += smrow[2][col][c];
+ j += image[row*width+col][c];
+ }
+ j = (j << 16) / i;
+ for (sum=c=0; c < 3; c++) {
+ ipix[c] = foveon_apply_curve (curve[c+3],
+ ((smrow[2][col][c] * j + 0x8000) >> 16) - image[row*width+col][c]);
+ sum += ipix[c];
+ }
+ sum >>= 3;
+ FORC3 {
+ i = image[row*width+col][c] + ipix[c] - sum;
+ if (i < 0) i = 0;
+ image[row*width+col][c] = i;
+ }
+ }
+ }
+ free (shrink);
+ free (smrow[6]);
+ for (i=0; i < 8; i++)
+ free (curve[i]);
+
+ /* Trim off the black border */
+ active[1] -= keep[1];
+ active[3] -= 2;
+ i = active[2] - active[0];
+ for (row = 0; row < active[3]-active[1]; row++)
+ memcpy (image[row*i], image[(row+active[1])*width+active[0]],
+ i * sizeof *image);
+ width = i;
+ height = row;
+}
+#undef image
+
+/* END GPL BLOCK */
+
+/*
+ Seach from the current directory up to the root looking for
+ a ".badpixels" file, and fix those pixels now.
+ */
+void CLASS bad_pixels()
+{
+ FILE *fp=NULL;
+ char *fname, *cp, line[128];
+ int len, time, row, col, r, c, rad, tot, n, fixed=0;
+
+ if (!filters) return;
+ for (len=16 ; ; len *= 2) {
+ fname = malloc (len);
+ if (!fname) return;
+ if (getcwd (fname, len-12)) break;
+ free (fname);
+ if (errno != ERANGE) return;
+ }
+#ifdef WIN32
+ if (fname[1] == ':')
+ memmove (fname, fname+2, len-2);
+ for (cp=fname; *cp; cp++)
+ if (*cp == '\\') *cp = '/';
+#endif
+ cp = fname + strlen(fname);
+ if (cp[-1] == '/') cp--;
+ while (*fname == '/') {
+ strcpy (cp, "/.badpixels");
+ if ((fp = fopen (fname, "r"))) break;
+ if (cp == fname) break;
+ while (*--cp != '/');
+ }
+ free (fname);
+ if (!fp) return;
+ while (fgets (line, 128, fp)) {
+ cp = strchr (line, '#');
+ if (cp) *cp = 0;
+ if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue;
+ if ((unsigned) col >= width || (unsigned) row >= height) continue;
+ if (time > timestamp) continue;
+ for (tot=n=0, rad=1; rad < 3 && n==0; rad++)
+ for (r = row-rad; r <= row+rad; r++)
+ for (c = col-rad; c <= col+rad; c++)
+ if ((unsigned) r < height && (unsigned) c < width &&
+ (r != row || c != col) && FC(r,c) == FC(row,col)) {
+ tot += BAYER(r,c);
+ n++;
+ }
+ BAYER(row,col) = tot/n;
+ if (verbose) {
+ if (!fixed++)
+ fprintf (stderr, "Fixed bad pixels at:");
+ fprintf (stderr, " %d,%d", col, row);
+ }
+ }
+ if (fixed) fputc ('\n', stderr);
+ fclose (fp);
+}
+
+void CLASS pseudoinverse (const double (*in)[3], double (*out)[3], int size)
+{
+ double work[3][6], num;
+ int i, j, k;
+
+ for (i=0; i < 3; i++) {
+ for (j=0; j < 6; j++)
+ work[i][j] = j == i+3;
+ for (j=0; j < 3; j++)
+ for (k=0; k < size; k++)
+ work[i][j] += in[k][i] * in[k][j];
+ }
+ for (i=0; i < 3; i++) {
+ num = work[i][i];
+ for (j=0; j < 6; j++)
+ work[i][j] /= num;
+ for (k=0; k < 3; k++) {
+ if (k==i) continue;
+ num = work[k][i];
+ for (j=0; j < 6; j++)
+ work[k][j] -= work[i][j] * num;
+ }
+ }
+ for (i=0; i < size; i++)
+ for (j=0; j < 3; j++)
+ for (out[i][j]=k=0; k < 3; k++)
+ out[i][j] += work[j][k+3] * in[i][k];
+}
+
+void CLASS cam_xyz_coeff (double cam_xyz[4][3])
+{
+ double cam_rgb[4][3], inverse[4][3], num;
+ int i, j, k;
+
+ for (i=0; i < colors; i++) /* Multiply out XYZ colorspace */
+ for (j=0; j < 3; j++)
+ for (cam_rgb[i][j] = k=0; k < 3; k++)
+ cam_rgb[i][j] += cam_xyz[i][k] * xyz_rgb[k][j];
+
+ for (i=0; i < colors; i++) { /* Normalize cam_rgb so that */
+ for (num=j=0; j < 3; j++) /* cam_rgb * (1,1,1) is (1,1,1,1) */
+ num += cam_rgb[i][j];
+ for (j=0; j < 3; j++)
+ cam_rgb[i][j] /= num;
+ pre_mul[i] = 1 / num;
+ }
+ pseudoinverse ((const double (*)[3]) cam_rgb, inverse, colors);
+ for (raw_color = i=0; i < 3; i++)
+ for (j=0; j < colors; j++)
+ rgb_cam[i][j] = inverse[j][i];
+}
+
+#ifdef COLORCHECK
+void CLASS colorcheck()
+{
+#define NSQ 24
+// Coordinates of the GretagMacbeth ColorChecker squares
+// width, height, 1st_column, 1st_row
+ static const int cut[NSQ][4] = {
+ { 241, 231, 234, 274 },
+ { 251, 235, 534, 274 },
+ { 255, 239, 838, 272 },
+ { 255, 240, 1146, 274 },
+ { 251, 237, 1452, 278 },
+ { 243, 238, 1758, 288 },
+ { 253, 253, 218, 558 },
+ { 255, 249, 524, 562 },
+ { 261, 253, 830, 562 },
+ { 260, 255, 1144, 564 },
+ { 261, 255, 1450, 566 },
+ { 247, 247, 1764, 576 },
+ { 255, 251, 212, 862 },
+ { 259, 259, 518, 862 },
+ { 263, 261, 826, 864 },
+ { 265, 263, 1138, 866 },
+ { 265, 257, 1450, 872 },
+ { 257, 255, 1762, 874 },
+ { 257, 253, 212, 1164 },
+ { 262, 251, 516, 1172 },
+ { 263, 257, 826, 1172 },
+ { 263, 255, 1136, 1176 },
+ { 255, 252, 1452, 1182 },
+ { 257, 253, 1760, 1180 } };
+// ColorChecker Chart under 6500-kelvin illumination
+ static const double gmb_xyz[NSQ][3] = {
+ { 11.078, 9.870, 6.738 }, // Dark Skin
+ { 37.471, 35.004, 26.057 }, // Light Skin
+ { 18.187, 19.306, 35.425 }, // Blue Sky
+ { 10.825, 13.827, 7.600 }, // Foliage
+ { 24.769, 23.304, 43.943 }, // Blue Flower
+ { 31.174, 42.684, 45.277 }, // Bluish Green
+ { 36.238, 29.188, 6.222 }, // Orange
+ { 13.661, 11.845, 38.929 }, // Purplish Blue
+ { 27.999, 19.272, 14.265 }, // Moderate Red
+ { 8.398, 6.309, 14.211 }, // Purple
+ { 33.692, 44.346, 11.288 }, // Yellow Green
+ { 45.000, 42.144, 8.429 }, // Orange Yellow
+ { 8.721, 6.130, 31.181 }, // Blue
+ { 14.743, 24.049, 9.778 }, // Green
+ { 19.777, 11.530, 5.101 }, // Red
+ { 55.978, 59.599, 10.047 }, // Yellow
+ { 29.421, 19.271, 31.167 }, // Magenta
+ { 13.972, 18.952, 37.646 }, // Cyan
+ { 82.819, 87.727, 94.479 }, // White
+ { 55.950, 58.959, 64.375 }, // Neutral 8
+ { 32.877, 34.536, 38.097 }, // Neutral 6.5
+ { 18.556, 19.701, 21.487 }, // Neutral 5
+ { 8.353, 8.849, 9.812 }, // Neutral 3.5
+ { 2.841, 2.980, 3.332 } }; // Black
+ double inverse[NSQ][3], gmb_cam[NSQ][4], cam_xyz[4][3];
+ double num, error, minerr=DBL_MAX, best[4][3];
+ int b, c, i, j, k, sq, row, col, count[4];
+
+ memset (gmb_cam, 0, sizeof gmb_cam);
+ for (sq=0; sq < NSQ; sq++) {
+ FORCC count[c] = 0;
+ for (row=cut[sq][3]; row < cut[sq][3]+cut[sq][1]; row++)
+ for (col=cut[sq][2]; col < cut[sq][2]+cut[sq][0]; col++) {
+ c = FC(row,col);
+ if (c >= colors) c -= 2;
+ gmb_cam[sq][c] += BAYER(row,col);
+ count[c]++;
+ }
+ FORCC gmb_cam[sq][c] /= count[c];
+ }
+ for (b=0; b < 2000; b++) {
+ pseudoinverse (gmb_xyz, inverse, NSQ);
+ for (i=0; i < colors; i++)
+ for (j=0; j < 3; j++)
+ for (cam_xyz[i][j] = k=0; k < NSQ; k++)
+ cam_xyz[i][j] += gmb_cam[k][i] * inverse[k][j];
+
+ for (error=sq=0; sq < NSQ; sq++)
+ FORCC {
+ for (num=j=0; j < 3; j++)
+ num += cam_xyz[c][j] * gmb_xyz[sq][j];
+ if (num < 0) num=0;
+ error += pow (num - gmb_cam[sq][c], 2);
+ gmb_cam[sq][c]--; // for the next black value
+ }
+ if (error < minerr) {
+ black = b;
+ minerr = error;
+ memcpy (best, cam_xyz, sizeof best);
+ }
+ }
+ cam_xyz_coeff (best);
+ if (verbose) {
+ fprintf (stderr, " { \"%s %s\",\n\t{ ", make, model);
+ num = 10000 / (best[1][0] + best[1][1] + best[1][2]);
+ FORCC for (j=0; j < 3; j++)
+ fprintf (stderr, "%d,", (int) (best[c][j] * num + 0.5));
+ fprintf (stderr, "\b } },\n");
+ }
+#undef NSQ
+}
+#endif
+
+void CLASS scale_colors()
+{
+ int row, col, c, val, shift=0;
+ int min[4], max[4], count[4];
+ double sum[4], dmin;
+
+ maximum -= black;
+ if (use_auto_wb || (use_camera_wb && camera_red == -1)) {
+ FORC4 min[c] = INT_MAX;
+ FORC4 max[c] = count[c] = sum[c] = 0;
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col++)
+ FORC4 {
+ val = image[row*width+col][c];
+ if (!val) continue;
+ if (min[c] > val) min[c] = val;
+ if (max[c] < val) max[c] = val;
+ val -= black;
+ if (val > maximum-25) continue;
+ if (val < 0) val = 0;
+ sum[c] += val;
+ count[c]++;
+ }
+ FORC4 if (sum[c]) pre_mul[c] = count[c] / sum[c];
+ }
+ if (use_camera_wb && camera_red != -1) {
+ FORC4 count[c] = sum[c] = 0;
+ for (row=0; row < 8; row++)
+ for (col=0; col < 8; col++) {
+ c = FC(row,col);
+ if ((val = white[row][col] - black) > 0)
+ sum[c] += val;
+ count[c]++;
+ }
+ if (sum[0] && sum[1] && sum[2] && sum[3])
+ FORC4 pre_mul[c] = count[c] / sum[c];
+ else if (camera_red && camera_blue)
+ memcpy (pre_mul, cam_mul, sizeof pre_mul);
+ else
+ fprintf (stderr, "%s: Cannot use camera white balance.\n", ifname);
+ }
+ if (raw_color) {
+ pre_mul[0] *= red_scale;
+ pre_mul[2] *= blue_scale;
+ }
+ if (pre_mul[3] == 0) pre_mul[3] = colors < 4 ? pre_mul[1] : 1;
+ dmin = DBL_MAX;
+ FORC4 if (dmin > pre_mul[c])
+ dmin = pre_mul[c];
+ FORC4 pre_mul[c] /= dmin;
+
+ while (maximum << shift < 0x8000) shift++;
+ FORC4 pre_mul[c] *= 1 << shift;
+ maximum <<= shift;
+
+ if (write_fun != write_ppm || bright < 1) {
+ maximum *= bright;
+ if (maximum > 0xffff)
+ maximum = 0xffff;
+ FORC4 pre_mul[c] *= bright;
+ }
+ if (verbose) {
+ fprintf (stderr, "Scaling with black=%d, pre_mul[] =", black);
+ FORC4 fprintf (stderr, " %f", pre_mul[c]);
+ fputc ('\n', stderr);
+ }
+ clip_max = clip_color ? maximum : 0xffff;
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col++)
+ FORC4 {
+ val = image[row*width+col][c];
+ if (!val) continue;
+ val -= black;
+ val *= pre_mul[c];
+ image[row*width+col][c] = CLIP(val);
+ }
+ if (filters && colors == 3) {
+ if (four_color_rgb) {
+ colors++;
+ FORC3 rgb_cam[c][3] = rgb_cam[c][1] /= 2;
+ } else {
+ for (row = FC(1,0) >> 1; row < height; row+=2)
+ for (col = FC(row,1) & 1; col < width; col+=2)
+ image[row*width+col][1] = image[row*width+col][3];
+ filters &= ~((filters & 0x55555555) << 1);
+ }
+ }
+}
+
+void CLASS border_interpolate (int border)
+{
+ unsigned row, col, y, x, c, sum[8];
+
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col++) {
+ if (col==border && row >= border && row < height-border)
+ col = width-border;
+ memset (sum, 0, sizeof sum);
+ for (y=row-1; y != row+2; y++)
+ for (x=col-1; x != col+2; x++)
+ if (y < height && x < width) {
+ sum[FC(y,x)] += BAYER(y,x);
+ sum[FC(y,x)+4]++;
+ }
+ FORCC if (c != FC(row,col))
+ image[row*width+col][c] = sum[c] / sum[c+4];
+ }
+}
+
+void CLASS lin_interpolate()
+{
+ int code[8][2][32], *ip, sum[4];
+ int c, i, x, y, row, col, shift, color;
+ ushort *pix;
+
+ if (verbose) fprintf (stderr, "Bilinear interpolation...\n");
+
+ border_interpolate(1);
+ for (row=0; row < 8; row++)
+ for (col=0; col < 2; col++) {
+ ip = code[row][col];
+ memset (sum, 0, sizeof sum);
+ for (y=-1; y <= 1; y++)
+ for (x=-1; x <= 1; x++) {
+ shift = (y==0) + (x==0);
+ if (shift == 2) continue;
+ color = FC(row+y,col+x);
+ *ip++ = (width*y + x)*4 + color;
+ *ip++ = shift;
+ *ip++ = color;
+ sum[color] += 1 << shift;
+ }
+ FORCC
+ if (c != FC(row,col)) {
+ *ip++ = c;
+ *ip++ = sum[c];
+ }
+ }
+ for (row=1; row < height-1; row++)
+ for (col=1; col < width-1; col++) {
+ pix = image[row*width+col];
+ ip = code[row & 7][col & 1];
+ memset (sum, 0, sizeof sum);
+ for (i=8; i--; ip+=3)
+ sum[ip[2]] += pix[ip[0]] << ip[1];
+ for (i=colors; --i; ip+=2)
+ pix[ip[0]] = sum[ip[0]] / ip[1];
+ }
+}
+
+/*
+ This algorithm is officially called:
+
+ "Interpolation using a Threshold-based variable number of gradients"
+
+ described in http://www-ise.stanford.edu/~tingchen/algodep/vargra.html
+
+ I've extended the basic idea to work with non-Bayer filter arrays.
+ Gradients are numbered clockwise from NW=0 to W=7.
+ */
+void CLASS vng_interpolate()
+{
+ static const signed char *cp, terms[] = {
+ -2,-2,+0,-1,0,0x01, -2,-2,+0,+0,1,0x01, -2,-1,-1,+0,0,0x01,
+ -2,-1,+0,-1,0,0x02, -2,-1,+0,+0,0,0x03, -2,-1,+0,+1,1,0x01,
+ -2,+0,+0,-1,0,0x06, -2,+0,+0,+0,1,0x02, -2,+0,+0,+1,0,0x03,
+ -2,+1,-1,+0,0,0x04, -2,+1,+0,-1,1,0x04, -2,+1,+0,+0,0,0x06,
+ -2,+1,+0,+1,0,0x02, -2,+2,+0,+0,1,0x04, -2,+2,+0,+1,0,0x04,
+ -1,-2,-1,+0,0,0x80, -1,-2,+0,-1,0,0x01, -1,-2,+1,-1,0,0x01,
+ -1,-2,+1,+0,1,0x01, -1,-1,-1,+1,0,0x88, -1,-1,+1,-2,0,0x40,
+ -1,-1,+1,-1,0,0x22, -1,-1,+1,+0,0,0x33, -1,-1,+1,+1,1,0x11,
+ -1,+0,-1,+2,0,0x08, -1,+0,+0,-1,0,0x44, -1,+0,+0,+1,0,0x11,
+ -1,+0,+1,-2,1,0x40, -1,+0,+1,-1,0,0x66, -1,+0,+1,+0,1,0x22,
+ -1,+0,+1,+1,0,0x33, -1,+0,+1,+2,1,0x10, -1,+1,+1,-1,1,0x44,
+ -1,+1,+1,+0,0,0x66, -1,+1,+1,+1,0,0x22, -1,+1,+1,+2,0,0x10,
+ -1,+2,+0,+1,0,0x04, -1,+2,+1,+0,1,0x04, -1,+2,+1,+1,0,0x04,
+ +0,-2,+0,+0,1,0x80, +0,-1,+0,+1,1,0x88, +0,-1,+1,-2,0,0x40,
+ +0,-1,+1,+0,0,0x11, +0,-1,+2,-2,0,0x40, +0,-1,+2,-1,0,0x20,
+ +0,-1,+2,+0,0,0x30, +0,-1,+2,+1,1,0x10, +0,+0,+0,+2,1,0x08,
+ +0,+0,+2,-2,1,0x40, +0,+0,+2,-1,0,0x60, +0,+0,+2,+0,1,0x20,
+ +0,+0,+2,+1,0,0x30, +0,+0,+2,+2,1,0x10, +0,+1,+1,+0,0,0x44,
+ +0,+1,+1,+2,0,0x10, +0,+1,+2,-1,1,0x40, +0,+1,+2,+0,0,0x60,
+ +0,+1,+2,+1,0,0x20, +0,+1,+2,+2,0,0x10, +1,-2,+1,+0,0,0x80,
+ +1,-1,+1,+1,0,0x88, +1,+0,+1,+2,0,0x08, +1,+0,+2,-1,0,0x40,
+ +1,+0,+2,+1,0,0x10
+ }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 };
+ ushort (*brow[5])[4], *pix;
+ int code[8][2][320], *ip, gval[8], gmin, gmax, sum[4];
+ int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag;
+ int g, diff, thold, num, c;
+
+ lin_interpolate();
+ if (verbose) fprintf (stderr, "VNG interpolation...\n");
+
+ for (row=0; row < 8; row++) { /* Precalculate for VNG */
+ for (col=0; col < 2; col++) {
+ ip = code[row][col];
+ for (cp=terms, t=0; t < 64; t++) {
+ y1 = *cp++; x1 = *cp++;
+ y2 = *cp++; x2 = *cp++;
+ weight = *cp++;
+ grads = *cp++;
+ color = FC(row+y1,col+x1);
+ if (FC(row+y2,col+x2) != color) continue;
+ diag = (FC(row,col+1) == color && FC(row+1,col) == color) ? 2:1;
+ if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue;
+ *ip++ = (y1*width + x1)*4 + color;
+ *ip++ = (y2*width + x2)*4 + color;
+ *ip++ = weight;
+ for (g=0; g < 8; g++)
+ if (grads & 1<<g) *ip++ = g;
+ *ip++ = -1;
+ }
+ *ip++ = INT_MAX;
+ for (cp=chood, g=0; g < 8; g++) {
+ y = *cp++; x = *cp++;
+ *ip++ = (y*width + x) * 4;
+ color = FC(row,col);
+ if (FC(row+y,col+x) != color && FC(row+y*2,col+x*2) == color)
+ *ip++ = (y*width + x) * 8 + color;
+ else
+ *ip++ = 0;
+ }
+ }
+ }
+ brow[4] = calloc (width*3, sizeof **brow);
+ merror (brow[4], "vng_interpolate()");
+ for (row=0; row < 3; row++)
+ brow[row] = brow[4] + row*width;
+ for (row=2; row < height-2; row++) { /* Do VNG interpolation */
+ for (col=2; col < width-2; col++) {
+ pix = image[row*width+col];
+ ip = code[row & 7][col & 1];
+ memset (gval, 0, sizeof gval);
+ while ((g = ip[0]) != INT_MAX) { /* Calculate gradients */
+ diff = ABS(pix[g] - pix[ip[1]]) << ip[2];
+ gval[ip[3]] += diff;
+ ip += 5;
+ if ((g = ip[-1]) == -1) continue;
+ gval[g] += diff;
+ while ((g = *ip++) != -1)
+ gval[g] += diff;
+ }
+ ip++;
+ gmin = gmax = gval[0]; /* Choose a threshold */
+ for (g=1; g < 8; g++) {
+ if (gmin > gval[g]) gmin = gval[g];
+ if (gmax < gval[g]) gmax = gval[g];
+ }
+ if (gmax == 0) {
+ memcpy (brow[2][col], pix, sizeof *image);
+ continue;
+ }
+ thold = gmin + (gmax >> 1);
+ memset (sum, 0, sizeof sum);
+ color = FC(row,col);
+ for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */
+ if (gval[g] <= thold) {
+ FORCC
+ if (c == color && ip[1])
+ sum[c] += (pix[c] + pix[ip[1]]) >> 1;
+ else
+ sum[c] += pix[ip[0] + c];
+ num++;
+ }
+ }
+ FORCC { /* Save to buffer */
+ t = pix[color];
+ if (c != color)
+ t += (sum[c] - sum[color]) / num;
+ brow[2][col][c] = CLIP(t);
+ }
+ }
+ if (row > 3) /* Write buffer to image */
+ memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image);
+ for (g=0; g < 4; g++)
+ brow[(g-1) & 3] = brow[g];
+ }
+ memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image);
+ memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image);
+ free (brow[4]);
+}
+
+void CLASS cam_to_cielab (ushort cam[4], float lab[3])
+{
+ int c, i, j, k;
+ float r, xyz[3];
+ static const float d65[3] = { 0.950456, 1, 1.088754 };
+ static float cbrt[0x10000], xyz_cam[3][4];
+
+ if (cam == NULL) {
+ for (i=0; i < 0x10000; i++) {
+ r = (float) i / maximum;
+ cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0;
+ }
+ for (i=0; i < 3; i++)
+ for (j=0; j < colors; j++)
+ for (xyz_cam[i][j] = k=0; k < 3; k++)
+ xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65[i];
+ } else {
+ for (i=0; i < 3; i++) {
+ for (xyz[i]=0.5, c=0; c < colors; c++)
+ xyz[i] += xyz_cam[i][c] * cam[c];
+ xyz[i] = cbrt[CLIP((int) xyz[i])];
+ }
+ lab[0] = 116 * xyz[1] - 16;
+ lab[1] = 500 * (xyz[0] - xyz[1]);
+ lab[2] = 200 * (xyz[1] - xyz[2]);
+ }
+}
+
+/*
+ Adaptive Homogeneity-Directed interpolation is based on
+ the work of Keigo Hirakawa, Thomas Parks, and Paul Lee.
+ */
+#define TS 256 /* Tile Size */
+
+void CLASS ahd_interpolate()
+{
+ int i, j, top, left, row, col, tr, tc, fc, c, d, val, hm[2];
+ ushort (*pix)[4], (*rix)[3];
+ static const int dir[4] = { -1, 1, -TS, TS };
+ unsigned ldiff[2][4], abdiff[2][4], leps, abeps;
+ float flab[3];
+ ushort (*rgb)[TS][TS][3];
+ short (*lab)[TS][TS][3];
+ char (*homo)[TS][TS], *buffer;
+
+ if (verbose) fprintf (stderr, "AHD interpolation...\n");
+
+ border_interpolate(3);
+ buffer = malloc (26*TS*TS); /* 1664 kB */
+ merror (buffer, "ahd_interpolate()");
+ rgb = (void *) buffer;
+ lab = (void *) (buffer + 12*TS*TS);
+ homo = (void *) (buffer + 24*TS*TS);
+
+ for (top=0; top < height; top += TS-6)
+ for (left=0; left < width; left += TS-6) {
+ memset (rgb, 0, 12*TS*TS);
+
+/* Interpolate green horizontally and vertically: */
+ for (row = top < 2 ? 2:top; row < top+TS && row < height-2; row++) {
+ col = left + (FC(row,left) == 1);
+ if (col < 2) col += 2;
+ for (fc = FC(row,col); col < left+TS && col < width-2; col+=2) {
+ pix = image + row*width+col;
+ val = ((pix[-1][1] + pix[0][fc] + pix[1][1]) * 2
+ - pix[-2][fc] - pix[2][fc]) >> 2;
+ rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]);
+ val = ((pix[-width][1] + pix[0][fc] + pix[width][1]) * 2
+ - pix[-2*width][fc] - pix[2*width][fc]) >> 2;
+ rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]);
+ }
+ }
+/* Interpolate red and blue, and convert to CIELab: */
+ for (d=0; d < 2; d++)
+ for (row=top+1; row < top+TS-1 && row < height-1; row++)
+ for (col=left+1; col < left+TS-1 && col < width-1; col++) {
+ pix = image + row*width+col;
+ rix = &rgb[d][row-top][col-left];
+ if ((c = 2 - FC(row,col)) == 1) {
+ c = FC(row+1,col);
+ val = pix[0][1] + (( pix[-1][2-c] + pix[1][2-c]
+ - rix[-1][1] - rix[1][1] ) >> 1);
+ rix[0][2-c] = CLIP(val);
+ val = pix[0][1] + (( pix[-width][c] + pix[width][c]
+ - rix[-TS][1] - rix[TS][1] ) >> 1);
+ } else
+ val = rix[0][1] + (( pix[-width-1][c] + pix[-width+1][c]
+ + pix[+width-1][c] + pix[+width+1][c]
+ - rix[-TS-1][1] - rix[-TS+1][1]
+ - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2);
+ rix[0][c] = CLIP(val);
+ c = FC(row,col);
+ rix[0][c] = pix[0][c];
+ cam_to_cielab (rix[0], flab);
+ FORC3 lab[d][row-top][col-left][c] = 64*flab[c];
+ }
+/* Build homogeneity maps from the CIELab images: */
+ memset (homo, 0, 2*TS*TS);
+ for (row=top+2; row < top+TS-2 && row < height; row++) {
+ tr = row-top;
+ for (col=left+2; col < left+TS-2 && col < width; col++) {
+ tc = col-left;
+ for (d=0; d < 2; d++)
+ for (i=0; i < 4; i++)
+ ldiff[d][i] = ABS(lab[d][tr][tc][0]-lab[d][tr][tc+dir[i]][0]);
+ leps = MIN(MAX(ldiff[0][0],ldiff[0][1]),
+ MAX(ldiff[1][2],ldiff[1][3]));
+ for (d=0; d < 2; d++)
+ for (i=0; i < 4; i++)
+ if (i >> 1 == d || ldiff[d][i] <= leps)
+ abdiff[d][i] = SQR(lab[d][tr][tc][1]-lab[d][tr][tc+dir[i]][1])
+ + SQR(lab[d][tr][tc][2]-lab[d][tr][tc+dir[i]][2]);
+ abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]),
+ MAX(abdiff[1][2],abdiff[1][3]));
+ for (d=0; d < 2; d++)
+ for (i=0; i < 4; i++)
+ if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps)
+ homo[d][tr][tc]++;
+ }
+ }
+/* Combine the most homogenous pixels for the final result: */
+ for (row=top+3; row < top+TS-3 && row < height-3; row++) {
+ tr = row-top;
+ for (col=left+3; col < left+TS-3 && col < width-3; col++) {
+ tc = col-left;
+ for (d=0; d < 2; d++)
+ for (hm[d]=0, i=tr-1; i <= tr+1; i++)
+ for (j=tc-1; j <= tc+1; j++)
+ hm[d] += homo[d][i][j];
+ if (hm[0] != hm[1])
+ FORC3 image[row*width+col][c] = rgb[hm[1] > hm[0]][tr][tc][c];
+ else
+ FORC3 image[row*width+col][c] =
+ (rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) >> 1;
+ }
+ }
+ }
+ free (buffer);
+}
+#undef TS
+
+/*
+ Bilateral Filtering was developed by C. Tomasi and R. Manduchi.
+ */
+void CLASS bilateral_filter()
+{
+ float (**window)[7], *kernel, scale_r, elut[1024], sum[5];
+ int c, i, wr, ws, wlast, row, col, y, x;
+ unsigned sep;
+
+ if (verbose) fprintf (stderr, "Bilateral filtering...\n");
+
+ wr = ceil(sigma_d*2); /* window radius */
+ ws = 2*wr + 1; /* window size */
+ window = calloc ((ws+1)*sizeof *window +
+ ws*width*sizeof **window + ws*sizeof *kernel, 1);
+ merror (window, "bilateral_filter()");
+ for (i=0; i <= ws; i++)
+ window[i] = (float(*)[7]) (window+ws+1) + i*width;
+ kernel = (float *) window[ws] + wr;
+ for (i=-wr; i <= wr; i++)
+ kernel[i] = 256 / (2*SQR(sigma_d)) * i*i + 0.25;
+ scale_r = 256 / (2*SQR(sigma_r));
+ for (i=0; i < 1024; i++)
+ elut[i] = exp (-i/256.0);
+
+ for (wlast=-1, row=0; row < height; row++) {
+ while (wlast < row+wr) {
+ wlast++;
+ for (i=0; i <= ws; i++) /* rotate window rows */
+ window[(ws+i) % (ws+1)] = window[i];
+ if (wlast < height)
+ for (col=0; col < width; col++) {
+ FORCC window[ws-1][col][c] = image[wlast*width+col][c];
+ cam_to_cielab (image[wlast*width+col], window[ws-1][col]+4);
+ }
+ }
+ for (col=0; col < width; col++) {
+ memset (sum, 0, sizeof sum);
+ for (y=-wr; y <= wr; y++)
+ if ((unsigned)(row+y) < height)
+ for (x=-wr; x <= wr; x++)
+ if ((unsigned)(col+x) < width) {
+ sep = ( SQR(window[wr+y][col+x][4] - window[wr][col][4])
+ + SQR(window[wr+y][col+x][5] - window[wr][col][5])
+ + SQR(window[wr+y][col+x][6] - window[wr][col][6]) )
+ * scale_r + kernel[y] + kernel[x];
+ if (sep < 1024) {
+ FORCC sum[c] += elut[sep] * window[wr+y][col+x][c];
+ sum[4] += elut[sep];
+ }
+ }
+ FORCC image[row*width+col][c] = sum[c]/sum[4];
+ }
+ }
+ free (window);
+}
+
+void CLASS parse_makernote()
+{
+ static const uchar xlat[2][256] = {
+ { 0xc1,0xbf,0x6d,0x0d,0x59,0xc5,0x13,0x9d,0x83,0x61,0x6b,0x4f,0xc7,0x7f,0x3d,0x3d,
+ 0x53,0x59,0xe3,0xc7,0xe9,0x2f,0x95,0xa7,0x95,0x1f,0xdf,0x7f,0x2b,0x29,0xc7,0x0d,
+ 0xdf,0x07,0xef,0x71,0x89,0x3d,0x13,0x3d,0x3b,0x13,0xfb,0x0d,0x89,0xc1,0x65,0x1f,
+ 0xb3,0x0d,0x6b,0x29,0xe3,0xfb,0xef,0xa3,0x6b,0x47,0x7f,0x95,0x35,0xa7,0x47,0x4f,
+ 0xc7,0xf1,0x59,0x95,0x35,0x11,0x29,0x61,0xf1,0x3d,0xb3,0x2b,0x0d,0x43,0x89,0xc1,
+ 0x9d,0x9d,0x89,0x65,0xf1,0xe9,0xdf,0xbf,0x3d,0x7f,0x53,0x97,0xe5,0xe9,0x95,0x17,
+ 0x1d,0x3d,0x8b,0xfb,0xc7,0xe3,0x67,0xa7,0x07,0xf1,0x71,0xa7,0x53,0xb5,0x29,0x89,
+ 0xe5,0x2b,0xa7,0x17,0x29,0xe9,0x4f,0xc5,0x65,0x6d,0x6b,0xef,0x0d,0x89,0x49,0x2f,
+ 0xb3,0x43,0x53,0x65,0x1d,0x49,0xa3,0x13,0x89,0x59,0xef,0x6b,0xef,0x65,0x1d,0x0b,
+ 0x59,0x13,0xe3,0x4f,0x9d,0xb3,0x29,0x43,0x2b,0x07,0x1d,0x95,0x59,0x59,0x47,0xfb,
+ 0xe5,0xe9,0x61,0x47,0x2f,0x35,0x7f,0x17,0x7f,0xef,0x7f,0x95,0x95,0x71,0xd3,0xa3,
+ 0x0b,0x71,0xa3,0xad,0x0b,0x3b,0xb5,0xfb,0xa3,0xbf,0x4f,0x83,0x1d,0xad,0xe9,0x2f,
+ 0x71,0x65,0xa3,0xe5,0x07,0x35,0x3d,0x0d,0xb5,0xe9,0xe5,0x47,0x3b,0x9d,0xef,0x35,
+ 0xa3,0xbf,0xb3,0xdf,0x53,0xd3,0x97,0x53,0x49,0x71,0x07,0x35,0x61,0x71,0x2f,0x43,
+ 0x2f,0x11,0xdf,0x17,0x97,0xfb,0x95,0x3b,0x7f,0x6b,0xd3,0x25,0xbf,0xad,0xc7,0xc5,
+ 0xc5,0xb5,0x8b,0xef,0x2f,0xd3,0x07,0x6b,0x25,0x49,0x95,0x25,0x49,0x6d,0x71,0xc7 },
+ { 0xa7,0xbc,0xc9,0xad,0x91,0xdf,0x85,0xe5,0xd4,0x78,0xd5,0x17,0x46,0x7c,0x29,0x4c,
+ 0x4d,0x03,0xe9,0x25,0x68,0x11,0x86,0xb3,0xbd,0xf7,0x6f,0x61,0x22,0xa2,0x26,0x34,
+ 0x2a,0xbe,0x1e,0x46,0x14,0x68,0x9d,0x44,0x18,0xc2,0x40,0xf4,0x7e,0x5f,0x1b,0xad,
+ 0x0b,0x94,0xb6,0x67,0xb4,0x0b,0xe1,0xea,0x95,0x9c,0x66,0xdc,0xe7,0x5d,0x6c,0x05,
+ 0xda,0xd5,0xdf,0x7a,0xef,0xf6,0xdb,0x1f,0x82,0x4c,0xc0,0x68,0x47,0xa1,0xbd,0xee,
+ 0x39,0x50,0x56,0x4a,0xdd,0xdf,0xa5,0xf8,0xc6,0xda,0xca,0x90,0xca,0x01,0x42,0x9d,
+ 0x8b,0x0c,0x73,0x43,0x75,0x05,0x94,0xde,0x24,0xb3,0x80,0x34,0xe5,0x2c,0xdc,0x9b,
+ 0x3f,0xca,0x33,0x45,0xd0,0xdb,0x5f,0xf5,0x52,0xc3,0x21,0xda,0xe2,0x22,0x72,0x6b,
+ 0x3e,0xd0,0x5b,0xa8,0x87,0x8c,0x06,0x5d,0x0f,0xdd,0x09,0x19,0x93,0xd0,0xb9,0xfc,
+ 0x8b,0x0f,0x84,0x60,0x33,0x1c,0x9b,0x45,0xf1,0xf0,0xa3,0x94,0x3a,0x12,0x77,0x33,
+ 0x4d,0x44,0x78,0x28,0x3c,0x9e,0xfd,0x65,0x57,0x16,0x94,0x6b,0xfb,0x59,0xd0,0xc8,
+ 0x22,0x36,0xdb,0xd2,0x63,0x98,0x43,0xa1,0x04,0x87,0x86,0xf7,0xa6,0x26,0xbb,0xd6,
+ 0x59,0x4d,0xbf,0x6a,0x2e,0xaa,0x2b,0xef,0xe6,0x78,0xb6,0x4e,0xe0,0x2f,0xdc,0x7c,
+ 0xbe,0x57,0x19,0x32,0x7e,0x2a,0xd0,0xb8,0xba,0x29,0x00,0x3c,0x52,0x7d,0xa8,0x49,
+ 0x3b,0x2d,0xeb,0x25,0x49,0xfa,0xa3,0xaa,0x39,0xa7,0xc5,0xa7,0x50,0x11,0x36,0xfb,
+ 0xc6,0x67,0x4a,0xf5,0xa5,0x12,0x65,0x7e,0xb0,0xdf,0xaf,0x4e,0xb3,0x61,0x7f,0x2f } };
+ unsigned base=0, offset=0, entries, tag, type, len, save, c;
+ unsigned ver97=0, serial=0, i;
+ uchar buf97[324], ci, cj, ck;
+ static const int size[] = { 1,1,1,2,4,8,1,1,2,4,8,4,8 };
+ short sorder;
+ char buf[10];
+/*
+ The MakerNote might have its own TIFF header (possibly with
+ its own byte-order!), or it might just be a table.
+ */
+ sorder = order;
+ fread (buf, 1, 10, ifp);
+ if (!strncmp (buf,"KC" ,2) || /* these aren't TIFF format */
+ !strncmp (buf,"MLY",3)) return;
+ if (!strcmp (buf,"Nikon")) {
+ base = ftell(ifp);
+ order = get2();
+ if (get2() != 42) goto quit;
+ offset = get4();
+ fseek (ifp, offset-8, SEEK_CUR);
+ } else if (!strncmp (buf,"FUJIFILM",8) ||
+ !strcmp (buf,"Panasonic")) {
+ order = 0x4949;
+ fseek (ifp, 2, SEEK_CUR);
+ } else if (!strcmp (buf,"OLYMP") ||
+ !strcmp (buf,"LEICA") ||
+ !strcmp (buf,"EPSON"))
+ fseek (ifp, -2, SEEK_CUR);
+ else if (!strcmp (buf,"AOC") ||
+ !strcmp (buf,"TQVC"))
+ fseek (ifp, -4, SEEK_CUR);
+ else fseek (ifp, -10, SEEK_CUR);
+
+ entries = get2();
+ while (entries--) {
+ tag = get2();
+ type = get2();
+ len = get4();
+ save = ftell(ifp);
+ if (len * size[type < 13 ? type:0] > 4)
+ fseek (ifp, get4()+base, SEEK_SET);
+
+ if (tag == 8 && type == 4)
+ shot_order = get4();
+ if (tag == 0xc && len == 4) {
+ camera_red = getrat();
+ camera_blue = getrat();
+ }
+ if (tag == 0x14 && len == 2560 && type == 7) {
+ fseek (ifp, 1248, SEEK_CUR);
+ goto get2_256;
+ }
+ if (strstr(make,"PENTAX")) {
+ if (tag == 0x1b) tag = 0x1018;
+ if (tag == 0x1c) tag = 0x1017;
+ }
+ if (tag == 0x1d)
+ while ((c = fgetc(ifp)))
+ serial = serial*10 + (isdigit(c) ? c - '0' : c % 10);
+ if (tag == 0x8c)
+ nikon_curve_offset = ftell(ifp) + 2112;
+ if (tag == 0x96)
+ nikon_curve_offset = ftell(ifp) + 2;
+ if (tag == 0x97) {
+ for (i=0; i < 4; i++)
+ ver97 = (ver97 << 4) + fgetc(ifp)-'0';
+ switch (ver97) {
+ case 0x100:
+ fseek (ifp, 68, SEEK_CUR);
+ FORC4 cam_mul[(c >> 1) | ((c & 1) << 1)] = get2();
+ break;
+ case 0x102:
+ fseek (ifp, 6, SEEK_CUR);
+ goto get2_rggb;
+ case 0x103:
+ fseek (ifp, 16, SEEK_CUR);
+ FORC4 cam_mul[c] = get2();
+ }
+ if (ver97 >> 8 == 2) {
+ if (ver97 != 0x205) fseek (ifp, 280, SEEK_CUR);
+ fread (buf97, 324, 1, ifp);
+ }
+ }
+ if (tag == 0xa7 && ver97 >> 8 == 2) {
+ ci = xlat[0][serial & 0xff];
+ cj = xlat[1][fgetc(ifp)^fgetc(ifp)^fgetc(ifp)^fgetc(ifp)];
+ ck = 0x60;
+ for (i=0; i < 324; i++)
+ buf97[i] ^= (cj += ci * ck++);
+ FORC4 cam_mul[c ^ (c >> 1)] =
+ sget2 (buf97 + (ver97 == 0x205 ? 14:6) + c*2);
+ }
+ if (tag == 0xe0 && len == 17) {
+ get2();
+ raw_width = get2();
+ raw_height = get2();
+ }
+ if (tag == 0x200 && len == 4)
+ black = (get2()+get2()+get2()+get2())/4;
+ if (tag == 0x201 && len == 4)
+ goto get2_rggb;
+ if (tag == 0x401 && len == 4) {
+ black = (get4()+get4()+get4()+get4())/4;
+ }
+ if (tag == 0xe01) { /* Nikon Capture Note */
+ type = order;
+ order = 0x4949;
+ fseek (ifp, 22, SEEK_CUR);
+ for (offset=22; offset+22 < len; offset += 22+i) {
+ tag = get4();
+ fseek (ifp, 14, SEEK_CUR);
+ i = get4()-4;
+ if (tag == 0x76a43207) flip = get2();
+ else fseek (ifp, i, SEEK_CUR);
+ }
+ order = type;
+ }
+ if (tag == 0xe80 && len == 256 && type == 7) {
+ fseek (ifp, 48, SEEK_CUR);
+ camera_red = get2() * 508 * 1.078 / 0x10000;
+ camera_blue = get2() * 382 * 1.173 / 0x10000;
+ }
+ if (tag == 0xf00 && len == 614 && type == 7) {
+ fseek (ifp, 188, SEEK_CUR);
+ goto get2_256;
+ }
+ if (tag == 0x1017)
+ camera_red = get2() / 256.0;
+ if (tag == 0x1018)
+ camera_blue = get2() / 256.0;
+ if (tag == 0x2011 && len == 2) {
+get2_256:
+ order = 0x4d4d;
+ camera_red = get2() / 256.0;
+ camera_blue = get2() / 256.0;
+ }
+ if (tag == 0x4001) {
+ fseek (ifp, strstr(model,"EOS-1D") ? 68 :
+ strstr(model,"EOS 5D") ? 126 : 50, SEEK_CUR);
+get2_rggb:
+ FORC4 cam_mul[c ^ (c >> 1)] = get2();
+ }
+ fseek (ifp, save+4, SEEK_SET);
+ }
+quit:
+ order = sorder;
+}
+
+/*
+ Since the TIFF DateTime string has no timezone information,
+ assume that the camera's clock was set to Universal Time.
+ */
+void CLASS get_timestamp (int reversed)
+{
+ struct tm t;
+ char str[20];
+ int i;
+
+ if (timestamp) return;
+ str[19] = 0;
+ if (reversed)
+ for (i=19; i--; ) str[i] = fgetc(ifp);
+ else
+ fread (str, 19, 1, ifp);
+ if (sscanf (str, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon,
+ &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec) != 6)
+ return;
+ t.tm_year -= 1900;
+ t.tm_mon -= 1;
+ if (mktime(&t) > 0)
+ timestamp = mktime(&t);
+}
+
+void CLASS parse_exif (int base)
+{
+ int entries, tag, type, len, val, save;
+
+ entries = get2();
+ while (entries--) {
+ tag = get2();
+ type = get2();
+ len = get4();
+ val = get4();
+ save = ftell(ifp);
+ fseek (ifp, base+val, SEEK_SET);
+ if (tag == 0x9003 || tag == 0x9004)
+ get_timestamp(0);
+ if (tag == 0x927c)
+ parse_makernote();
+ fseek (ifp, save, SEEK_SET);
+ }
+}
+
+void CLASS parse_mos (int offset);
+void CLASS sony_decrypt (unsigned *data, int len, int start, int key);
+
+int CLASS parse_tiff_ifd (int base, int level)
+{
+ unsigned entries, tag, type, len, plen=16, save;
+ int done=0, use_cm=0, cfa, i, j, c;
+ static const int size[] = { 1,1,1,2,4,8,1,1,2,4,8,4,8 };
+ char software[64], *cbuf, *cp;
+ static const int flip_map[] = { 0,1,3,2,4,6,7,5 };
+ uchar cfa_pat[16], cfa_pc[] = { 0,1,2,3 }, tab[256];
+ double dblack, cc[4][4], cm[4][3], cam_xyz[4][3];
+ double ab[]={ 1,1,1,1 }, asn[] = { 0,0,0,0 }, xyz[] = { 1,1,1 };
+ unsigned *buf, sony_offset=0, sony_length=0, sony_key=0;
+ FILE *sfp;
+
+ for (j=0; j < 4; j++)
+ for (i=0; i < 4; i++)
+ cc[j][i] = i == j;
+ entries = get2();
+ if (entries > 512) return 1;
+ while (entries--) {
+ tag = get2();
+ type = get2();
+ len = get4();
+ save = ftell(ifp);
+ if (tag > 50700 && tag < 50800) done = 1;
+ if (len * size[type < 13 ? type:0] > 4)
+ fseek (ifp, get4()+base, SEEK_SET);
+ switch (tag) {
+ case 0x11:
+ case 0x12:
+ if (type == 3 && len == 1)
+ cam_mul[(tag-0x11)*2] = get2() / 256.0;
+ break;
+ case 0x27:
+ if (len < 50) break;
+ fseek (ifp, 12, SEEK_CUR);
+ FORC3 cam_mul[c] = get2();
+ break;
+ case 0x2:
+ case 0x100: /* ImageWidth */
+ if ((strcmp(make,"Canon") || level) && len == 1)
+ raw_width = type==3 ? get2() : get4();
+ break;
+ case 0x3:
+ case 0x101: /* ImageHeight */
+ if ((strcmp(make,"Canon") || level) && len == 1)
+ raw_height = type==3 ? get2() : get4();
+ break;
+ case 0x102: /* Bits per sample */
+ fuji_secondary = len == 2;
+ maximum = (1 << (tiff_bps = get2())) - 1;
+ break;
+ case 0x103: /* Compression */
+ tiff_data_compression = get2();
+ break;
+ case 0x106: /* Kodak color format */
+ kodak_data_compression = get2();
+ break;
+ case 0x10f: /* Make */
+ fgets (make, 64, ifp);
+ break;
+ case 0x110: /* Model */
+ fgets (model, 64, ifp);
+ break;
+ case 0x111: /* StripOffset */
+ data_offset = get4();
+ break;
+ case 0x112: /* Qt::Orientation */
+ flip = flip_map[(get2()-1) & 7];
+ break;
+ case 0x115: /* SamplesPerPixel */
+ tiff_samples = get2();
+ break;
+ case 0x131: /* Software tag */
+ fgets (software, 64, ifp);
+ if (!strncmp(software,"Adobe",5) ||
+ !strncmp(software,"Bibble",6) ||
+ !strcmp (software,"Digital Photo Professional"))
+ make[0] = 0;
+ break;
+ case 0x132: /* DateTime tag */
+ get_timestamp(0);
+ break;
+ case 0x144: /* TileOffsets */
+ if (level) {
+ data_offset = ftell(ifp);
+ } else {
+ data_offset = get4();
+ done = 1;
+ }
+ break;
+ case 0x14a: /* SubIFD tag */
+ if (len > 2 && !dng_version && !strcmp(make,"Kodak"))
+ len = 2;
+ while (len--) {
+ i = ftell(ifp);
+ fseek (ifp, get4()+base, SEEK_SET);
+ if (parse_tiff_ifd (base, level+1)) break;
+ fseek (ifp, i+4, SEEK_SET);
+ }
+ break;
+ case 29184: sony_offset = get4(); break;
+ case 29185: sony_length = get4(); break;
+ case 29217: sony_key = get4(); break;
+ case 29443:
+ FORC4 cam_mul[c ^ (c < 2)] = get2();
+ break;
+ case 33405: /* Model2 */
+ fgets (model2, 64, ifp);
+ break;
+ case 33422: /* CFAPattern */
+ if ((plen=len) > 16) plen = 16;
+ fread (cfa_pat, 1, plen, ifp);
+ for (colors=cfa=i=0; i < plen; i++) {
+ colors += !(cfa & (1 << cfa_pat[i]));
+ cfa |= 1 << cfa_pat[i];
+ }
+ if (cfa == 070) memcpy (cfa_pc,"\003\004\005",3); /* CMY */
+ if (cfa == 072) memcpy (cfa_pc,"\005\003\004\001",4); /* GMCY */
+ goto guess_cfa_pc;
+ case 34310:
+ parse_mos (ftell(ifp));
+ break;
+ case 34665: /* EXIF tag */
+ fseek (ifp, get4()+base, SEEK_SET);
+ parse_exif (base);
+ break;
+ case 37122: /* CompressedBitsPerPixel */
+ kodak_cbpp = get4();
+ break;
+ case 37400:
+ for (raw_color = i=0; i < 3; i++) {
+ getrat();
+ FORC3 rgb_cam[i][c] = getrat();
+ }
+ break;
+ case 46275:
+ strcpy (make, "Imacon");
+ data_offset = ftell(ifp);
+ raw_width = 4090;
+ raw_height = len / raw_width / 2;
+ done = 1;
+ break;
+ case 50454: /* Sinar tag */
+ case 50455:
+ if (!(cbuf = malloc(len))) break;
+ fread (cbuf, 1, len, ifp);
+ for (cp = cbuf-1; cp && cp < cbuf+len; cp = strchr(cp,'\n'))
+ if (!strncmp (++cp,"Neutral ",8))
+ sscanf (cp+8, "%f %f %f", cam_mul, cam_mul+1, cam_mul+2);
+ free (cbuf);
+ break;
+ case 50706: /* DNGVersion */
+ FORC4 dng_version = (dng_version << 8) + fgetc(ifp);
+ break;
+ case 50710: /* CFAPlaneColor */
+ if (len > 4) len = 4;
+ colors = len;
+ fread (cfa_pc, 1, colors, ifp);
+guess_cfa_pc:
+ FORCC tab[cfa_pc[c]] = c;
+ for (i=16; i--; )
+ filters = filters << 2 | tab[cfa_pat[i % plen]];
+ break;
+ case 50711: /* CFALayout */
+ if (get2() == 2) {
+ fuji_width = (raw_width+1)/2;
+ filters = 0x49494949;
+ }
+ break;
+ case 0x123:
+ case 0x90d:
+ case 50712: /* LinearizationTable */
+ if (len > 0x1000)
+ len = 0x1000;
+ read_shorts (curve, len);
+ for (i=len; i < 0x1000; i++)
+ maximum = curve[i] = curve[i-1];
+ break;
+ case 50714: /* BlackLevel */
+ case 50715: /* BlackLevelDeltaH */
+ case 50716: /* BlackLevelDeltaV */
+ for (dblack=i=0; i < len; i++)
+ dblack += getrat();
+ black += dblack/len + 0.5;
+ break;
+ case 50717: /* WhiteLevel */
+ maximum = get2();
+ break;
+ case 50718: /* DefaultScale */
+ i = get4();
+ j = get4() * get4();
+ i *= get4();
+ if (i > j) xmag = i / j;
+ else ymag = j / i;
+ break;
+ case 50721: /* ColorMatrix1 */
+ case 50722: /* ColorMatrix2 */
+ FORCC for (j=0; j < 3; j++)
+ cm[c][j] = getrat();
+ use_cm = 1;
+ break;
+ case 50723: /* CameraCalibration1 */
+ case 50724: /* CameraCalibration2 */
+ for (i=0; i < colors; i++)
+ FORCC cc[i][c] = getrat();
+ case 50727: /* AnalogBalance */
+ FORCC ab[c] = getrat();
+ break;
+ case 50728: /* AsShotNeutral */
+ FORCC asn[c] = getrat();
+ break;
+ case 50729: /* AsShotWhiteXY */
+ xyz[0] = getrat();
+ xyz[1] = getrat();
+ xyz[2] = 1 - xyz[0] - xyz[1];
+ break;
+ case 50740: /* DNGPrivateData */
+ if (dng_version) break;
+ fseek (ifp, get4()+base, SEEK_SET);
+ parse_tiff_ifd (base, level+1);
+ break;
+ case 50829: /* ActiveArea */
+ top_margin = get4();
+ left_margin = get4();
+ height = get4() - top_margin;
+ width = get4() - left_margin;
+ }
+ fseek (ifp, save+4, SEEK_SET);
+ }
+ if (sony_length && (buf = malloc(sony_length))) {
+ fseek (ifp, sony_offset, SEEK_SET);
+ fread (buf, sony_length, 1, ifp);
+ sony_decrypt (buf, sony_length/4, 1, sony_key);
+ sfp = ifp;
+ if ((ifp = tmpfile())) {
+ fwrite (buf, sony_length, 1, ifp);
+ fseek (ifp, 0, SEEK_SET);
+ parse_tiff_ifd (-sony_offset, level);
+ fclose (ifp);
+ }
+ ifp = sfp;
+ free (buf);
+ }
+ if (!(base | level | dng_version) &&
+ (strstr(make,"Minolta") || strstr(make,"MINOLTA"))) make[0] = 0;
+ for (i=0; i < colors; i++)
+ FORCC cc[i][c] *= ab[i];
+ if (use_cm) {
+ FORCC for (i=0; i < 3; i++)
+ for (cam_xyz[c][i]=j=0; j < colors; j++)
+ cam_xyz[c][i] += cc[c][j] * cm[j][i] * xyz[i];
+ cam_xyz_coeff (cam_xyz);
+ }
+ if (asn[0])
+ FORCC pre_mul[c] = 1 / asn[c];
+ if (!use_cm)
+ FORCC pre_mul[c] /= cc[c][c];
+ return done;
+}
+
+void CLASS parse_tiff (int base)
+{
+ int doff, maxifd=1000;
+
+ fseek (ifp, base, SEEK_SET);
+ order = get2();
+ if (order != 0x4949 && order != 0x4d4d) return;
+ get2();
+ while ((doff = get4()) && maxifd--) {
+ fseek (ifp, doff+base, SEEK_SET);
+ if (parse_tiff_ifd (base, 0)) break;
+ if (!dng_version && data_offset == 8) make[0] = 0;
+ }
+ if (!dng_version && !strncmp(make,"Kodak",5)) {
+ fseek (ifp, 12+base, SEEK_SET);
+ parse_tiff_ifd (base, 2);
+ }
+}
+
+void CLASS parse_minolta()
+{
+ int save, tag, len, offset, high=0, wide=0, i, c;
+
+ fseek (ifp, 4, SEEK_SET);
+ offset = get4() + 8;
+ while ((save=ftell(ifp)) < offset) {
+ tag = get4();
+ len = get4();
+ switch (tag) {
+ case 0x505244: /* PRD */
+ fseek (ifp, 8, SEEK_CUR);
+ high = get2();
+ wide = get2();
+ break;
+ case 0x574247: /* WBG */
+ get4();
+ i = strstr(model,"A200") ? 3:0;
+ FORC4 cam_mul[c ^ (c >> 1) ^ i] = get2();
+ break;
+ case 0x545457: /* TTW */
+ parse_tiff (ftell(ifp));
+ }
+ fseek (ifp, save+len+8, SEEK_SET);
+ }
+ raw_height = high;
+ raw_width = wide;
+ data_offset = offset;
+}
+
+/*
+ Many cameras have a "debug mode" that writes JPEG and raw
+ at the same time. The raw file has no header, so try to
+ to open the matching JPEG file and read its metadata.
+ */
+void CLASS parse_external_jpeg()
+{
+ char *file, *ext, *jname, *jfile, *jext;
+ FILE *save=ifp;
+
+ ext = strrchr (ifname, '.');
+ file = strrchr (ifname, '/');
+ if (!file) file = strrchr (ifname, '\\');
+ if (!file) file = ifname-1;
+ file++;
+ if (strlen(ext) != 4 || ext-file != 8) return;
+ jname = malloc (strlen(ifname) + 1);
+ merror (jname, "parse_external()");
+ strcpy (jname, ifname);
+ jfile = file - ifname + jname;
+ jext = ext - ifname + jname;
+ if (strcasecmp (ext, ".jpg")) {
+ strcpy (jext, isupper(ext[1]) ? ".JPG":".jpg");
+ memcpy (jfile, file+4, 4);
+ memcpy (jfile+4, file, 4);
+ } else
+ while (isdigit(*--jext)) {
+ if (*jext != '9') {
+ (*jext)++;
+ break;
+ }
+ *jext = '0';
+ }
+ if (strcmp (jname, ifname)) {
+ if ((ifp = fopen (jname, "rb"))) {
+ if (verbose)
+ fprintf (stderr, "Reading metadata from %s...\n", jname);
+ parse_tiff (12);
+ fclose (ifp);
+ }
+ }
+ if (!timestamp)
+ fprintf (stderr, "Failed to read metadata from %s\n", jname);
+ free (jname);
+ ifp = save;
+}
+
+/*
+ CIFF block 0x1030 contains an 8x8 white sample.
+ Load this into white[][] for use in scale_colors().
+ */
+void CLASS ciff_block_1030()
+{
+ static const ushort key[] = { 0x410, 0x45f3 };
+ int i, bpp, row, col, vbits=0;
+ unsigned long bitbuf=0;
+
+ get2();
+ if (get4() != 0x80008) return;
+ if (get4() == 0) return;
+ bpp = get2();
+ if (bpp != 10 && bpp != 12) return;
+ for (i=row=0; row < 8; row++)
+ for (col=0; col < 8; col++) {
+ if (vbits < bpp) {
+ bitbuf = bitbuf << 16 | (get2() ^ key[i++ & 1]);
+ vbits += 16;
+ }
+ white[row][col] =
+ bitbuf << (LONG_BIT - vbits) >> (LONG_BIT - bpp);
+ vbits -= bpp;
+ }
+}
+
+/*
+ Parse a CIFF file, better known as Canon CRW format.
+ */
+void CLASS parse_ciff (int offset, int length)
+{
+ int tboff, nrecs, i, c, type, len, roff, aoff, save, wbi=-1;
+ static const int remap[] = { 1,2,3,4,5,1 };
+ static const int remap_10d[] = { 0,1,3,4,5,6,0,0,2,8 };
+ static const int remap_s70[] = { 0,1,2,9,4,3,6,7,8,9,10,0,0,0,7,0,0,8 };
+ ushort key[] = { 0x410, 0x45f3 };
+
+ if (strcmp(model,"Canon PowerShot G6") &&
+ strcmp(model,"Canon PowerShot S60") &&
+ strcmp(model,"Canon PowerShot S70") &&
+ strcmp(model,"Canon PowerShot Pro1"))
+ key[0] = key[1] = 0;
+ fseek (ifp, offset+length-4, SEEK_SET);
+ tboff = get4() + offset;
+ fseek (ifp, tboff, SEEK_SET);
+ nrecs = get2();
+ if (nrecs > 100) return;
+ for (i = 0; i < nrecs; i++) {
+ type = get2();
+ len = get4();
+ roff = get4();
+ aoff = offset + roff;
+ save = ftell(ifp);
+ if (type == 0x080a) { /* Get the camera make and model */
+ fseek (ifp, aoff, SEEK_SET);
+ fread (make, 64, 1, ifp);
+ fseek (ifp, aoff+strlen(make)+1, SEEK_SET);
+ fread (model, 64, 1, ifp);
+ }
+ if (type == 0x102a) { /* Find the White Balance index */
+ fseek (ifp, aoff+14, SEEK_SET); /* 0=auto, 1=daylight, 2=cloudy ... */
+ wbi = get2();
+ if (((!strcmp(model,"Canon EOS DIGITAL REBEL") ||
+ !strcmp(model,"Canon EOS 300D DIGITAL"))) && wbi == 6)
+ wbi++;
+ }
+ if (type == 0x102c) { /* Get white balance (G2) */
+ if (!strcmp(model,"Canon PowerShot G1") ||
+ !strcmp(model,"Canon PowerShot Pro90 IS")) {
+ fseek (ifp, aoff+120, SEEK_SET);
+ FORC4 cam_mul[c ^ 2] = get2();
+ } else {
+ fseek (ifp, aoff+100, SEEK_SET);
+ goto common;
+ }
+ }
+ if (type == 0x0032) { /* Get white balance (D30 & G3) */
+ if (!strcmp(model,"Canon EOS D30")) {
+ fseek (ifp, aoff+72, SEEK_SET);
+common:
+ camera_red = get2() ^ key[0];
+ camera_red =(get2() ^ key[1]) / camera_red;
+ camera_blue = get2() ^ key[0];
+ camera_blue /= get2() ^ key[1];
+ if (!wbi) camera_red = -1; /* Use my auto WB for this photo */
+ } else if (!strcmp(model,"Canon PowerShot G6") ||
+ !strcmp(model,"Canon PowerShot S60") ||
+ !strcmp(model,"Canon PowerShot S70")) {
+ fseek (ifp, aoff+96 + remap_s70[wbi]*8, SEEK_SET);
+ goto common;
+ } else if (!strcmp(model,"Canon PowerShot Pro1")) {
+ fseek (ifp, aoff+96 + wbi*8, SEEK_SET);
+ goto common;
+ } else {
+ fseek (ifp, aoff+80 + (wbi < 6 ? remap[wbi]*8 : 0), SEEK_SET);
+ if (!camera_red)
+ goto common;
+ }
+ }
+ if (type == 0x10a9) { /* Get white balance (D60) */
+ if (!strcmp(model,"Canon EOS 10D"))
+ wbi = remap_10d[wbi];
+ fseek (ifp, aoff+2 + wbi*8, SEEK_SET);
+ camera_red = get2();
+ camera_red /= get2();
+ camera_blue = get2();
+ camera_blue = get2() / camera_blue;
+ }
+ if (type == 0x1030 && (wbi == 6 || wbi == 15)) {
+ fseek (ifp, aoff, SEEK_SET); /* Get white sample */
+ ciff_block_1030();
+ }
+ if (type == 0x1031) { /* Get the raw width and height */
+ fseek (ifp, aoff+2, SEEK_SET);
+ raw_width = get2();
+ raw_height = get2();
+ }
+ if (type == 0x180e) { /* Get the timestamp */
+ fseek (ifp, aoff, SEEK_SET);
+ timestamp = get4();
+ }
+ if (type == 0x5817)
+ shot_order = len;
+ if (type == 0x580e)
+ timestamp = len;
+#ifdef LOCALTIME
+ if ((type | 0x4000) == 0x580e)
+ timestamp = mktime (gmtime (&timestamp));
+#endif
+ if (type == 0x5813)
+ flash_used = int_to_float(len);
+ if (type == 0x5814)
+ canon_5814 = int_to_float(len);
+ if (type == 0x1810) { /* Get the rotation */
+ fseek (ifp, aoff+12, SEEK_SET);
+ flip = get4();
+ }
+ if (type == 0x1835) { /* Get the decoder table */
+ fseek (ifp, aoff, SEEK_SET);
+ crw_init_tables (get4());
+ }
+ if (type >> 8 == 0x28 || type >> 8 == 0x30) /* Get sub-tables */
+ parse_ciff(aoff, len);
+ fseek (ifp, save, SEEK_SET);
+ }
+}
+
+void CLASS parse_rollei()
+{
+ char line[128], *val;
+ int tx=0, ty=0;
+ struct tm t;
+
+ fseek (ifp, 0, SEEK_SET);
+ do {
+ fgets (line, 128, ifp);
+ if ((val = strchr(line,'=')))
+ *val++ = 0;
+ else
+ val = line + strlen(line);
+ if (!strcmp(line,"DAT"))
+ sscanf (val, "%d.%d.%d", &t.tm_mday, &t.tm_mon, &t.tm_year);
+ if (!strcmp(line,"TIM"))
+ sscanf (val, "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec);
+ if (!strcmp(line,"HDR"))
+ data_offset = atoi(val);
+ if (!strcmp(line,"X "))
+ raw_width = atoi(val);
+ if (!strcmp(line,"Y "))
+ raw_height = atoi(val);
+ if (!strcmp(line,"TX "))
+ tx = atoi(val);
+ if (!strcmp(line,"TY "))
+ ty = atoi(val);
+ } while (strncmp(line,"EOHD",4));
+ t.tm_year -= 1900;
+ t.tm_mon -= 1;
+ if (mktime(&t) > 0)
+ timestamp = mktime(&t);
+ data_offset += tx * ty * 2;
+ strcpy (make, "Rollei");
+ strcpy (model,"d530flex");
+}
+
+void CLASS parse_mos (int offset)
+{
+ char data[40];
+ int skip, from, i, c, neut[4];
+ static const unsigned bayer[] =
+ { 0x94949494, 0x61616161, 0x16161616, 0x49494949 };
+
+ fseek (ifp, offset, SEEK_SET);
+ while (1) {
+ fread (data, 1, 8, ifp);
+ if (strcmp(data,"PKTS")) break;
+ if (!make[0]) strcpy(make,"Leaf");
+ fread (data, 1, 40, ifp);
+ skip = get4();
+ from = ftell(ifp);
+#ifdef USE_LCMS
+ if (!strcmp(data,"icc_camera_profile")) {
+ profile_length = skip;
+ profile_offset = from;
+ }
+#endif
+ if (!strcmp(data,"CaptProf_number_of_planes")) {
+ fscanf (ifp, "%d", &i);
+ if (i > 1) filters = 0;
+ }
+ if (!strcmp(data,"CaptProf_raw_data_rotation") && filters) {
+ fscanf (ifp, "%d", &i);
+ filters = bayer[i/90];
+ }
+ if (!strcmp(data,"NeutObj_neutrals")) {
+ for (i=0; i < 4; i++)
+ fscanf (ifp, "%d", neut+i);
+ FORC3 cam_mul[c] = 1.0 / neut[c+1];
+ }
+ parse_mos (from);
+ fseek (ifp, skip+from, SEEK_SET);
+ }
+}
+
+void CLASS parse_phase_one (int base)
+{
+ unsigned entries, tag, type, len, data, save, i, c;
+ char *cp;
+
+ fseek (ifp, base, SEEK_SET);
+ order = get4() & 0xffff;
+ if (get4() >> 8 != 0x526177) return; /* "Raw" */
+ fseek (ifp, base+get4(), SEEK_SET);
+ entries = get4();
+ get4();
+ while (entries--) {
+ tag = get4();
+ type = get4();
+ len = get4();
+ data = get4();
+ save = ftell(ifp);
+ fseek (ifp, base+data, SEEK_SET);
+ switch (tag) {
+ case 0x106:
+ for (raw_color = i=0; i < 3; i++)
+ FORC3 rgb_cam[i][c] = int_to_float(get4());
+ break;
+ case 0x107:
+ FORC3 cam_mul[c] = pre_mul[c] = int_to_float(get4());
+ break;
+ case 0x108: raw_width = data; break;
+ case 0x109: raw_height = data; break;
+ case 0x10a: left_margin = data; break;
+ case 0x10b: top_margin = data; break;
+ case 0x10c: width = data; break;
+ case 0x10d: height = data; break;
+ case 0x10e: tiff_data_compression = data; break;
+ case 0x10f: data_offset = data+base; break;
+ case 0x112:
+ nikon_curve_offset = save - 4; break;
+ case 0x301:
+ fread (model, 64, 1, ifp);
+ cp = strstr(model," camera");
+ if (cp && cp < model+64) *cp = 0;
+ }
+ fseek (ifp, save, SEEK_SET);
+ }
+ load_raw = tiff_data_compression < 3 ?
+ phase_one_load_raw:phase_one_load_raw_c;
+ strcpy (make, "Phase One");
+ if (model[0]) return;
+ sprintf (model, "%dx%d", width, height);
+ switch (raw_height) {
+ case 2060: strcpy (model,"LightPhase"); break;
+ case 2682: strcpy (model,"H 10"); break;
+ case 4128: strcpy (model,"H 20"); break;
+ case 5488: strcpy (model,"H 25"); break;
+ }
+}
+
+void CLASS parse_fuji (int offset)
+{
+ int entries, tag, len, save, c;
+
+ fseek (ifp, offset, SEEK_SET);
+ entries = get4();
+ if (entries > 255) return;
+ while (entries--) {
+ tag = get2();
+ len = get2();
+ save = ftell(ifp);
+ if (tag == 0x100) {
+ raw_height = get2();
+ raw_width = get2();
+ } else if (tag == 0x121) {
+ height = get2();
+ if ((width = get2()) == 4284) width += 3;
+ } else if (tag == 0x130)
+ fuji_layout = fgetc(ifp) >> 7;
+ if (tag == 0x2ff0)
+ FORC4 cam_mul[c ^ 1] = get2();
+ fseek (ifp, save+len, SEEK_SET);
+ }
+ if (fuji_layout) {
+ height *= 2;
+ width /= 2;
+ }
+}
+
+int CLASS parse_jpeg (int offset)
+{
+ int len, save, hlen;
+
+ fseek (ifp, offset, SEEK_SET);
+ if (fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) return 0;
+
+ while (fgetc(ifp) == 0xff && fgetc(ifp) >> 4 != 0xd) {
+ order = 0x4d4d;
+ len = get2() - 2;
+ save = ftell(ifp);
+ order = get2();
+ hlen = get4();
+ if (get4() == 0x48454150) /* "HEAP" */
+ parse_ciff (save+hlen, len-hlen);
+ parse_tiff (save+6);
+ fseek (ifp, save+len, SEEK_SET);
+ }
+ return 1;
+}
+
+void CLASS parse_riff()
+{
+ unsigned i, size, end;
+ char tag[4], date[64], month[64];
+ static const char mon[12][4] =
+ { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" };
+ struct tm t;
+
+ order = 0x4949;
+ fread (tag, 4, 1, ifp);
+ size = get4();
+ if (!memcmp(tag,"RIFF",4) || !memcmp(tag,"LIST",4)) {
+ end = ftell(ifp) + size;
+ get4();
+ while (ftell(ifp) < end)
+ parse_riff();
+ } else if (!memcmp(tag,"IDIT",4) && size < 64) {
+ fread (date, 64, 1, ifp);
+ date[size] = 0;
+ if (sscanf (date, "%*s %s %d %d:%d:%d %d", month, &t.tm_mday,
+ &t.tm_hour, &t.tm_min, &t.tm_sec, &t.tm_year) == 6) {
+ for (i=0; i < 12 && strcmp(mon[i],month); i++);
+ t.tm_mon = i;
+ t.tm_year -= 1900;
+ if (mktime(&t) > 0)
+ timestamp = mktime(&t);
+ }
+ } else
+ fseek (ifp, size, SEEK_CUR);
+}
+
+void CLASS parse_smal (int offset, int fsize)
+{
+ int ver;
+
+ fseek (ifp, offset+2, SEEK_SET);
+ order = 0x4949;
+ ver = fgetc(ifp);
+ if (ver == 6)
+ fseek (ifp, 5, SEEK_CUR);
+ if (get4() != fsize) return;
+ if (ver > 6) data_offset = get4();
+ raw_height = height = get2();
+ raw_width = width = get2();
+ strcpy (make, "SMaL");
+ sprintf (model, "v%d %dx%d", ver, width, height);
+ if (ver == 6) load_raw = smal_v6_load_raw;
+ if (ver == 9) load_raw = smal_v9_load_raw;
+}
+
+char * CLASS foveon_gets (int offset, char *str, int len)
+{
+ int i;
+ fseek (ifp, offset, SEEK_SET);
+ for (i=0; i < len-1; i++)
+ if ((str[i] = get2()) == 0) break;
+ str[i] = 0;
+ return str;
+}
+
+void CLASS parse_foveon()
+{
+ int entries, off, len, tag, save, i, wide, high, pent, poff[256][2];
+ char name[64];
+
+ order = 0x4949; /* Little-endian */
+ fseek (ifp, 36, SEEK_SET);
+ flip = get4();
+ fseek (ifp, -4, SEEK_END);
+ fseek (ifp, get4(), SEEK_SET);
+ if (get4() != 0x64434553) return; /* SECd */
+ get4();
+ entries = get4();
+ while (entries--) {
+ off = get4();
+ len = get4();
+ tag = get4();
+ save = ftell(ifp);
+ fseek (ifp, off, SEEK_SET);
+ if (get4() != (0x20434553 | (tag << 24))) return;
+ switch (tag) {
+ case 0x47414d49: /* IMAG */
+ case 0x32414d49: /* IMA2 */
+ fseek (ifp, 12, SEEK_CUR);
+ wide = get4();
+ high = get4();
+ if (wide > raw_width && high > raw_height) {
+ raw_width = wide;
+ raw_height = high;
+ data_offset = off + 24;
+ }
+ break;
+ case 0x464d4143: /* CAMF */
+ meta_offset = off + 24;
+ meta_length = len - 28;
+ if (meta_length > 0x20000)
+ meta_length = 0x20000;
+ break;
+ case 0x504f5250: /* PROP */
+ get4();
+ pent = get4();
+ fseek (ifp, 12, SEEK_CUR);
+ off += pent*8 + 24;
+ if (pent > 256) pent=256;
+ for (i=0; i < pent*2; i++)
+ poff[0][i] = off + get4()*2;
+ for (i=0; i < pent; i++) {
+ foveon_gets (poff[i][0], name, 64);
+ if (!strcmp (name, "CAMMANUF"))
+ foveon_gets (poff[i][1], make, 64);
+ if (!strcmp (name, "CAMMODEL"))
+ foveon_gets (poff[i][1], model, 64);
+ if (!strcmp (name, "WB_DESC"))
+ foveon_gets (poff[i][1], model2, 64);
+ if (!strcmp (name, "TIME"))
+ timestamp = atoi (foveon_gets (poff[i][1], name, 64));
+ }
+#ifdef LOCALTIME
+ timestamp = mktime (gmtime (&timestamp));
+#endif
+ }
+ fseek (ifp, save, SEEK_SET);
+ }
+ is_foveon = 1;
+}
+
+/*
+ Thanks to Adobe for providing these excellent CAM -> XYZ matrices!
+ */
+void CLASS adobe_coeff()
+{
+ static const struct {
+ const char *prefix;
+ short trans[12];
+ } table[] = {
+ { "Canon EOS D2000",
+ { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } },
+ { "Canon EOS D6000",
+ { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } },
+ { "Canon EOS D30",
+ { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } },
+ { "Canon EOS D60",
+ { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } },
+ { "Canon EOS 5D",
+ { 6228,-404,-967,-8314,16108,2312,-1923,2179,7499 } },
+ { "Canon EOS 20D",
+ { 6599,-537,-891,-8071,15783,2424,-1983,2234,7462 } },
+ { "Canon EOS 350D",
+ { 6018,-617,-965,-8645,15881,2975,-1530,1719,7642 } },
+ { "Canon EOS DIGITAL REBEL XT",
+ { 6018,-617,-965,-8645,15881,2975,-1530,1719,7642 } },
+ { "Canon EOS-1Ds Mark II",
+ { 6517,-602,-867,-8180,15926,2378,-1618,1771,7633 } },
+ { "Canon EOS-1D Mark II",
+ { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } },
+ { "Canon EOS-1DS",
+ { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } },
+ { "Canon EOS-1D",
+ { 6806,-179,-1020,-8097,16415,1687,-3267,4236,7690 } },
+ { "Canon EOS",
+ { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } },
+ { "Canon PowerShot A50",
+ { -5300,9846,1776,3436,684,3939,-5540,9879,6200,-1404,11175,217 } },
+ { "Canon PowerShot A5",
+ { -4801,9475,1952,2926,1611,4094,-5259,10164,5947,-1554,10883,547 } },
+ { "Canon PowerShot G1",
+ { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } },
+ { "Canon PowerShot G2",
+ { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } },
+ { "Canon PowerShot G3",
+ { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } },
+ { "Canon PowerShot G5",
+ { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } },
+ { "Canon PowerShot G6",
+ { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } },
+ { "Canon PowerShot Pro1",
+ { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } },
+ { "Canon PowerShot Pro70",
+ { -4155,9818,1529,3939,-25,4522,-5521,9870,6610,-2238,10873,1342 } },
+ { "Canon PowerShot Pro90",
+ { -4963,9896,2235,4642,-987,4294,-5162,10011,5859,-1770,11230,577 } },
+ { "Canon PowerShot S30",
+ { 10566,-3652,-1129,-6552,14662,2006,-2197,2581,7670 } },
+ { "Canon PowerShot S40",
+ { 8510,-2487,-940,-6869,14231,2900,-2318,2829,9013 } },
+ { "Canon PowerShot S45",
+ { 8163,-2333,-955,-6682,14174,2751,-2077,2597,8041 } },
+ { "Canon PowerShot S50",
+ { 8882,-2571,-863,-6348,14234,2288,-1516,2172,6569 } },
+ { "Canon PowerShot S60",
+ { 8795,-2482,-797,-7804,15403,2573,-1422,1996,7082 } },
+ { "Canon PowerShot S70",
+ { 9976,-3810,-832,-7115,14463,2906,-901,989,7889 } },
+ { "Contax N Digital",
+ { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } },
+ { "EPSON R-D1",
+ { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } },
+ { "FUJIFILM FinePix E550",
+ { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } },
+ { "FUJIFILM FinePix F8",
+ { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } },
+ { "FUJIFILM FinePix F7",
+ { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } },
+ { "FUJIFILM FinePix S20Pro",
+ { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } },
+ { "FUJIFILM FinePix S2Pro",
+ { 12492,-4690,-1402,-7033,15423,1647,-1507,2111,7697 } },
+ { "FUJIFILM FinePix S3Pro",
+ { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } },
+ { "FUJIFILM FinePix S5000",
+ { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } },
+ { "FUJIFILM FinePix S5100",
+ { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } },
+ { "FUJIFILM FinePix S7000",
+ { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } },
+ { "FUJIFILM FinePix S9", /* copied from S7000 */
+ { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } },
+ { "KODAK NC2000F", /* DJC */
+ { 16475,-6903,-1218,-851,10375,477,2505,-7,1020 } },
+ { "Kodak DCS315C",
+ { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } },
+ { "Kodak DCS330C",
+ { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } },
+ { "KODAK DCS420",
+ { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } },
+ { "KODAK DCS460",
+ { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } },
+ { "KODAK EOSDCS1",
+ { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } },
+ { "KODAK EOSDCS3B",
+ { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } },
+ { "Kodak DCS520C",
+ { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } },
+ { "Kodak DCS560C",
+ { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } },
+ { "Kodak DCS620C",
+ { 23617,-10175,-3149,-2054,11749,-272,2586,-489,3453 } },
+ { "Kodak DCS620X",
+ { 13095,-6231,154,12221,-21,-2137,895,4602,2258 } },
+ { "Kodak DCS660C",
+ { 18244,-6351,-2739,-791,11193,-521,3711,-129,2802 } },
+ { "Kodak DCS720X",
+ { 11775,-5884,950,9556,1846,-1286,-1019,6221,2728 } },
+ { "Kodak DCS760C",
+ { 16623,-6309,-1411,-4344,13923,323,2285,274,2926 } },
+ { "Kodak DCS Pro SLR",
+ { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } },
+ { "Kodak DCS Pro 14nx",
+ { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } },
+ { "Kodak DCS Pro 14",
+ { 7791,3128,-776,-8588,16458,2039,-2455,4006,6198 } },
+ { "Kodak ProBack645",
+ { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } },
+ { "Kodak ProBack",
+ { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } },
+ { "LEICA DIGILUX 2",
+ { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } },
+ { "Leaf Valeo",
+ { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } },
+ { "Minolta DiMAGE 5",
+ { 8983,-2942,-963,-6556,14476,2237,-2426,2887,8014 } },
+ { "Minolta DiMAGE 7Hi",
+ { 11368,-3894,-1242,-6521,14358,2339,-2475,3056,7285 } },
+ { "Minolta DiMAGE 7",
+ { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } },
+ { "Minolta DiMAGE A1",
+ { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } },
+ { "MINOLTA DiMAGE A200",
+ { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } },
+ { "Minolta DiMAGE A2",
+ { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } },
+ { "Minolta DiMAGE Z2",
+ { 11428,-3512,-1706,-5895,13815,2266,-2382,2719,5651 } },
+ { "MINOLTA DYNAX 5",
+ { 10284,-3283,-1086,-7957,15762,2316,-829,882,6644 } },
+ { "MINOLTA DYNAX 7",
+ { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } },
+ { "NIKON D100",
+ { 5902,-933,-782,-8983,16719,2354,-1402,1455,6464 } },
+ { "NIKON D1H",
+ { 7577,-2166,-926,-7454,15592,1934,-2377,2808,8606 } },
+ { "NIKON D1X",
+ { 7702,-2245,-975,-9114,17242,1875,-2679,3055,8521 } },
+ { "NIKON D1",
+ { 7559,-2130,-965,-7611,15713,1972,-2478,3042,8290 } },
+ { "NIKON D2H",
+ { 5710,-901,-615,-8594,16617,2024,-2975,4120,6830 } },
+ { "NIKON D2X",
+ { 10231,-2769,-1255,-8301,15900,2552,-797,680,7148 } },
+ { "NIKON D50",
+ { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } },
+ { "NIKON D70",
+ { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } },
+ { "NIKON E995", /* copied from E5000 */
+ { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
+ { "NIKON E2500",
+ { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
+ { "NIKON E4500",
+ { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
+ { "NIKON E5000",
+ { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
+ { "NIKON E5400",
+ { 9349,-2987,-1001,-7919,15766,2266,-2098,2680,6839 } },
+ { "NIKON E5700",
+ { -5368,11478,2368,5537,-113,3148,-4969,10021,5782,778,9028,211 } },
+ { "NIKON E8400",
+ { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } },
+ { "NIKON E8700",
+ { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } },
+ { "NIKON E8800",
+ { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } },
+ { "OLYMPUS C5050",
+ { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } },
+ { "OLYMPUS C5060",
+ { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } },
+ { "OLYMPUS C70",
+ { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } },
+ { "OLYMPUS C80",
+ { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } },
+ { "OLYMPUS E-10",
+ { 12745,-4500,-1416,-6062,14542,1580,-1934,2256,6603 } },
+ { "OLYMPUS E-1",
+ { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } },
+ { "OLYMPUS E-20",
+ { 13173,-4732,-1499,-5807,14036,1895,-2045,2452,7142 } },
+ { "OLYMPUS E-300",
+ { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } },
+ { "OLYMPUS E-500", /* copied from E-300 */
+ { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } },
+ { "PENTAX *ist DS",
+ { 10371,-2333,-1206,-8688,16231,2602,-1230,1116,11282 } },
+ { "PENTAX *ist D",
+ { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } },
+ { "Panasonic DMC-FZ30",
+ { 10976,-4029,-1141,-7918,15491,2600,-1670,2071,8246 } },
+ { "Panasonic DMC-LC1",
+ { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } },
+ { "Panasonic DMC-LX1",
+ { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } },
+ { "SONY DSC-F828",
+ { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,3481 } },
+ { "SONY DSC-R1", /* DJC */
+ { 10528,-3695,-517,-2822,10699,2124,406,1240,5342 } },
+ { "SONY DSC-V3",
+ { 7511,-2571,-692,-7894,15088,3060,-948,1111,8128 } }
+ };
+ double cam_xyz[4][3];
+ char name[130];
+ int i, j;
+
+ sprintf (name, "%s %s", make, model);
+ for (i=0; i < sizeof table / sizeof *table; i++)
+ if (!strncmp (name, table[i].prefix, strlen(table[i].prefix))) {
+ for (j=0; j < 12; j++)
+ cam_xyz[0][j] = table[i].trans[j];
+ cam_xyz_coeff (cam_xyz);
+ break;
+ }
+}
+
+void CLASS simple_coeff (int index)
+{
+ static const float table[][12] = {
+ /* index 0 -- all Foveon cameras */
+ { 1.4032,-0.2231,-0.1016,-0.5263,1.4816,0.017,-0.0112,0.0183,0.9113 },
+ /* index 1 -- Kodak DC20 and DC25 */
+ { 2.25,0.75,-1.75,-0.25,-0.25,0.75,0.75,-0.25,-0.25,-1.75,0.75,2.25 },
+ /* index 2 -- Logitech Fotoman Pixtura */
+ { 1.893,-0.418,-0.476,-0.495,1.773,-0.278,-1.017,-0.655,2.672 },
+ /* index 3 -- Nikon E700, E800, and E950 */
+ { -1.936280, 1.800443, -1.448486, 2.584324,
+ 1.405365, -0.524955, -0.289090, 0.408680,
+ -1.204965, 1.082304, 2.941367, -1.818705 }
+ };
+ int i, c;
+
+ for (raw_color = i=0; i < 3; i++)
+ FORCC rgb_cam[i][c] = table[index][i*colors+c];
+}
+
+short CLASS guess_byte_order (int words)
+{
+ uchar test[4][2];
+ int t=2, msb;
+ double diff, sum[2] = {0,0};
+
+ fread (test[0], 2, 2, ifp);
+ for (words-=2; words--; ) {
+ fread (test[t], 2, 1, ifp);
+ for (msb=0; msb < 2; msb++) {
+ diff = (test[t^2][msb] << 8 | test[t^2][!msb])
+ - (test[t ][msb] << 8 | test[t ][!msb]);
+ sum[msb] += diff*diff;
+ }
+ t = (t+1) & 3;
+ }
+ return sum[0] < sum[1] ? 0x4d4d : 0x4949;
+}
+
+/*
+ Identify which camera created this file, and set global variables
+ accordingly. Return nonzero if the file cannot be decoded.
+ */
+int CLASS identify (int no_decode)
+{
+ char head[32], *cp;
+ unsigned hlen, fsize, i, c, is_jpeg=0, is_canon;
+ static const struct {
+ int fsize;
+ char make[12], model[15], withjpeg;
+ } table[] = {
+ { 62464, "Kodak", "DC20" ,0 },
+ { 124928, "Kodak", "DC20" ,0 },
+ { 311696, "ST Micro", "STV680 VGA" ,0 }, /* SPYz */
+ { 787456, "Creative", "PC-CAM 600" ,0 },
+ { 1138688, "Minolta", "RD175" ,0 },
+ { 3840000, "Foculus", "531C" ,0 },
+ { 1920000, "AVT", "F-201C" ,0 },
+ { 5067304, "AVT", "F-510C" ,0 },
+ { 10134608, "AVT", "F-510C" ,0 },
+ { 16157136, "AVT", "F-810C" ,0 },
+ { 6624000, "Pixelink", "A782" ,0 },
+ { 13248000, "Pixelink", "A782" ,0 },
+ { 6291456, "RoverShot","3320AF" ,0 },
+ { 5939200, "OLYMPUS", "C770UZ" ,0 },
+ { 1581060, "NIKON", "E900" ,1 }, /* or E900s,E910 */
+ { 2465792, "NIKON", "E950" ,1 }, /* or E800,E700 */
+ { 2940928, "NIKON", "E2100" ,1 }, /* or E2500 */
+ { 4771840, "NIKON", "E990" ,1 }, /* or E995 */
+ { 4775936, "NIKON", "E3700" ,1 }, /* or Optio 33WR */
+ { 5869568, "NIKON", "E4300" ,1 }, /* or DiMAGE Z2 */
+ { 5865472, "NIKON", "E4500" ,1 },
+ { 7438336, "NIKON", "E5000" ,1 }, /* or E5700 */
+ { 1976352, "CASIO", "QV-2000UX" ,1 },
+ { 3217760, "CASIO", "QV-3*00EX" ,1 },
+ { 6218368, "CASIO", "QV-5700" ,1 },
+ { 7530816, "CASIO", "QV-R51" ,1 },
+ { 7684000, "CASIO", "QV-4000" ,1 },
+ { 4948608, "CASIO", "EX-S100" ,1 },
+ { 7542528, "CASIO", "EX-Z50" ,1 },
+ { 7753344, "CASIO", "EX-Z55" ,1 },
+ { 7426656, "CASIO", "EX-P505" ,1 },
+ { 9313536, "CASIO", "EX-P600" ,1 },
+ { 10979200, "CASIO", "EX-P700" ,1 },
+ { 3178560, "PENTAX", "Optio S" ,1 }, /* 8-bit */
+ { 4841984, "PENTAX", "Optio S" ,1 }, /* 12-bit */
+ { 6114240, "PENTAX", "Optio S4" ,1 }, /* or S4i */
+ { 12582980, "Sinar", "" ,0 } };
+ static const char *corp[] =
+ { "Canon", "NIKON", "EPSON", "KODAK", "Kodak", "OLYMPUS", "PENTAX",
+ "MINOLTA", "Minolta", "Konica", "CASIO", "Sinar" };
+
+/* What format is this file? Set make[] if we recognize it. */
+
+ load_raw = NULL;
+ raw_height = raw_width = fuji_width = flip = 0;
+ height = width = top_margin = left_margin = 0;
+ make[0] = model[0] = model2[0] = 0;
+ memset (white, 0, sizeof white);
+ data_offset = meta_length = tiff_bps = tiff_data_compression = 0;
+ kodak_cbpp = zero_after_ff = dng_version = fuji_secondary = 0;
+ timestamp = shot_order = tiff_samples = black = is_foveon = 0;
+ raw_color = use_gamma = xmag = ymag = 1;
+ filters = UINT_MAX; /* 0 = no filters, UINT_MAX = unknown */
+ for (i=0; i < 4; i++) {
+ cam_mul[i] = i == 1;
+ pre_mul[i] = i < 3;
+ FORC3 rgb_cam[c][i] = c == i;
+ }
+ colors = 3;
+ for (i=0; i < 0x1000; i++) curve[i] = i;
+ maximum = 0xfff;
+#ifdef USE_LCMS
+ profile_length = 0;
+#endif
+
+ order = get2();
+ hlen = get4();
+ fseek (ifp, 0, SEEK_SET);
+ fread (head, 1, 32, ifp);
+ fseek (ifp, 0, SEEK_END);
+ fsize = ftell(ifp);
+ if ((cp = memmem (head, 32, "MMMM", 4)) ||
+ (cp = memmem (head, 32, "IIII", 4)))
+ parse_phase_one (cp-head);
+ else if (order == 0x4949 || order == 0x4d4d) {
+ if (!memcmp (head+6,"HEAPCCDR",8)) {
+ data_offset = hlen;
+ parse_ciff (hlen, fsize - hlen);
+ } else {
+ parse_tiff(0);
+ if (!dng_version && !strncmp(make,"NIKON",5) && filters == UINT_MAX)
+ make[0] = 0;
+ }
+ } else if (!memcmp (head,"\xff\xd8\xff\xe1",4) &&
+ !memcmp (head+6,"Exif",4)) {
+ fseek (ifp, 4, SEEK_SET);
+ fseek (ifp, 4 + get2(), SEEK_SET);
+ if (fgetc(ifp) != 0xff)
+ parse_tiff(12);
+ } else if (!memcmp (head,"BM",2) &&
+ head[26] == 1 && head[28] == 16 && head[30] == 0) {
+ data_offset = 0x1000;
+ order = 0x4949;
+ fseek (ifp, 38, SEEK_SET);
+ if (get4() == 2834 && get4() == 2834 && get4() == 0 && get4() == 4096) {
+ strcpy (model, "BMQ");
+ flip = 3;
+ goto nucore;
+ }
+ } else if (!memcmp (head,"BR",2)) {
+ strcpy (model, "RAW");
+nucore:
+ strcpy (make, "Nucore");
+ order = 0x4949;
+ fseek (ifp, 10, SEEK_SET);
+ data_offset += get4();
+ get4();
+ raw_width = get4();
+ raw_height = get4();
+ if (model[0] == 'B' && raw_width == 2597) {
+ raw_width++;
+ data_offset -= 0x1000;
+ }
+ } else if (!memcmp (head+25,"ARECOYK",7)) {
+ strcpy (make, "Contax");
+ strcpy (model,"N Digital");
+ fseek (ifp, 33, SEEK_SET);
+ get_timestamp(1);
+ fseek (ifp, 60, SEEK_SET);
+ FORC4 cam_mul[c ^ (c >> 1)] = get4();
+ } else if (!strcmp (head, "PXN")) {
+ strcpy (make, "Logitech");
+ strcpy (model,"Fotoman Pixtura");
+ } else if (!memcmp (head,"FUJIFILM",8)) {
+ fseek (ifp, 92, SEEK_SET);
+ parse_fuji (get4());
+ fseek (ifp, 84, SEEK_SET);
+ if ((hlen = get4()) > 120) {
+ fseek (ifp, 120, SEEK_SET);
+ fuji_secondary = (i = get4()) && 1;
+ if (fuji_secondary && use_secondary)
+ parse_fuji (i);
+ }
+ fseek (ifp, 100, SEEK_SET);
+ i = get4();
+ parse_tiff (hlen+12);
+ data_offset = i;
+ } else if (!memcmp (head,"RIFF",4)) {
+ fseek (ifp, 0, SEEK_SET);
+ parse_riff();
+ } else if (!memcmp (head,"DSC-Image",9))
+ parse_rollei();
+ else if (!memcmp (head,"\0MRM",4))
+ parse_minolta();
+ else if (!memcmp (head,"FOVb",4))
+ parse_foveon();
+ else
+ for (i=0; i < sizeof table / sizeof *table; i++)
+ if (fsize == table[i].fsize) {
+ strcpy (make, table[i].make );
+ strcpy (model, table[i].model);
+ if (table[i].withjpeg)
+ parse_external_jpeg();
+ }
+ parse_mos(8);
+ parse_mos(3472);
+ if (make[0] == 0) parse_smal (0, fsize);
+ if (make[0] == 0) is_jpeg = parse_jpeg(0);
+ if (no_decode) return !timestamp;
+
+ for (i=0; i < sizeof corp / sizeof *corp; i++)
+ if (strstr (make, corp[i])) /* Simplify company names */
+ strcpy (make, corp[i]);
+ if (!strncmp (make,"KODAK",5))
+ make[16] = model[16] = 0;
+ cp = make + strlen(make); /* Remove trailing spaces */
+ while (*--cp == ' ') *cp = 0;
+ cp = model + strlen(model);
+ while (*--cp == ' ') *cp = 0;
+ i = strlen(make); /* Remove make from model */
+ if (!strncmp (model, make, i) && model[i++] == ' ')
+ memmove (model, model+i, 64-i);
+ make[63] = model[63] = model2[63] = 0;
+
+ if (make[0] == 0) {
+ fprintf (stderr, "%s: unsupported file format.\n", ifname);
+ return 1;
+ }
+ if ((raw_height | raw_width) < 0)
+ raw_height = raw_width = 0;
+ if (!height) height = raw_height;
+ if (!width) width = raw_width;
+ if (fuji_width) {
+ width = height + fuji_width;
+ height = width - 1;
+ xmag = ymag = 1;
+ }
+ if (dng_version) {
+ strcat (model," DNG");
+ if (filters == UINT_MAX) filters = 0;
+ if (!filters)
+ colors = tiff_samples;
+ if (tiff_data_compression == 1)
+ load_raw = adobe_dng_load_raw_nc;
+ if (tiff_data_compression == 7)
+ load_raw = adobe_dng_load_raw_lj;
+ FORC4 cam_mul[c] = pre_mul[c];
+ goto dng_skip;
+ }
+
+/* We'll try to decode anything from Canon or Nikon. */
+
+ if (filters == UINT_MAX) filters = 0x94949494;
+ if ((is_canon = !strcmp(make,"Canon"))) {
+ load_raw = memcmp (head+6,"HEAPCCDR",8) ?
+ lossless_jpeg_load_raw : canon_compressed_load_raw;
+ maximum = 0xfff;
+ }
+ if (!strcmp(make,"NIKON"))
+ load_raw = nikon_is_compressed() ?
+ nikon_compressed_load_raw : nikon_load_raw;
+ if (!strncmp (make,"OLYMPUS",7))
+ height += height & 1;
+
+/* Set parameters based on camera name (for non-DNG files). */
+
+ if (is_foveon) {
+ if (height*2 < width) ymag = 2;
+ if (height > width) xmag = 2;
+ filters = 0;
+ load_raw = foveon_load_raw;
+ simple_coeff(0);
+ } else if (!strcmp(model,"PowerShot 600")) {
+ height = 613;
+ width = 854;
+ colors = 4;
+ filters = 0xe1e4e1e4;
+ load_raw = canon_600_load_raw;
+ } else if (!strcmp(model,"PowerShot A5") ||
+ !strcmp(model,"PowerShot A5 Zoom")) {
+ height = 773;
+ width = 960;
+ raw_width = 992;
+ colors = 4;
+ filters = 0x1e4e1e4e;
+ load_raw = canon_a5_load_raw;
+ } else if (!strcmp(model,"PowerShot A50")) {
+ height = 968;
+ width = 1290;
+ raw_width = 1320;
+ colors = 4;
+ filters = 0x1b4e4b1e;
+ load_raw = canon_a5_load_raw;
+ } else if (!strcmp(model,"PowerShot Pro70")) {
+ height = 1024;
+ width = 1552;
+ colors = 4;
+ filters = 0x1e4b4e1b;
+ load_raw = canon_a5_load_raw;
+ black = 34;
+ } else if (!strcmp(model,"PowerShot Pro90 IS")) {
+ width = 1896;
+ colors = 4;
+ filters = 0xb4b4b4b4;
+ } else if (is_canon && raw_width == 2144) {
+ height = 1550;
+ width = 2088;
+ top_margin = 8;
+ left_margin = 4;
+ if (!strcmp(model,"PowerShot G1")) {
+ colors = 4;
+ filters = 0xb4b4b4b4;
+ }
+ } else if (is_canon && raw_width == 2224) {
+ height = 1448;
+ width = 2176;
+ top_margin = 6;
+ left_margin = 48;
+ } else if (is_canon && raw_width == 2376) {
+ height = 1720;
+ width = 2312;
+ top_margin = 6;
+ left_margin = 12;
+ } else if (is_canon && raw_width == 2672) {
+ height = 1960;
+ width = 2616;
+ top_margin = 6;
+ left_margin = 12;
+ } else if (is_canon && raw_width == 3152) {
+ height = 2056;
+ width = 3088;
+ top_margin = 12;
+ left_margin = 64;
+ maximum = 0xfa0;
+ } else if (is_canon && raw_width == 3160) {
+ height = 2328;
+ width = 3112;
+ top_margin = 12;
+ left_margin = 44;
+ } else if (is_canon && raw_width == 3344) {
+ height = 2472;
+ width = 3288;
+ top_margin = 6;
+ left_margin = 4;
+ } else if (!strcmp(model,"EOS D2000C")) {
+ filters = 0x61616161;
+ black = curve[200];
+ } else if (!strcmp(model,"EOS-1D")) {
+ raw_height = height = 1662;
+ raw_width = width = 2496;
+ data_offset = 288912;
+ filters = 0x61616161;
+ } else if (!strcmp(model,"EOS-1DS")) {
+ raw_height = height = 2718;
+ raw_width = width = 4082;
+ data_offset = 289168;
+ filters = 0x61616161;
+ } else if (is_canon && raw_width == 3516) {
+ top_margin = 14;
+ left_margin = 42;
+ goto canon_cr2;
+ } else if (is_canon && raw_width == 3596) {
+ top_margin = 12;
+ left_margin = 74;
+ goto canon_cr2;
+ } else if (is_canon && raw_width == 4476) {
+ top_margin = 34;
+ left_margin = 90;
+ goto canon_cr2;
+ } else if (is_canon && raw_width == 5108) {
+ top_margin = 13;
+ left_margin = 98;
+ maximum = 0xe80;
+canon_cr2:
+ height = raw_height - top_margin;
+ width = raw_width - left_margin;
+ } else if (!strcmp(model,"D1")) {
+ camera_red *= 256/527.0;
+ camera_blue *= 256/317.0;
+ } else if (!strcmp(model,"D1X")) {
+ width = 4024;
+ ymag = 2;
+ } else if (!strcmp(model,"D70")) {
+ maximum = 0xf53;
+ } else if (!strcmp(model,"D100")) {
+ if (tiff_data_compression == 34713 && load_raw == nikon_load_raw)
+ raw_width = (width += 3) + 3;
+ maximum = 0xf44;
+ } else if (!strcmp(model,"D2H")) {
+ width = 2482;
+ left_margin = 6;
+ } else if (!strcmp(model,"D2X")) {
+ width = 4312;
+ } else if (fsize == 1581060) {
+ height = 963;
+ width = 1287;
+ raw_width = 1632;
+ load_raw = nikon_e900_load_raw;
+ maximum = 0x3f4;
+ colors = 4;
+ filters = 0x1e1e1e1e;
+ simple_coeff(3);
+ pre_mul[0] = 1.2085;
+ pre_mul[1] = 1.0943;
+ pre_mul[3] = 1.1103;
+ } else if (fsize == 2465792) {
+ height = 1203;
+ width = 1616;
+ raw_width = 2048;
+ load_raw = nikon_e900_load_raw;
+ maximum = 0x3dd;
+ colors = 4;
+ filters = 0x4b4b4b4b;
+ simple_coeff(3);
+ pre_mul[0] = 1.18193;
+ pre_mul[2] = 1.16452;
+ pre_mul[3] = 1.17250;
+ } else if (!strcmp(model,"E880") ||
+ !strcmp(model,"E990")) {
+ if (!timestamp && !nikon_e990()) goto cp_e995;
+ height = 1540;
+ width = 2064;
+ colors = 4;
+ filters = 0xb4b4b4b4;
+ simple_coeff(3);
+ pre_mul[0] = 1.196;
+ pre_mul[1] = 1.246;
+ pre_mul[2] = 1.018;
+ } else if (!strcmp(model,"E995")) {
+cp_e995:
+ strcpy (model, "E995");
+ height = 1540;
+ width = 2064;
+ colors = 4;
+ filters = 0xe1e1e1e1;
+ } else if (!strcmp(model,"E2100")) {
+ if (!timestamp && !nikon_e2100()) goto cp_e2500;
+ height = 1206;
+ width = 1616;
+ load_raw = nikon_e2100_load_raw;
+ pre_mul[0] = 1.945;
+ pre_mul[2] = 1.040;
+ } else if (!strcmp(model,"E2500")) {
+cp_e2500:
+ strcpy (model, "E2500");
+ height = 1204;
+ width = 1616;
+ colors = 4;
+ filters = 0x4b4b4b4b;
+ } else if (fsize == 4775936) {
+ height = 1542;
+ width = 2064;
+ load_raw = nikon_e2100_load_raw;
+ pre_mul[0] = 1.818;
+ pre_mul[2] = 1.618;
+ if ((i = nikon_3700()) == 2) {
+ strcpy (make, "OLYMPUS");
+ strcpy (model, "C740UZ");
+ } else if (i == 0) {
+ strcpy (make, "PENTAX");
+ strcpy (model,"Optio 33WR");
+ flip = 1;
+ filters = 0x16161616;
+ pre_mul[0] = 1.331;
+ pre_mul[2] = 1.820;
+ }
+ } else if (!strcmp(model,"E4300")) {
+ if (!timestamp && minolta_z2()) goto dimage_z2;
+ height = 1710;
+ width = 2288;
+ filters = 0x16161616;
+ pre_mul[0] = 508;
+ pre_mul[1] = 256;
+ pre_mul[2] = 322;
+ } else if (!strcmp(model,"DiMAGE Z2")) {
+dimage_z2:
+ strcpy (make, "MINOLTA");
+ strcpy (model,"DiMAGE Z2");
+ height = 1710;
+ width = 2288;
+ filters = 0x16161616;
+ load_raw = nikon_e2100_load_raw;
+ black = 68;
+ } else if (!strcmp(model,"E4500")) {
+ height = 1708;
+ width = 2288;
+ colors = 4;
+ filters = 0xb4b4b4b4;
+ } else if (fsize == 7438336) {
+ height = 1924;
+ width = 2576;
+ colors = 4;
+ filters = 0xb4b4b4b4;
+ } else if (!strcmp(model,"R-D1")) {
+ tiff_data_compression = 34713;
+ load_raw = nikon_load_raw;
+ } else if (!strcmp(model,"FinePix S5100") ||
+ !strcmp(model,"FinePix S5500")) {
+ load_raw = unpacked_load_raw;
+ maximum = 0xffff;
+ } else if (!strncmp(model,"FinePix",7)) {
+ if (!strcmp(model+7,"S2Pro")) {
+ strcpy (model+7," S2Pro");
+ height = 2144;
+ width = 2880;
+ black = 128;
+ flip = 6;
+ } else
+ maximum = 0x3e00;
+ top_margin = (raw_height - height)/2;
+ left_margin = (raw_width - width )/2;
+ data_offset += (top_margin*raw_width + left_margin) * 2;
+ if (fuji_secondary)
+ data_offset += use_secondary * ( strcmp(model+7," S3Pro")
+ ? (raw_width *= 2) : raw_height*raw_width*2 );
+ fuji_width = width >> !fuji_layout;
+ width = (height >> fuji_layout) + fuji_width;
+ raw_height = height;
+ height = width - 1;
+ load_raw = fuji_load_raw;
+ if (!(fuji_width & 1)) filters = 0x49494949;
+ } else if (!strcmp(model,"RD175")) {
+ height = 986;
+ width = 1534;
+ data_offset = 513;
+ filters = 0x61616161;
+ load_raw = minolta_rd175_load_raw;
+ } else if (!strcmp(model,"Digital Camera KD-400Z")) {
+ height = 1712;
+ width = 2312;
+ raw_width = 2336;
+ data_offset = 4034;
+ fseek (ifp, 2032, SEEK_SET);
+ goto konica_400z;
+ } else if (!strcmp(model,"Digital Camera KD-510Z")) {
+ data_offset = 4032;
+ pre_mul[0] = 1.297;
+ pre_mul[2] = 1.438;
+ fseek (ifp, 2032, SEEK_SET);
+ goto konica_510z;
+ } else if (!strcasecmp(make,"MINOLTA")) {
+ load_raw = unpacked_load_raw;
+ maximum = 0xf7d;
+ if (!strncmp(model,"DiMAGE A",8)) {
+ if (!strcmp(model,"DiMAGE A200"))
+ filters = 0x49494949;
+ load_raw = packed_12_load_raw;
+ maximum = model[8] == '1' ? 0xf8b : 0xfff;
+ } else if (!strncmp(model,"ALPHA",5) ||
+ !strncmp(model,"DYNAX",5) ||
+ !strncmp(model,"MAXXUM",6)) {
+ sprintf (model, "DYNAX %s", model+6 + (model[0]=='M'));
+ load_raw = packed_12_load_raw;
+ maximum = 0xffb;
+ } else if (!strncmp(model,"DiMAGE G",8)) {
+ if (model[8] == '4') {
+ data_offset = 5056;
+ pre_mul[0] = 1.602;
+ pre_mul[2] = 1.441;
+ fseek (ifp, 2078, SEEK_SET);
+ height = 1716;
+ width = 2304;
+ } else if (model[8] == '5') {
+ data_offset = 4016;
+ fseek (ifp, 1936, SEEK_SET);
+konica_510z:
+ height = 1956;
+ width = 2607;
+ raw_width = 2624;
+ } else if (model[8] == '6') {
+ data_offset = 4032;
+ fseek (ifp, 2030, SEEK_SET);
+ height = 2136;
+ width = 2848;
+ }
+ filters = 0x61616161;
+konica_400z:
+ load_raw = unpacked_load_raw;
+ maximum = 0x3df;
+ order = 0x4d4d;
+ FORC4 cam_mul[(c >> 1) | ((c & 1) << 1)] = get2();
+ }
+ if (pre_mul[0] == 1 && pre_mul[2] == 1) {
+ pre_mul[0] = 1.42;
+ pre_mul[2] = 1.25;
+ }
+ } else if (!strncmp(model,"*ist D",6)) {
+ load_raw = model[6] ? packed_12_load_raw : unpacked_load_raw;
+ if (model[6] == 'S') height -= 2;
+ } else if (!strcmp(model,"Optio S")) {
+ if (fsize == 3178560) {
+ height = 1540;
+ width = 2064;
+ load_raw = eight_bit_load_raw;
+ camera_red *= 4;
+ camera_blue *= 4;
+ pre_mul[0] = 1.391;
+ pre_mul[2] = 1.188;
+ } else {
+ height = 1544;
+ width = 2068;
+ raw_width = 3136;
+ load_raw = packed_12_load_raw;
+ maximum = 0xf7c;
+ pre_mul[0] = 1.137;
+ pre_mul[2] = 1.453;
+ }
+ } else if (!strncmp(model,"Optio S4",8)) {
+ height = 1737;
+ width = 2324;
+ raw_width = 3520;
+ load_raw = packed_12_load_raw;
+ maximum = 0xf7a;
+ pre_mul[0] = 1.980;
+ pre_mul[2] = 1.570;
+ } else if (!strcmp(model,"STV680 VGA")) {
+ height = 484;
+ width = 644;
+ load_raw = eight_bit_load_raw;
+ flip = 2;
+ filters = 0x16161616;
+ black = 16;
+ pre_mul[0] = 1.097;
+ pre_mul[2] = 1.128;
+ } else if (!strcmp(model,"531C")) {
+ height = 1200;
+ width = 1600;
+ load_raw = unpacked_load_raw;
+ filters = 0x49494949;
+ pre_mul[1] = 1.218;
+ } else if (!strcmp(model,"F-201C")) {
+ height = 1200;
+ width = 1600;
+ load_raw = eight_bit_load_raw;
+ } else if (!strcmp(model,"F-510C")) {
+ height = 1958;
+ width = 2588;
+ load_raw = (fsize < 7500000) ? eight_bit_load_raw : unpacked_load_raw;
+ maximum = 0xfff0;
+ } else if (!strcmp(model,"F-810C")) {
+ height = 2469;
+ width = 3272;
+ load_raw = unpacked_load_raw;
+ maximum = 0xfff0;
+ } else if (!strcmp(model,"A782")) {
+ height = 3000;
+ width = 2208;
+ filters = 0x61616161;
+ load_raw = (fsize < 10000000) ? eight_bit_load_raw : unpacked_load_raw;
+ maximum = 0xffc0;
+ } else if (!strcmp(model,"3320AF")) {
+ height = 1536;
+ raw_width = width = 2048;
+ filters = 0x61616161;
+ load_raw = unpacked_load_raw;
+ maximum = 0x3ff;
+ pre_mul[0] = 1.717;
+ pre_mul[2] = 1.138;
+ fseek (ifp, 0x300000, SEEK_SET);
+ if ((order = guess_byte_order(0x10000)) == 0x4d4d) {
+ data_offset = (2048 * 16 + 28) * 2;
+ height -= 16;
+ width -= 28;
+ maximum = 0xf5c0;
+ strcpy (make, "ISG");
+ sprintf (model, "%dx%d", width, height);
+ }
+ } else if (!strcmp(make,"Imacon")) {
+ height = raw_height - 6;
+ width = raw_width - 10;
+ data_offset += 6 + raw_width*12;
+ flip = height > width+10 ? 5:3;
+ sprintf (model, "Ixpress %d-Mp", height*width/1000000);
+ filters = 0x61616161;
+ load_raw = unpacked_load_raw;
+ maximum = 0xffff;
+ pre_mul[0] = 1.963;
+ pre_mul[2] = 1.430;
+ } else if (!strcmp(make,"Sinar")) {
+ if (!memcmp(head,"8BPS",4)) {
+ fseek (ifp, 14, SEEK_SET);
+ height = get4();
+ width = get4();
+ filters = 0x61616161;
+ data_offset = 68;
+ }
+ load_raw = unpacked_load_raw;
+ maximum = 0x3fff;
+ } else if (!strcmp(make,"Leaf")) {
+ load_raw = unpacked_load_raw;
+ if (tiff_data_compression == 99)
+ load_raw = lossless_jpeg_load_raw;
+ maximum = 0x3fff;
+ strcpy (model, "Valeo");
+ if (filters == 0) {
+ load_raw = leaf_load_raw;
+ maximum = 0xffff;
+ strcpy (model, "Volare");
+ }
+ } else if (!strcmp(make,"LEICA") || !strcmp(make,"Panasonic")) {
+ if (width == 3880) {
+ data_offset += 12;
+ maximum = 0xf7f0;
+ width -= 22;
+ } else if (width == 3304) {
+ maximum = 0xf94c;
+ width -= 16;
+ } else maximum = 0xfff0;
+ load_raw = unpacked_load_raw;
+ } else if (!strcmp(model,"E-1")) {
+ filters = 0x61616161;
+ load_raw = unpacked_load_raw;
+ maximum = 0xfff0;
+ black = 1024;
+ } else if (!strcmp(model,"E-10")) {
+ load_raw = unpacked_load_raw;
+ maximum = 0xfff0;
+ black = 2048;
+ } else if (!strncmp(model,"E-20",4)) {
+ load_raw = unpacked_load_raw;
+ maximum = 0xffc0;
+ black = 2560;
+ } else if (!strcmp(model,"E-300") ||
+ !strcmp(model,"E-500")) {
+ width -= 20;
+ load_raw = olympus_e300_load_raw;
+ maximum = 0xfff;
+ if (fsize > 15728640) {
+ load_raw = unpacked_load_raw;
+ maximum = 0xfc30;
+ }
+ } else if (!strcmp(model,"C770UZ")) {
+ height = 1718;
+ width = 2304;
+ filters = 0x16161616;
+ load_raw = nikon_e2100_load_raw;
+ } else if (!strcmp(make,"OLYMPUS")) {
+ load_raw = olympus_cseries_load_raw;
+ if (!strcmp(model,"C5050Z") ||
+ !strcmp(model,"C8080WZ"))
+ filters = 0x16161616;
+ } else if (!strcmp(model,"N Digital")) {
+ height = 2047;
+ width = 3072;
+ filters = 0x61616161;
+ data_offset = 0x1a00;
+ load_raw = packed_12_load_raw;
+ maximum = 0xf1e;
+ } else if (!strcmp(model,"DSC-F828")) {
+ width = 3288;
+ left_margin = 5;
+ data_offset = 862144;
+ load_raw = sony_load_raw;
+ filters = 0x9c9c9c9c;
+ colors = 4;
+ black = 491;
+ } else if (!strcmp(model,"DSC-V3")) {
+ width = 3109;
+ left_margin = 59;
+ data_offset = 787392;
+ load_raw = sony_load_raw;
+ } else if (!strcmp(model,"DSC-R1")) {
+ width = 3925;
+ order = 0x4d4d;
+ load_raw = unpacked_load_raw;
+ black = 512;
+ } else if (!strncmp(model,"P850",4)) {
+ height = 1950;
+ width = 2608;
+ data_offset = 76456;
+ filters = 0x16161616;
+ load_raw = packed_12_load_raw;
+ } else if (!strcasecmp(make,"KODAK")) {
+ filters = 0x61616161;
+ if (!strcmp(model,"NC2000F")) {
+ width -= 4;
+ left_margin = 2;
+ } else if (!strcmp(model,"EOSDCS3B")) {
+ width -= 4;
+ left_margin = 2;
+ } else if (!strcmp(model,"EOSDCS1")) {
+ width -= 4;
+ left_margin = 2;
+ } else if (!strcmp(model,"DCS315C")) {
+ black = 8;
+ } else if (!strcmp(model,"DCS330C")) {
+ black = 8;
+ } else if (!strcmp(model,"DCS420")) {
+ width -= 4;
+ left_margin = 2;
+ } else if (!strcmp(model,"DCS460")) {
+ width -= 4;
+ left_margin = 2;
+ } else if (!strcmp(model,"DCS460A")) {
+ width -= 4;
+ left_margin = 2;
+ colors = 1;
+ filters = 0;
+ } else if (!strcmp(model,"DCS520C")) {
+ black = 180;
+ } else if (!strcmp(model,"DCS560C")) {
+ black = 188;
+ } else if (!strcmp(model,"DCS620C")) {
+ black = 180;
+ } else if (!strcmp(model,"DCS620X")) {
+ black = 185;
+ } else if (!strcmp(model,"DCS660C")) {
+ black = 214;
+ } else if (!strcmp(model,"DCS660M")) {
+ black = 214;
+ colors = 1;
+ filters = 0;
+ } else if (!strcmp(model,"DCS760M")) {
+ colors = 1;
+ filters = 0;
+ }
+ switch (tiff_data_compression) {
+ case 0: /* No compression */
+ case 1:
+ load_raw = kodak_easy_load_raw;
+ break;
+ case 7: /* Lossless JPEG */
+ load_raw = lossless_jpeg_load_raw;
+ case 32867:
+ break;
+ case 65000: /* Kodak DCR compression */
+ if (kodak_data_compression == 32803)
+ load_raw = kodak_compressed_load_raw;
+ else {
+ load_raw = kodak_yuv_load_raw;
+ height = (height+1) & -2;
+ width = (width +1) & -2;
+ filters = 0;
+ }
+ break;
+ default:
+ fprintf (stderr, "%s: %s %s uses unsupported compression method %d.\n",
+ ifname, make, model, tiff_data_compression);
+ return 1;
+ }
+ if (strstr(model,"DC25")) {
+ strcpy (model, "DC25");
+ data_offset = 15424;
+ }
+ if (!strncmp(model,"DC2",3)) {
+ height = 242;
+ if (fsize < 100000) {
+ raw_width = 256; width = 249;
+ } else {
+ raw_width = 512; width = 501;
+ }
+ data_offset += raw_width + 1;
+ colors = 4;
+ filters = 0x8d8d8d8d;
+ simple_coeff(1);
+ pre_mul[1] = 1.179;
+ pre_mul[2] = 1.209;
+ pre_mul[3] = 1.036;
+ load_raw = kodak_easy_load_raw;
+ } else if (!strcmp(model,"Digital Camera 40")) {
+ strcpy (model, "DC40");
+ height = 512;
+ width = 768;
+ data_offset = 1152;
+ load_raw = kodak_radc_load_raw;
+ } else if (strstr(model,"DC50")) {
+ strcpy (model, "DC50");
+ height = 512;
+ width = 768;
+ data_offset = 19712;
+ load_raw = kodak_radc_load_raw;
+ } else if (strstr(model,"DC120")) {
+ strcpy (model, "DC120");
+ height = 976;
+ width = 848;
+ if (tiff_data_compression == 7)
+ load_raw = kodak_jpeg_load_raw;
+ else
+ load_raw = kodak_dc120_load_raw;
+ }
+ } else if (!strcmp(model,"Fotoman Pixtura")) {
+ height = 512;
+ width = 768;
+ data_offset = 3632;
+ load_raw = kodak_radc_load_raw;
+ filters = 0x61616161;
+ simple_coeff(2);
+ } else if (!strcmp(make,"Rollei")) {
+ switch (raw_width) {
+ case 1316:
+ height = 1030;
+ width = 1300;
+ top_margin = 1;
+ left_margin = 6;
+ break;
+ case 2568:
+ height = 1960;
+ width = 2560;
+ top_margin = 2;
+ left_margin = 8;
+ }
+ filters = 0x16161616;
+ load_raw = rollei_load_raw;
+ pre_mul[0] = 1.8;
+ pre_mul[2] = 1.3;
+ } else if (!strcmp(model,"PC-CAM 600")) {
+ height = 768;
+ data_offset = width = 1024;
+ filters = 0x49494949;
+ load_raw = eight_bit_load_raw;
+ pre_mul[0] = 1.14;
+ pre_mul[2] = 2.73;
+ } else if (!strcmp(model,"QV-2000UX")) {
+ height = 1208;
+ width = 1632;
+ data_offset = width * 2;
+ load_raw = eight_bit_load_raw;
+ } else if (fsize == 3217760) {
+ height = 1546;
+ width = 2070;
+ raw_width = 2080;
+ load_raw = eight_bit_load_raw;
+ } else if (!strcmp(model,"QV-4000")) {
+ height = 1700;
+ width = 2260;
+ load_raw = unpacked_load_raw;
+ maximum = 0xffff;
+ } else if (!strcmp(model,"QV-5700")) {
+ height = 1924;
+ width = 2576;
+ load_raw = casio_qv5700_load_raw;
+ } else if (!strcmp(model,"QV-R51")) {
+ height = 1926;
+ width = 2576;
+ raw_width = 3904;
+ load_raw = packed_12_load_raw;
+ pre_mul[0] = 1.340;
+ pre_mul[2] = 1.672;
+ } else if (!strcmp(model,"EX-S100")) {
+ height = 1544;
+ width = 2058;
+ raw_width = 3136;
+ load_raw = packed_12_load_raw;
+ pre_mul[0] = 1.631;
+ pre_mul[2] = 1.106;
+ } else if (!strcmp(model,"EX-Z50")) {
+ height = 1931;
+ width = 2570;
+ raw_width = 3904;
+ load_raw = packed_12_load_raw;
+ pre_mul[0] = 2.529;
+ pre_mul[2] = 1.185;
+ } else if (!strcmp(model,"EX-Z55")) {
+ height = 1960;
+ width = 2570;
+ raw_width = 3904;
+ load_raw = packed_12_load_raw;
+ pre_mul[0] = 1.520;
+ pre_mul[2] = 1.316;
+ } else if (!strcmp(model,"EX-P505")) {
+ height = 1928;
+ width = 2568;
+ raw_width = 3852;
+ load_raw = packed_12_load_raw;
+ pre_mul[0] = 2.07;
+ pre_mul[2] = 1.88;
+ } else if (!strcmp(model,"EX-P600")) {
+ height = 2142;
+ width = 2844;
+ raw_width = 4288;
+ load_raw = packed_12_load_raw;
+ pre_mul[0] = 1.797;
+ pre_mul[2] = 1.219;
+ } else if (!strcmp(model,"EX-P700")) {
+ height = 2318;
+ width = 3082;
+ raw_width = 4672;
+ load_raw = packed_12_load_raw;
+ pre_mul[0] = 1.758;
+ pre_mul[2] = 1.504;
+ } else if (!strcmp(make,"Nucore")) {
+ filters = 0x61616161;
+ load_raw = unpacked_load_raw;
+ if (width == 2598) {
+ filters = 0x16161616;
+ load_raw = nucore_load_raw;
+ flip = 2;
+ }
+ }
+ if (raw_color) adobe_coeff();
+dng_skip:
+ if (!load_raw || !height || is_jpeg) {
+ fprintf (stderr, "%s: Cannot decode %s %s%s images.\n",
+ ifname, make, model, is_jpeg ? " JPEG":"");
+ return 1;
+ }
+#ifdef NO_JPEG
+ if (load_raw == kodak_jpeg_load_raw) {
+ fprintf (stderr, "%s: decoder was not linked with libjpeg.\n", ifname);
+ return 1;
+ }
+#endif
+ if (!raw_height) raw_height = height;
+ if (!raw_width ) raw_width = width;
+ raw_color |= use_camera_rgb && colors == 3;
+ FORCC { /* Apply user-selected color balance */
+ rgb_cam[0][c] *= red_scale;
+ rgb_cam[2][c] *= blue_scale;
+ }
+ if (filters && colors == 3)
+ for (i=0; i < 32; i+=4) {
+ if ((filters >> i & 15) == 9)
+ filters |= 2 << i;
+ if ((filters >> i & 15) == 6)
+ filters |= 8 << i;
+ }
+ fseek (ifp, data_offset, SEEK_SET);
+ return 0;
+}
+
+#ifdef USE_LCMS
+void CLASS apply_profile (char *pfname)
+{
+ char *prof;
+ cmsHPROFILE hInProfile=NULL, hOutProfile;
+ cmsHTRANSFORM hTransform;
+
+ if (pfname)
+ hInProfile = cmsOpenProfileFromFile (pfname, "r");
+ else if (profile_length) {
+ prof = malloc (profile_length);
+ merror (prof, "apply_profile()");
+ fseek (ifp, profile_offset, SEEK_SET);
+ fread (prof, 1, profile_length, ifp);
+ hInProfile = cmsOpenProfileFromMem (prof, profile_length);
+ free (prof);
+ }
+ if (!hInProfile) return;
+ if (verbose)
+ fprintf (stderr, "Applying color profile...\n");
+ maximum = 0xffff;
+ use_gamma = 0;
+ raw_color = 1; /* Don't use rgb_cam with a profile */
+
+ hOutProfile = cmsCreate_sRGBProfile();
+ hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16,
+ hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0);
+ cmsDoTransform (hTransform, image, image, width*height);
+
+ cmsDeleteTransform (hTransform);
+ cmsCloseProfile (hInProfile);
+ cmsCloseProfile (hOutProfile);
+}
+#endif
+
+/*
+ Convert the entire image to RGB colorspace and build a histogram.
+ */
+void CLASS convert_to_rgb()
+{
+ int row, col, c, i, fc=0;
+ ushort *img;
+ float rgb[3];
+
+ if (verbose)
+ fprintf (stderr, raw_color ?
+ "Building histograms...\n" : "Converting to sRGB colorspace...\n");
+
+ if (document_mode)
+ colors = 1;
+ memset (histogram, 0, sizeof histogram);
+ for (row = 0; row < height; row++)
+ for (col = 0; col < width; col++) {
+ img = image[row*width+col];
+ if (document_mode)
+ fc = FC(row,col);
+ if (colors == 4 && raw_color) /* Recombine the greens */
+ img[1] = (img[1] + img[3]) >> 1;
+ if (colors == 1) /* RGB from grayscale */
+ FORC3 rgb[c] = img[fc];
+ else if (raw_color) /* RGB from RGB (easy) */
+ goto norgb;
+ else FORC3 /* RGB via rgb_cam */
+ for (rgb[c]=i=0; i < colors; i++)
+ rgb[c] += img[i] * rgb_cam[c][i];
+ FORC3 img[c] = CLIP((int) rgb[c]);
+norgb:
+ FORC3 histogram[c][img[c] >> 3]++;
+ }
+}
+
+void CLASS fuji_rotate()
+{
+ int i, wide, high, row, col;
+ double step;
+ float r, c, fr, fc;
+ unsigned ur, uc;
+ ushort (*img)[4], (*pix)[4];
+
+ if (!fuji_width) return;
+ if (verbose)
+ fprintf (stderr, "Rotating image 45 degrees...\n");
+ fuji_width = (fuji_width - 1 + shrink) >> shrink;
+ step = sqrt(0.5);
+ wide = fuji_width / step;
+ high = (height - fuji_width) / step;
+ img = calloc (wide*high, sizeof *img);
+ merror (img, "fuji_rotate()");
+
+ for (row=0; row < high; row++)
+ for (col=0; col < wide; col++) {
+ ur = r = fuji_width + (row-col)*step;
+ uc = c = (row+col)*step;
+ if (ur > height-2 || uc > width-2) continue;
+ fr = r - ur;
+ fc = c - uc;
+ pix = image + ur*width + uc;
+ for (i=0; i < colors; i++)
+ img[row*wide+col][i] =
+ (pix[ 0][i]*(1-fc) + pix[ 1][i]*fc) * (1-fr) +
+ (pix[width][i]*(1-fc) + pix[width+1][i]*fc) * fr;
+ }
+ free (image);
+ width = wide;
+ height = high;
+ image = img;
+ fuji_width = 0;
+}
+
+void CLASS flip_image()
+{
+ unsigned *flag;
+ int size, base, dest, next, row, col, temp;
+ INT64 *img, hold;
+
+ if (verbose)
+ fprintf (stderr, "Flipping image %c:%c:%c...\n",
+ flip & 1 ? 'H':'0', flip & 2 ? 'V':'0', flip & 4 ? 'T':'0');
+
+ img = (INT64 *) image;
+ size = height * width;
+ flag = calloc ((size+31) >> 5, sizeof *flag);
+ merror (flag, "flip_image()");
+ for (base = 0; base < size; base++) {
+ if (flag[base >> 5] & (1 << (base & 31)))
+ continue;
+ dest = base;
+ hold = img[base];
+ while (1) {
+ if (flip & 4) {
+ row = dest % height;
+ col = dest / height;
+ } else {
+ row = dest / width;
+ col = dest % width;
+ }
+ if (flip & 2)
+ row = height - 1 - row;
+ if (flip & 1)
+ col = width - 1 - col;
+ next = row * width + col;
+ if (next == base) break;
+ flag[next >> 5] |= 1 << (next & 31);
+ img[dest] = img[next];
+ dest = next;
+ }
+ img[dest] = hold;
+ }
+ free (flag);
+ if (flip & 4) {
+ temp = height;
+ height = width;
+ width = temp;
+ temp = ymag;
+ ymag = xmag;
+ xmag = temp;
+ }
+}
+
+/*
+ Write the image to an 8-bit PPM file.
+ */
+void CLASS write_ppm (FILE *ofp)
+{
+ uchar (*ppm)[3], lut[0x10000];
+ int perc, c, val, total, i, row, col;
+ float white=0, r;
+
+ fprintf (ofp, "P6\n%d %d\n255\n", xmag*width, ymag*height);
+ ppm = calloc (width, 3*xmag);
+ merror (ppm, "write_ppm()");
+
+ perc = width * height * 0.01; /* 99th percentile white point */
+ if (fuji_width) perc /= 2;
+ FORC3 {
+ for (val=0x2000, total=0; --val > 32; )
+ if ((total += histogram[c][val]) > perc) break;
+ if (white < val) white = val;
+ }
+ white *= 8 / bright;
+ for (i=0; i < 0x10000; i++) {
+ r = i / white;
+ val = 256 * ( !use_gamma ? r :
+#ifdef SRGB_GAMMA
+ r <= 0.00304 ? r*12.92 : pow(r,2.5/6)*1.055-0.055 );
+#else
+ r <= 0.018 ? r*4.5 : pow(r,0.45)*1.099-0.099 );
+#endif
+ if (val > 255) val = 255;
+ lut[i] = val;
+ }
+ for (row=0; row < height; row++) {
+ for (col=0; col < width; col++)
+ FORC3 for (i=0; i < xmag; i++)
+ ppm[xmag*col+i][c] = lut[image[row*width+col][c]];
+ for (i=0; i < ymag; i++)
+ fwrite (ppm, width, 3*xmag, ofp);
+ }
+ free (ppm);
+}
+
+/*
+ Write the image to a 16-bit Photoshop file.
+ */
+void CLASS write_psd (FILE *ofp)
+{
+ char head[] = {
+ '8','B','P','S', /* signature */
+ 0,1,0,0,0,0,0,0, /* version and reserved */
+ 0,3, /* number of channels */
+ 0,0,0,0, /* height, big-endian */
+ 0,0,0,0, /* width, big-endian */
+ 0,16, /* 16-bit color */
+ 0,3, /* mode (1=grey, 3=rgb) */
+ 0,0,0,0, /* color mode data */
+ 0,0,0,0, /* image resources */
+ 0,0,0,0, /* layer/tqmask info */
+ 0,0 /* no compression */
+ };
+ int hw[2], psize, row, col, c;
+ ushort *buffer, *pred;
+
+ hw[0] = htonl(height); /* write the header */
+ hw[1] = htonl(width);
+ memcpy (head+14, hw, sizeof hw);
+ fwrite (head, 40, 1, ofp);
+
+ psize = height*width;
+ buffer = calloc (6, psize);
+ merror (buffer, "write_psd()");
+ pred = buffer;
+
+ for (row = 0; row < height; row++)
+ for (col = 0; col < width; col++) {
+ FORC3 pred[c*psize] = htons(image[row*width+col][c]);
+ pred++;
+ }
+ fwrite(buffer, psize, 6, ofp);
+ free (buffer);
+}
+
+/*
+ Write the image to a 16-bit PPM file.
+ */
+void CLASS write_ppm16 (FILE *ofp)
+{
+ int row, col, c;
+ ushort (*ppm)[3];
+
+ if (maximum < 256) maximum = 256;
+ fprintf (ofp, "P6\n%d %d\n%d\n", width, height, maximum);
+
+ ppm = calloc (width, 6);
+ merror (ppm, "write_ppm16()");
+
+ for (row = 0; row < height; row++) {
+ for (col = 0; col < width; col++)
+ FORC3 ppm[col][c] = htons(image[row*width+col][c]);
+ fwrite (ppm, width, 6, ofp);
+ }
+ free (ppm);
+}
+
+int CLASS main (int argc, char **argv)
+{
+ int arg, status=0, user_flip=-1, user_black=-1, user_qual=-1;
+ int timestamp_only=0, identify_only=0, write_to_stdout=0;
+ int half_size=0, use_fuji_rotate=1, quality;
+ char opt, *ofname, *cp;
+ struct utimbuf ut;
+ const char *write_ext = ".ppm";
+ FILE *ofp = stdout;
+#ifdef USE_LCMS
+ char *profile = NULL;
+#endif
+
+#ifndef LOCALTIME
+ putenv ("TZ=UTC");
+#endif
+ if (argc == 1)
+ {
+ fprintf (stderr,
+ "\nRaw Photo Decoder \"dcraw\" v7.82"
+ "\nby Dave Coffin, dcoffin a cybercom o net"
+ "\n\nUsage: %s [options] file1 file2 ...\n"
+ "\nValid options:"
+ "\n-v Print verbose messages"
+ "\n-z Change file dates to camera timestamp"
+ "\n-i Identify files without decoding them"
+ "\n-c Write to standard output"
+ "\n-a Use automatic white balance"
+ "\n-w Use camera white balance, if possible"
+ "\n-r <num> Set red multiplier (default = 1.0)"
+ "\n-l <num> Set blue multiplier (default = 1.0)"
+ "\n-b <num> Set brightness (default = 1.0)"
+ "\n-k <num> Set black point"
+ "\n-n Don't clip colors"
+ "\n-m Don't convert camera RGB to sRGB"
+#ifdef USE_LCMS
+ "\n-p <file> Apply color profile from file"
+#endif
+ "\n-d Document Mode (no color, no interpolation)"
+ "\n-q [0-3] Set the interpolation quality"
+ "\n-h Half-size color image (twice as fast as \"-q 0\")"
+ "\n-f Interpolate RGGB as four colors"
+ "\n-B <domain> <range> Apply bilateral filter to reduce noise"
+ "\n-j Show Fuji Super CCD images tilted 45 degrees"
+ "\n-s Use secondary pixels (Fuji Super CCD SR only)"
+ "\n-t [0-7] Flip image (0 = none, 3 = 180, 5 = 90CCW, 6 = 90CW)"
+ "\n-2 Write 8-bit PPM with 0.45 gamma (default)"
+ "\n-3 Write 16-bit linear PSD (Adobe Photoshop)"
+ "\n-4 Write 16-bit linear PPM"
+ "\n\n", argv[0]);
+ return 1;
+ }
+
+ argv[argc] = "";
+ for (arg=1; argv[arg][0] == '-'; ) {
+ opt = argv[arg++][1];
+ if ((strchr("Bbrlktq", opt) && !isdigit(argv[arg][0])) ||
+ (opt == 'B' && !isdigit(argv[arg+1][0]))) {
+ fprintf (stderr, "Non-numeric argument to \"-%c\"\n", opt);
+ return 1;
+ }
+ switch (opt)
+ {
+ case 'B': sigma_d = atof(argv[arg++]);
+ sigma_r = atof(argv[arg++]); break;
+ case 'b': bright = atof(argv[arg++]); break;
+ case 'r': red_scale = atof(argv[arg++]); break;
+ case 'l': blue_scale = atof(argv[arg++]); break;
+ case 'k': user_black = atoi(argv[arg++]); break;
+ case 't': user_flip = atoi(argv[arg++]); break;
+ case 'q': user_qual = atoi(argv[arg++]); break;
+#ifdef USE_LCMS
+ case 'p': profile = argv[arg++] ; break;
+#endif
+ case 'z': timestamp_only = 1; break;
+ case 'i': identify_only = 1; break;
+ case 'c': write_to_stdout = 1; break;
+ case 'v': verbose = 1; break;
+ case 'h': half_size = 1; /* "-h" implies "-f" */
+ case 'f': four_color_rgb = 1; break;
+ case 'd': document_mode = 1; break;
+ case 'a': use_auto_wb = 1; break;
+ case 'w': use_camera_wb = 1; break;
+ case 'j': use_fuji_rotate = 0; break;
+ case 's': use_secondary = 1; break;
+ case 'n': clip_color = 0; break;
+ case 'm': use_camera_rgb = 1; break;
+
+ case '2': write_fun = write_ppm; write_ext = ".ppm"; break;
+ case '3': write_fun = write_psd; write_ext = ".psd"; break;
+ case '4': write_fun = write_ppm16; write_ext = ".ppm"; break;
+
+ default:
+ fprintf (stderr, "Unknown option \"-%c\".\n", opt);
+ return 1;
+ }
+ }
+ if (arg == argc) {
+ fprintf (stderr, "No files to process.\n");
+ return 1;
+ }
+ if (write_to_stdout) {
+ if (isatty(1)) {
+ fprintf (stderr, "Will not write an image to the terminal!\n");
+ return 1;
+ }
+#if defined(WIN32) || defined(DJGPP) || defined(__CYGWIN__)
+ if (setmode(1,O_BINARY) < 0) {
+ perror("setmode()");
+ return 1;
+ }
+#endif
+ }
+ for ( ; arg < argc; arg++) {
+ status = 1;
+ image = NULL;
+ if (setjmp (failure)) {
+ if (fileno(ifp) > 2) fclose(ifp);
+ if (fileno(ofp) > 2) fclose(ofp);
+ if (image) free (image);
+ status = 1;
+ continue;
+ }
+ ifname = argv[arg];
+ if (!(ifp = fopen (ifname, "rb"))) {
+ perror (ifname);
+ continue;
+ }
+ if (timestamp_only) {
+ if ((status = identify(1)))
+ fprintf (stderr, "%s has no timestamp.\n", ifname);
+ else if (identify_only)
+ printf ("%10ld%10d %s\n", timestamp, shot_order, ifname);
+ else {
+ if (verbose)
+ fprintf (stderr, "%s time set to %d.\n", ifname, (int) timestamp);
+ ut.actime = ut.modtime = timestamp;
+ utime (ifname, &ut);
+ }
+ goto next;
+ }
+ if ((status = identify(0))) goto next;
+ if (user_flip >= 0)
+ flip = user_flip;
+ switch ((flip+3600) % 360) {
+ case 270: flip = 5; break;
+ case 180: flip = 3; break;
+ case 90: flip = 6;
+ }
+ if (identify_only) {
+ fprintf (stderr, "%s is a %s %s image.\n", ifname, make, model);
+next:
+ fclose(ifp);
+ continue;
+ }
+ shrink = half_size && filters;
+ iheight = (height + shrink) >> shrink;
+ iwidth = (width + shrink) >> shrink;
+ image = calloc (iheight*iwidth*sizeof *image + meta_length, 1);
+ merror (image, "main()");
+ meta_data = (char *) (image + iheight*iwidth);
+ if (verbose)
+ fprintf (stderr,
+ "Loading %s %s image from %s...\n", make, model, ifname);
+ (*load_raw)();
+ bad_pixels();
+ height = iheight;
+ width = iwidth;
+#ifdef COLORCHECK
+ colorcheck();
+#endif
+ quality = 2 + !fuji_width;
+ if (user_qual >= 0) quality = user_qual;
+ if (user_black >= 0) black = user_black;
+ if (is_foveon) foveon_interpolate();
+ else scale_colors();
+ if (shrink) filters = 0;
+ cam_to_cielab (NULL,NULL);
+ if (filters && !document_mode) {
+ if (quality == 0)
+ lin_interpolate();
+ else if (quality < 3 || colors > 3)
+ vng_interpolate();
+ else ahd_interpolate();
+ }
+ if (sigma_d > 0 && sigma_r > 0) bilateral_filter();
+ if (use_fuji_rotate) fuji_rotate();
+#ifdef USE_LCMS
+ apply_profile (profile);
+#endif
+ convert_to_rgb();
+ if (flip) flip_image();
+ fclose(ifp);
+ ofname = malloc (strlen(ifname) + 16);
+ merror (ofname, "main()");
+ if (write_to_stdout)
+ strcpy (ofname, "standard output");
+ else {
+ strcpy (ofname, ifname);
+ if ((cp = strrchr (ofname, '.'))) *cp = 0;
+ strcat (ofname, write_ext);
+ ofp = fopen (ofname, "wb");
+ if (!ofp) {
+ status = 1;
+ perror(ofname);
+ goto cleanup;
+ }
+ }
+ if (verbose)
+ fprintf (stderr, "Writing data to %s...\n", ofname);
+ (*write_fun)(ofp);
+ if (ofp != stdout)
+ fclose(ofp);
+cleanup:
+ free (ofname);
+ free (image);
+ }
+ return status;
+}
diff --git a/filters/chalk/raw/kis_raw_import.cpp b/filters/chalk/raw/kis_raw_import.cpp
new file mode 100644
index 00000000..adfd14f6
--- /dev/null
+++ b/filters/chalk/raw/kis_raw_import.cpp
@@ -0,0 +1,630 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include "config.h"
+
+#ifdef HAVE_SYS_TYPES_H
+ #include <sys/types.h>
+#endif
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include <tqstring.h>
+#include <tqfile.h>
+#include <tqimage.h>
+#include <tqradiobutton.h>
+#include <tqgroupbox.h>
+#include <tqbuttongroup.h>
+#include <tqpushbutton.h>
+#include <tqlabel.h>
+#include <tqcheckbox.h>
+#include <tqapplication.h>
+#include <tqcursor.h>
+#include <tqeventloop.h>
+#include <tqprogressdialog.h>
+#include <tqtimer.h>
+
+#include <kglobal.h>
+#include <kconfig.h>
+#include <knuminput.h>
+#include <kgenericfactory.h>
+#include <kdialogbase.h>
+#include <kdialog.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kprocess.h>
+
+#include <KoDocument.h>
+#include <KoFilterChain.h>
+
+#include "imageviewer.h"
+#include "kis_config.h"
+#include "kis_cmb_idlist.h"
+#include "kis_types.h"
+#include "kis_raw_import.h"
+#include "kis_doc.h"
+#include "kis_image.h"
+#include "kis_meta_registry.h"
+#include "kis_layer.h"
+#include "kis_annotation.h"
+#include "kis_profile.h"
+#include "kis_colorspace_factory_registry.h"
+#include "kis_iterators_pixel.h"
+#include "kis_abstract_colorspace.h"
+#include "kis_paint_device.h"
+#include "kis_paint_layer.h"
+#include "wdgrawimport.h"
+
+typedef KGenericFactory<KisRawImport, KoFilter> KisRawImportFactory;
+K_EXPORT_COMPONENT_FACTORY(libchalk_raw_import, KisRawImportFactory("kofficefilters"))
+
+KisRawImport::KisRawImport(KoFilter *, const char *, const TQStringList&)
+ : KoFilter()
+ , m_data(0)
+ , m_process(0)
+ , m_progress(0)
+ , m_err(false)
+{
+ m_dialog = new KDialogBase();
+ m_dialog->enableButtonApply(false);
+ m_page = new WdgRawImport(m_dialog);
+ m_dialog -> setMainWidget(m_page);
+
+ connect(m_page->bnPreview, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotUpdatePreview()));
+ connect(m_page->grpColorSpace, TQT_SIGNAL(clicked( int )), this, TQT_SLOT(slotFillCmbProfiles()));
+ connect(m_page->grpChannelDepth, TQT_SIGNAL(clicked( int )), this, TQT_SLOT(slotFillCmbProfiles()));
+
+ KisConfig cfg;
+ TQString monitorProfileName = cfg.monitorProfile();
+ m_monitorProfile = KisMetaRegistry::instance()->csRegistry()->getProfileByName(monitorProfileName);
+
+ slotFillCmbProfiles();
+}
+
+KisRawImport::~KisRawImport()
+{
+ delete m_dialog;
+ delete m_process;
+}
+
+KoFilter::ConversiontqStatus KisRawImport::convert(const TQCString& from, const TQCString& to)
+{
+ if (from != "image/x-raw" || to != "application/x-chalk") {
+ return KoFilter::NotImplemented;
+ }
+
+ if (m_err) {
+ return KoFilter::CreationError;
+ }
+
+ kdDebug(41008) << "Chalk importing from Raw\n";
+
+ KisDoc * doc = dynamic_cast<KisDoc*>(m_chain -> outputDocument());
+ if (!doc) {
+ return KoFilter::CreationError;
+ }
+
+ doc -> prepareForImport();
+
+ TQString filename = m_chain -> inputFile();
+
+ if (filename.isEmpty()) {
+ return KoFilter::FileNotFound;
+ }
+
+ slotUpdatePreview();
+
+ // Show dialog
+ m_dialog->setCursor(TQt::ArrowCursor);
+ TQApplication::setOverrideCursor(TQt::ArrowCursor);
+
+ KConfig * cfg = KGlobal::config();
+ cfg->setGroup("rawimport");
+
+ m_page->radioGray->setChecked(cfg->readBoolEntry("gray", false));
+ m_page->radioRGB->setChecked(cfg->readBoolEntry("rgb", true));
+ m_page->radio8->setChecked(cfg->readBoolEntry("8bit", false));
+ m_page->radio16->setChecked(cfg->readBoolEntry("16bit", true));
+ m_page->chkFourColorRGB->setChecked( cfg->readBoolEntry("four_color_rgb", false));
+ m_page->chkCameraColors->setChecked( cfg->readBoolEntry("camera_colors", false));
+ m_page->chkBrightness->setChecked( cfg->readBoolEntry("do_brightness", false));
+ m_page->chkBlackpoint->setChecked( cfg->readBoolEntry("do_blackpoint", false));
+ m_page->chkRed->setChecked( cfg->readBoolEntry("do_red", false));
+ m_page->chkBlue->setChecked( cfg->readBoolEntry("do_blue", false));
+ m_page->radioFixed->setChecked( cfg->readBoolEntry("fixed_wb", true));
+ m_page->radioAutomatic->setChecked( cfg->readBoolEntry("automatic_wb", false));
+ m_page->radioCamera->setChecked( cfg->readBoolEntry("camera_wb", false));
+ m_page->chkClip->setChecked( cfg->readBoolEntry("clip", true));
+ m_page->chkProfile->setChecked(cfg->readBoolEntry("useprofile", false));
+ m_page->dblBrightness->setValue(cfg->readDoubleNumEntry("brightness", 1.0));
+ m_page->dblBlackpoint->setValue(cfg->readDoubleNumEntry("blackpoint", 0));
+ m_page->dblRed->setValue(cfg->readDoubleNumEntry("red", 1.0));
+ m_page->dblBlue->setValue(cfg->readDoubleNumEntry("blue", 1.0));
+
+ if (m_dialog->exec() == TQDialog::Accepted) {
+
+ cfg->writeEntry("gray", m_page->radioGray->isChecked());
+ cfg->writeEntry("rgb", m_page->radioRGB->isChecked());
+ cfg->writeEntry("8bit", m_page->radio8->isChecked());
+ cfg->writeEntry("16bit", m_page->radio16->isChecked());
+ cfg->writeEntry("four_color_rgb", m_page->chkFourColorRGB -> isChecked());
+ cfg->writeEntry("camera_colors", m_page->chkCameraColors -> isChecked());
+ cfg->writeEntry("do_brightness", m_page->chkBrightness -> isChecked());
+ cfg->writeEntry("do_blackpoint", m_page->chkBlackpoint -> isChecked());
+ cfg->writeEntry("do_red", m_page->chkRed -> isChecked());
+ cfg->writeEntry("do_blue", m_page->chkBlue -> isChecked());
+ cfg->writeEntry("fixed_wb", m_page->radioFixed -> isChecked());
+ cfg->writeEntry("automatic_wb", m_page->radioAutomatic -> isChecked());
+ cfg->writeEntry("camera_wb", m_page->radioCamera -> isChecked());
+ cfg->writeEntry("clip", m_page->chkClip->isChecked());
+ cfg->writeEntry("useprofile", m_page->chkProfile->isChecked());
+ cfg->writeEntry("brightness", m_page->dblBrightness->value());
+ cfg->writeEntry("blackpoint", m_page->dblBlackpoint->value());
+ cfg->writeEntry("red", m_page->dblRed->value());
+ cfg->writeEntry("blue", m_page->dblBlue->value());
+
+ TQApplication::setOverrideCursor(TQt::waitCursor);
+ // Create a busy indicator to show that we didn't die or so
+ m_progress = new TQProgressDialog();
+ m_progress -> setTotalSteps(0);
+ m_progress -> setCancelButton(0);
+ TQTimer timer;
+ connect(&timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(incrementProgress()));
+ timer.start(200);
+
+ doc -> undoAdapter() -> setUndo(false);
+
+ getImageData(createArgumentList(false));
+
+ KisImageSP image = 0;
+ KisPaintLayerSP layer = 0;
+ KisPaintDeviceSP device = 0;
+
+ TQApplication::restoreOverrideCursor();
+
+ delete m_progress;
+ m_progress = 0;
+
+ if (m_page->radio8->isChecked()) {
+ // 8 bits
+
+ TQImage img;
+ img.loadFromData(*m_data);
+
+ KisColorSpace * cs = 0;
+ if (m_page->radioGray->isChecked()) {
+ cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace( KisID("GRAYA"), profile() );
+ }
+ else {
+ cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace( KisID("RGBA"), profile() );
+ }
+ if (cs == 0) { kdDebug() << "No CS\n"; return KoFilter::InternalError; }
+
+ image = new KisImage(doc->undoAdapter(), img.width(), img.height(), cs, filename);
+ if (image == 0) return KoFilter::CreationError;
+ image->blockSignals(true); // Don't send out signals while we're building the image
+
+ layer = dynamic_cast<KisPaintLayer*>( image->newLayer(image -> nextLayerName(), OPACITY_OPAQUE).data() );
+ if (layer == 0) return KoFilter::CreationError;
+
+ device = layer->paintDevice();
+ if (device == 0) return KoFilter::CreationError;
+
+ device->convertFromTQImage(img, "");
+
+ } else {
+ // 16 bits
+
+ TQ_UINT32 startOfImagedata = 0;
+ TQSize sz = determineSize(startOfImagedata);
+
+ kdDebug(41008) << "Total bytes: " << m_data->size()
+ << "\n start of image data: " << startOfImagedata
+ << "\n bytes for pixels left: " << m_data->size() - startOfImagedata
+ << "\n total pixels: " << sz.width() * sz.height()
+ << "\n total pixel bytes: " << sz.width() * sz.height() * 6
+ << "\n total necessary bytes: " << (sz.width() * sz.height() * 6) + startOfImagedata
+ << "\n";
+
+
+ char * data = m_data->data() + startOfImagedata;
+
+ KisColorSpace * cs = 0;
+ if (m_page->radioGray->isChecked()) {
+ cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace( KisID("GRAYA16"), profile() );
+ }
+ else {
+ cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace( KisID("RGBA16"), profile() );
+ }
+ if (cs == 0) return KoFilter::InternalError;
+
+ image = new KisImage( doc->undoAdapter(), sz.width(), sz.height(), cs, filename);
+ if (image == 0)return KoFilter::CreationError;
+
+ layer = dynamic_cast<KisPaintLayer*> (image->newLayer(image -> nextLayerName(), OPACITY_OPAQUE).data());
+ if (layer == 0) return KoFilter::CreationError;
+
+ device = layer->paintDevice();
+ if (device == 0) return KoFilter::CreationError;
+
+ // Copy the colordata to the pixels
+ int pos = 0;
+
+ for (int line = 0; line < sz.height(); ++line) {
+ KisHLineIterator it = device->createHLineIterator(0, line, sz.width(), true);
+
+ while (!it.isDone()) {
+ if (m_page->radioGray->isChecked()) {
+ TQ_UINT16 d = (TQ_INT16)*(data + pos);
+ d = ntohs(d);
+ memcpy(it.rawData(), &d, 2);
+ pos += 2;
+ }
+ else {
+ // Red
+ TQ_UINT16 d = (TQ_INT16)*(data + pos);
+ d = ntohs(d);
+ memcpy(it.rawData() + 4, &d, 2);
+
+ // Green
+ pos += 2;
+ d = (TQ_INT16)*(data + pos );
+ d = ntohs(d);
+ memcpy(it.rawData() + 2, &d, 2);
+
+ // Blue
+ pos += 2;
+ d = (TQ_INT16)*(data + pos );
+ d = ntohs(d);
+ memcpy(it.rawData(), &d, 2);
+
+ pos += 2;
+ }
+ cs->setAlpha(it.rawData(), OPACITY_OPAQUE, 1);
+ ++it;
+ }
+ }
+ }
+ layer->setDirty();
+ kdDebug() << "going to set image\n";
+ doc -> setCurrentImage(image);
+ doc -> undoAdapter() -> setUndo(true);
+ doc -> setModified(false);
+ kdDebug() << "everything ok\n";
+
+ TQApplication::restoreOverrideCursor();
+ return KoFilter::OK;
+ }
+
+ TQApplication::restoreOverrideCursor();
+ return KoFilter::UserCancelled;
+}
+
+void KisRawImport::incrementProgress()
+{
+ m_progress -> setProgress(m_progress -> progress() + 10);
+}
+
+
+void KisRawImport::slotUpdatePreview()
+{
+ TQApplication::setOverrideCursor(TQt::waitCursor);
+ getImageData(createArgumentList(true));
+
+ kdDebug(41008) << "Retrieved " << m_data->size() << " bytes of image data\n";
+
+ if (m_data->isNull()) return;
+
+ TQImage img;
+
+ if (m_page->radio8->isChecked()) {
+ // 8 bits
+ img.loadFromData(*m_data);
+
+ } else {
+ // 16 bits
+
+ TQ_UINT32 startOfImagedata = 0;
+ TQSize sz = determineSize(startOfImagedata);
+
+ kdDebug(41008) << "Total bytes: " << m_data->size()
+ << "\n start of image data: " << startOfImagedata
+ << "\n bytes for pixels left: " << m_data->size() - startOfImagedata
+ << "\n total pixels: " << sz.width() * sz.height()
+ << "\n total pixel bytes: " << sz.width() * sz.height() * 6
+ << "\n total necessary bytes: " << (sz.width() * sz.height() * 6) + startOfImagedata
+ << "\n";
+
+ char * data = m_data->data() + startOfImagedata;
+
+ KisColorSpace * cs = 0;
+ if (m_page->radioGray->isChecked()) {
+ cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace( KisID("GRAYA16"), profile() );
+ }
+ else {
+ cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace( KisID("RGBA16"), profile() );
+ }
+ KisPaintDevice * dev = new KisPaintDevice(cs, "preview");
+ // Copy the colordata to the pixels
+ int pos = 0;
+
+ for (int line = 0; line < sz.height(); ++line) {
+ KisHLineIterator it = dev->createHLineIterator(0, line, sz.width(), true);
+
+ while (!it.isDone()) {
+ if (m_page->radioGray->isChecked()) {
+ TQ_UINT16 d = (TQ_INT16)*(data + pos);
+ d = ntohs(d);
+ memcpy(it.rawData(), &d, 2);
+ pos += 2;
+ }
+ else {
+ // Red
+ TQ_UINT16 d = (TQ_INT16)*(data + pos);
+ d = ntohs(d);
+ memcpy(it.rawData() + 4, &d, 2);
+
+ // Green
+ pos += 2;
+ d = (TQ_INT16)*(data + pos );
+ d = ntohs(d);
+ memcpy(it.rawData() + 2, &d, 2);
+
+ // Blue
+ pos += 2;
+ d = (TQ_INT16)*(data + pos );
+ d = ntohs(d);
+ memcpy(it.rawData(), &d, 2);
+
+ pos += 2;
+ }
+ cs->setAlpha(it.rawData(), OPACITY_OPAQUE, 1);
+ ++it;
+ }
+ }
+
+ img = dev->convertToTQImage(m_monitorProfile);
+ }
+
+ m_page->lblPreview->setImage(img);
+ TQApplication::restoreOverrideCursor();
+}
+
+
+void KisRawImport::getImageData( TQStringList arguments )
+{
+ // delete m_process;
+ delete m_data;
+
+ kdDebug(41008) << "getImageData " << arguments.join(" ") << "\n";
+ KProcess process (this);
+ m_data = new TQByteArray(0);
+
+ for (TQStringList::iterator it = arguments.begin(); it != arguments.end(); ++it) {
+ process << *it;
+ }
+
+ process.setUseShell(true);
+ connect(&process, TQT_SIGNAL(receivedStdout(KProcess *, char *, int)), this, TQT_SLOT(slotReceivedStdout(KProcess *, char *, int)));
+ connect(&process, TQT_SIGNAL(receivedStderr(KProcess *, char *, int)), this, TQT_SLOT(slotReceivedStderr(KProcess *, char *, int)));
+ connect(&process, TQT_SIGNAL(processExited(KProcess *)), this, TQT_SLOT(slotProcessDone()));
+
+
+ kdDebug(41008) << "Starting process\n";
+
+ if (!process.start(KProcess::NotifyOnExit, KProcess::AllOutput)) {
+ KMessageBox::error( 0, i18n("Cannot convert RAW files because the dcraw executable could not be started."));
+ }
+ while (process.isRunning()) {
+ //kdDebug(41008) << "Waiting...\n";
+ tqApp->eventLoop()->processEvents(TQEventLoop::ExcludeUserInput);
+ //process.wait(2);
+ }
+
+ if (process.normalExit()) {
+ kdDebug(41008) << "Return value of process: " << process.exitStatus() << "\n";
+ }
+ else {
+ kdDebug(41008) << "Process did not exit normally. Exit signal: " << process.exitSignal() << "\n";
+ m_err = true;
+ }
+
+}
+
+
+void KisRawImport::slotProcessDone()
+{
+ kdDebug(41008) << "process done!\n";
+}
+
+void KisRawImport::slotReceivedStdout(KProcess *, char *buffer, int buflen)
+{
+ //kdDebug(41008) << "stdout received " << buflen << " bytes on stdout.\n";
+ //kdDebug(41008) << TQString::fromAscii(buffer, buflen) << "\n";
+ int oldSize = m_data->size();
+ m_data->resize(oldSize + buflen, TQGArray::SpeedOptim);
+ memcpy(m_data->data() + oldSize, buffer, buflen);
+}
+
+void KisRawImport::slotReceivedStderr(KProcess *, char *buffer, int buflen)
+{
+ TQByteArray b(buflen);
+ memcpy(b.data(), buffer, buflen);
+ kdDebug(41008) << TQString(b) << "\n";
+ KMessageBox::error(0, i18n("Error: Dcraw cannot load this image. Message: ") + TQString(b));
+ m_err = true;
+}
+
+
+TQStringList KisRawImport::createArgumentList(bool forPreview)
+{
+ TQStringList args;
+
+ args.append("dcraw"); // XXX: Create a chalkdcraw so we can count on it being available
+
+ //args.append("-v"); // Verbose
+
+ args.append("-c"); // Write to stdout
+
+ if (forPreview) {
+ args.append("-h"); // Fast, half size image
+ }
+
+ if (m_page->radio8->isChecked()) {
+ args.append("-2"); // 8 bits
+ }
+ else {
+ args.append("-4"); // 16 bits
+ }
+
+ if (m_page->radioGray->isChecked()) {
+ args.append("-d"); // Create grayscale image
+ }
+
+ if (m_page->chkCameraColors->isChecked()) {
+ args.append("-m"); // Use camera raw colors instead of sRGB
+ }
+
+ if (m_page->radioAutomatic->isChecked()) {
+ args.append("-a"); // Automatic white balancing
+ }
+
+ if (m_page->radioCamera->isChecked()) {
+ args.append("-w"); // Use camera white balance, if present
+ }
+
+ if (m_page->chkFourColorRGB->isChecked()) {
+ args.append("-f"); // Interpolate RGB as four colors
+ }
+
+ if (!m_page->chkClip->isChecked()) {
+ args.append("-n"); // Do not clip colors
+ }
+
+ if (m_page->chkBrightness->isChecked()) {
+ args.append("-b " + TQString::number(m_page->dblBrightness->value()));
+ }
+
+ if (m_page->chkBlackpoint->isChecked()) {
+ args.append("-k " + TQString::number(m_page->dblBlackpoint->value()));
+ }
+
+ if (m_page->chkRed->isChecked()) {
+ args.append("-r " + TQString::number(m_page->dblRed->value()));
+ }
+
+ if (m_page->chkBlue->isChecked()) {
+ args.append("-l " + TQString::number(m_page->dblBlue->value()));
+ }
+
+
+ KisProfile * pf = profile();
+ if (m_page->chkProfile->isChecked()) {
+ if (!pf->filename().isNull()) {
+ // Use the user-set profile, if it's not an lcms internal
+ // profile. This does not add the profile to the image, we
+ // need to do that later.
+ args.append("-p \"" + pf->filename() + "\"");
+ }
+ }
+
+ // Don't forget the filename
+ args.append("\"" + m_chain -> inputFile() + "\"");
+
+ return args;
+}
+
+TQSize KisRawImport::determineSize(TQ_UINT32& startOfImageData)
+{
+ if (m_data->isNull() || m_data->size() < 2048) {
+ startOfImageData = 0;
+ return TQSize(0,0);
+ }
+
+ TQString magick = TQString::fromAscii(m_data->data(), 2);
+ if (magick != "P6") {
+ kdDebug(41008) << " Bad magick! " << magick << "\n";
+ startOfImageData = 0;
+ return TQSize(0,0);
+ }
+
+ // Find the third newline that marks the header end in a dcraw generated ppm.
+ TQ_UINT32 i = 0;
+ TQ_UINT32 counter = 0;
+
+ while (true) {
+ if (counter == 3) break;
+ if (m_data->data()[i] == '\n') {
+ counter++;
+ }
+ ++i;
+ }
+
+ TQString size = TQStringList::split("\n", TQString::fromAscii(m_data->data(), i))[1];
+ kdDebug(41008) << "Header: " << TQString::fromAscii(m_data->data(), i) << "\n";
+ TQStringList sizelist = TQStringList::split(" ", size);
+ TQ_INT32 w = sizelist[0].toInt();
+ TQ_INT32 h = sizelist[1].toInt();
+
+ startOfImageData = i;
+ return TQSize(w, h);
+
+}
+
+KisProfile * KisRawImport::profile()
+{
+ if (m_page->chkProfile->isChecked()) {
+ return KisMetaRegistry::instance()->csRegistry()->getProfileByName(m_page->cmbProfile->currentText());
+ }
+ else
+ return 0;
+}
+
+void KisRawImport::slotFillCmbProfiles()
+{
+ KisID s = getColorSpace();
+
+ KisColorSpaceFactory * csf = KisMetaRegistry::instance()->csRegistry() -> get(s);
+ m_page -> cmbProfile -> clear();
+ TQValueVector<KisProfile *> profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf );
+ TQValueVector<KisProfile *> ::iterator it;
+ for ( it = profileList.begin(); it != profileList.end(); ++it ) {
+ m_page -> cmbProfile -> insertItem((*it) -> productName());
+ }
+}
+
+KisID KisRawImport::getColorSpace()
+{
+ if (m_page->radioRGB->isChecked()) {
+ if (m_page->radio16->isChecked()) {
+ return KisID( "RGBA16" );
+ }
+ }
+ else {
+ if (m_page->radio16->isChecked()) {
+ return KisID( "GRAYA16" );
+ }
+ else {
+ return KisID( "GRAYA" );
+ }
+ }
+ return KisID("RGBA");
+}
+
+#include "kis_raw_import.moc"
diff --git a/filters/chalk/raw/kis_raw_import.h b/filters/chalk/raw/kis_raw_import.h
new file mode 100644
index 00000000..35adb6e1
--- /dev/null
+++ b/filters/chalk/raw/kis_raw_import.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KIS_RAW_IMPORT_H_
+#define KIS_RAW_IMPORT_H_
+
+#include <KoFilter.h>
+
+class KProcess;
+class KDialogBase;
+class WdgRawImport;
+class KisProfile;
+class TQProgressDialog;
+
+class KisRawImport : public KoFilter {
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ KisRawImport(KoFilter *tqparent, const char *name, const TQStringList&);
+ virtual ~KisRawImport();
+
+public:
+ virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to);
+
+
+private slots:
+
+ void slotUpdatePreview();
+ void slotFillCmbProfiles();
+ void slotProcessDone();
+ void slotReceivedStdout(KProcess *proc, char *buffer, int buflen);
+ void slotReceivedStderr(KProcess *proc, char *buffer, int buflen);
+ void incrementProgress();
+
+private:
+
+ TQStringList createArgumentList(bool forPreview = false);
+ TQSize determineSize(TQ_UINT32& startOfImageData);
+ void getImageData(TQStringList arguments);
+ KisProfile * profile();
+ KisID getColorSpace();
+
+private:
+ TQByteArray * m_data;
+ KDialogBase * m_dialog;
+ WdgRawImport * m_page;
+ KisProfile * m_monitorProfile;
+ KProcess * m_process;
+ TQProgressDialog* m_progress;
+ bool m_err; // Set to true when slotReceivedStderr is called
+};
+
+#endif // KIS_RAW_IMPORT_H_
+
diff --git a/filters/chalk/raw/wdgrawimport.ui b/filters/chalk/raw/wdgrawimport.ui
new file mode 100644
index 00000000..d6080a01
--- /dev/null
+++ b/filters/chalk/raw/wdgrawimport.ui
@@ -0,0 +1,496 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>WdgRawImport</class>
+<widget class="TQWidget">
+ <property name="name">
+ <cstring>WdgRawImport</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>835</width>
+ <height>596</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQPushButton" row="2" column="2">
+ <property name="name">
+ <cstring>bnPreview</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Update Preview</string>
+ </property>
+ </widget>
+ <widget class="ImageViewer" row="0" column="1" rowspan="2" colspan="2">
+ <property name="name">
+ <cstring>lblPreview</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="tqminimumSize">
+ <size>
+ <width>200</width>
+ <height>150</height>
+ </size>
+ </property>
+ </widget>
+ <widget class="TQLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tqlayout2</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQGroupBox">
+ <property name="name">
+ <cstring>grpColorSettings</cstring>
+ </property>
+ <property name="title">
+ <string>Color Settings</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>chkBlackpoint</cstring>
+ </property>
+ <property name="text">
+ <string>Blackpoint:</string>
+ </property>
+ </widget>
+ <widget class="TQCheckBox" row="2" column="0">
+ <property name="name">
+ <cstring>chkRed</cstring>
+ </property>
+ <property name="text">
+ <string>Red multiplier:</string>
+ </property>
+ </widget>
+ <widget class="KDoubleSpinBox" row="2" column="1">
+ <property name="name">
+ <cstring>dblRed</cstring>
+ </property>
+ <property name="minValue">
+ <number>0.1</number>
+ </property>
+ <property name="value">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="TQCheckBox" row="3" column="0">
+ <property name="name">
+ <cstring>chkBlue</cstring>
+ </property>
+ <property name="text">
+ <string>Blue multiplier:</string>
+ </property>
+ </widget>
+ <widget class="KDoubleSpinBox" row="3" column="1">
+ <property name="name">
+ <cstring>dblBlue</cstring>
+ </property>
+ <property name="minValue">
+ <number>0.1</number>
+ </property>
+ <property name="value">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="KDoubleSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>dblBlackpoint</cstring>
+ </property>
+ </widget>
+ <widget class="KDoubleSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>dblBrightness</cstring>
+ </property>
+ <property name="minValue">
+ <number>0.1</number>
+ </property>
+ <property name="value">
+ <number>2</number>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Brightness. 1.0 is default</string>
+ </property>
+ </widget>
+ <widget class="TQButtonGroup" row="4" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>grpWhiteBalance</cstring>
+ </property>
+ <property name="title">
+ <string>&amp;White Balance</string>
+ </property>
+ <property name="exclusive">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQRadioButton">
+ <property name="name">
+ <cstring>radioFixed</cstring>
+ </property>
+ <property name="text">
+ <string>White card in sunlight</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="TQRadioButton">
+ <property name="name">
+ <cstring>radioAutomatic</cstring>
+ </property>
+ <property name="text">
+ <string>Automatic</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Automatic color balance. The default is to use a fixed color balance based on a white card photographed in sunlight.</string>
+ </property>
+ </widget>
+ <widget class="TQRadioButton">
+ <property name="name">
+ <cstring>radioCamera</cstring>
+ </property>
+ <property name="text">
+ <string>From camera</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>
+ Use the color balance specified by the camera. If this cannot be found, dcraw prints a warning and reverts to the default. </string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="TQCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>chkBrightness</cstring>
+ </property>
+ <property name="text">
+ <string>Brightness:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQButtonGroup">
+ <property name="name">
+ <cstring>grpColorSpace</cstring>
+ </property>
+ <property name="title">
+ <string>Colorspace</string>
+ </property>
+ <property name="exclusive">
+ <bool>true</bool>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>radioGray</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Document mode</string>
+ </property>
+ </widget>
+ <widget class="TQRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>radioRGB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;RGB</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQButtonGroup">
+ <property name="name">
+ <cstring>grpChannelDepth</cstring>
+ </property>
+ <property name="title">
+ <string>Channel Depth</string>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <property name="exclusive">
+ <bool>true</bool>
+ </property>
+ <property name="selectedId" stdset="0">
+ <number>0</number>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>radio16</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;16 bits per channel</string>
+ </property>
+ <property name="accel">
+ <string>Alt+1</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="TQRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>radio8</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;8 bits per channel</string>
+ </property>
+ <property name="accel">
+ <string>Alt+8</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQCheckBox">
+ <property name="name">
+ <cstring>chkFourColorRGB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Interpolate RGB as four colors</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Interpolate RGB as four colors. This blurs the image a little, but it eliminates false 2x2 mesh patterns. </string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer row="2" column="1">
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="tqsizeHint">
+ <size>
+ <width>500</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="1" column="0" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>spacer3_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="tqsizeHint">
+ <size>
+ <width>20</width>
+ <height>120</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQLayoutWidget" row="3" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>tqlayout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQCheckBox">
+ <property name="name">
+ <cstring>chkClip</cstring>
+ </property>
+ <property name="text">
+ <string>Clip colors to prevent pink highlights</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>By default, dcraw clips all colors to prevent pink hues in the highlights. Combine this option with -b 0.25 to leave the image data completely unclipped.</string>
+ </property>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>tqlayout10</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQCheckBox">
+ <property name="name">
+ <cstring>chkProfile</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KisCmbIDList">
+ <property name="name">
+ <cstring>cmbProfile</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="TQCheckBox">
+ <property name="name">
+ <cstring>chkCameraColors</cstring>
+ </property>
+ <property name="text">
+ <string>Use camera raw colors, not sRGB</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="tqsizeHint">
+ <size>
+ <width>41</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>KisCmbIDList</class>
+ <header location="local">kis_cmb_idlist.h</header>
+ <sizehint>
+ <width>1</width>
+ <height>24</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+ <customwidget>
+ <class>ImageViewer</class>
+ <header location="local">imageviewer.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image1</pixmap>
+ <signal>moved(QPoint)</signal>
+ <signal>moving(QPoint)</signal>
+ <signal>startMoving(QPoint)</signal>
+ <slot access="public" specifier="">zoomIn()</slot>
+ <slot access="public" specifier="">slot()</slot>
+ <slot access="public" specifier="">zoomOut()</slot>
+ <slot access="public" specifier="">slot()</slot>
+ <slot access="public" specifier="">slot()</slot>
+ <slot access="public" specifier="">slotMoving(QPoint)</slot>
+ <slot access="public" specifier="">slotMoved(QPoint)</slot>
+ <slot access="public" specifier="">slot()</slot>
+ <slot access="public" specifier="">slotStartMoving(QPoint)</slot>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="1002">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082</data>
+ </image>
+ <image name="image1">
+ <data format="XBM.GZ" length="79">789c534e494dcbcc4b554829cdcdad8c2fcf4c29c95030e0524611cd48cd4ccf28010a1797249664262b2467241641a592324b8aa363156c15aab914146aadb90067111b1f</data>
+ </image>
+</images>
+<tabstops>
+ <tabstop>radioRGB</tabstop>
+ <tabstop>radio16</tabstop>
+ <tabstop>chkBrightness</tabstop>
+ <tabstop>dblBrightness</tabstop>
+ <tabstop>chkBlackpoint</tabstop>
+ <tabstop>dblBlackpoint</tabstop>
+ <tabstop>chkRed</tabstop>
+ <tabstop>dblRed</tabstop>
+ <tabstop>chkBlue</tabstop>
+ <tabstop>dblBlue</tabstop>
+ <tabstop>radioFixed</tabstop>
+ <tabstop>chkFourColorRGB</tabstop>
+ <tabstop>chkClip</tabstop>
+ <tabstop>chkProfile</tabstop>
+ <tabstop>chkCameraColors</tabstop>
+ <tabstop>bnPreview</tabstop>
+ <tabstop>radioAutomatic</tabstop>
+</tabstops>
+<tqlayoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/filters/chalk/tiff/Makefile.am b/filters/chalk/tiff/Makefile.am
new file mode 100644
index 00000000..2e120576
--- /dev/null
+++ b/filters/chalk/tiff/Makefile.am
@@ -0,0 +1,55 @@
+kde_module_LTLIBRARIES = libchalktiffimport.la libchalktiffexport.la
+
+libchalktiffexport_la_LDFLAGS = -avoid-version -module -no-undefined \
+ $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalktiffexport_la_LIBADD = $(top_builddir)/chalk/libchalkcommon.la \
+ libchalktiffconverter.la $(KOFFICE_LIBS) -ltiff
+
+libchalktiffimport_la_LDFLAGS = -avoid-version -module -no-undefined \
+ $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalktiffimport_la_LIBADD = $(top_builddir)/chalk/libchalkcommon.la \
+ libchalktiffconverter.la $(KOFFICE_LIBS) -ltiff
+
+INCLUDES= \
+ -I$(srcdir) \
+ $(KOFFICE_INCLUDES) \
+ -I$(top_srcdir)/chalk \
+ -I$(top_srcdir)/chalk/core \
+ -I$(top_srcdir)/chalk/sdk \
+ -I$(top_srcdir)/chalk/core/tiles \
+ -I$(top_srcdir)/chalk/chalkcolor \
+ -I$(top_srcdir)/chalk/ui \
+ $(KOFFICE_INCLUDES) -I$(interfacedir) \
+ $(KOPAINTER_INCLUDES) \
+ $(all_includes)
+
+
+servicedir = $(kde_servicesdir)
+
+
+kdelnkdir = $(kde_appsdir)/.hidden
+
+
+
+
+METASOURCES = AUTO
+
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+libchalktiffimport_la_SOURCES = kis_tiff_import.cc
+libchalktiffexport_la_SOURCES = kis_tiff_export.cc kis_wdg_options_tiff.ui \
+ kis_dlg_options_tiff.cpp
+service_DATA = chalk_tiff_export.desktop chalk_tiff_import.desktop
+kdelnk_DATA = chalk_tiff.desktop
+noinst_HEADERS = kis_dlg_options_tiff.h kis_tiff_writer_visitor.h \
+ kis_tiff_ycbcr_reader.h
+libchalktiffconverter_la_LDFLAGS = -no-undefined $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+noinst_LTLIBRARIES = libchalktiffconverter.la
+libchalktiffconverter_la_SOURCES = kis_tiff_converter.cc kis_tiff_stream.cc \
+ kis_tiff_writer_visitor.cpp kis_tiff_reader.cc kis_tiff_ycbcr_reader.cc
diff --git a/filters/chalk/tiff/chalk_tiff.desktop b/filters/chalk/tiff/chalk_tiff.desktop
new file mode 100644
index 00000000..55cd1033
--- /dev/null
+++ b/filters/chalk/tiff/chalk_tiff.desktop
@@ -0,0 +1,63 @@
+[Desktop Entry]
+Categories=
+Exec=chalk %u
+GenericName=Painting and Image Editing Application
+GenericName[bg]=Редактор на графични изображения
+GenericName[ca]=Programa de dibuix i manipulació d'imatges
+GenericName[cs]=Malování a úpravy obrázků
+GenericName[cy]=Cymhwysiad Peintio Golygu Delweddau
+GenericName[da]=Male- og billedredigeringsprogram
+GenericName[de]=Mal- und Bildbearbeitungsprogramm
+GenericName[el]=Εφαρμογή επεξεργασίας εικόνων
+GenericName[eo]=Aplikaĵo por Pentrado kaj Bildredaktado
+GenericName[es]=Aplicación de pintura y de edición de imágenes
+GenericName[et]=Joonistamise ja pilditöötluse rakendus
+GenericName[eu]=Irudien marrazketa eta ediziorako aplikazioa
+GenericName[fa]=کاربرد ویرایش تصویر و نقاشی
+GenericName[fi]=Maalaus- ja kuvankäsitelyohjelma
+GenericName[fr]=Application de dessin et de manipulation d'images
+GenericName[fy]=Ofbyldingsmanipulaasje
+GenericName[gl]=Aplicación de Pintura e Manipulación de Imaxes
+GenericName[he]=יישום לציור ועריכת תמונות
+GenericName[hr]=Aplikacija za obradu slika i fotografija
+GenericName[hu]=Képszerkesztő
+GenericName[is]=Málun og myndritill
+GenericName[it]=Applicazione di disegno e di modifica delle immagini
+GenericName[ja]=描画と画像編集のためのアプリケーション
+GenericName[km]=កម្មវិធី​គូរ​គំនូរ និង​កែសម្រួល​រូបភាព
+GenericName[lv]=Zīmēšanas un attēlu apstrādes programma
+GenericName[nb]=Program for tegning og bilderedigering
+GenericName[nds]=Programm för't Malen un Bildbewerken
+GenericName[ne]=पेन्टीङ्ग र छवि सम्पादन अनुप्रयोग
+GenericName[nl]=Afbeeldingsmanipulatie
+GenericName[pl]=Program do edycji zdjęć oraz rysunków
+GenericName[pt]=Aplicação de Pintura e Edição de Imagens
+GenericName[pt_BR]=Aplicação de Pintura e Edição de Imagens
+GenericName[ru]=Растровые изображения
+GenericName[se]=Málen- ja govvagieđahallanprográmma
+GenericName[sk]=Program pre tvorbu a úpravu obrázkov
+GenericName[sl]=Program za risanje in obdelavo slik
+GenericName[sr]=Програм за цртање и уређивање слика
+GenericName[sr@Latn]=Program za crtanje i uređivanje slika
+GenericName[sv]=Målnings- och bildredigeringsprogram
+GenericName[uk]=Програма для малювання і редагування зображень
+GenericName[uz]=Rasmlar bilan ishlaydigan dastur
+GenericName[uz@cyrillic]=Расмлар билан ишлайдиган дастур
+GenericName[zh_CN]=绘图和图像编辑应用程序
+GenericName[zh_TW]=繪圖與影像處理程式
+Icon=chalk
+MimeType=image/tiff
+Name=Chalk
+Name[hi]=के-रिता
+Name[km]= Chalk
+Name[lo]=ກຣິຕາ
+Name[ne]=क्रिता
+Path=
+StartupNotify=true
+Terminal=false
+TerminalOptions=
+Type=Application
+X-DCOP-ServiceType=multi
+X-KDE-StartupNotify=true
+X-KDE-SubstituteUID=false
+X-KDE-Username=
diff --git a/filters/chalk/tiff/chalk_tiff_export.desktop b/filters/chalk/tiff/chalk_tiff_export.desktop
new file mode 100644
index 00000000..3f174827
--- /dev/null
+++ b/filters/chalk/tiff/chalk_tiff_export.desktop
@@ -0,0 +1,52 @@
+[Desktop Entry]
+Icon=
+Name=Chalk TIFF Export Filter
+Name[bg]=Филтър за експортиране от Chalk в TIFF
+Name[br]=Sil ezporzh TIFF evit Chalk
+Name[ca]=Filtre d'exportació TIFF per a Chalk
+Name[da]=Chalk TIFF-eksportfilter
+Name[de]=Chalk TIFF-Exportfilter
+Name[el]=Φίλτρο εξαγωγής TIFF του Chalk
+Name[eo]=Chalk TIFF-eksportfiltrilo
+Name[es]=Filtro de exportación a TIFF de Chalk
+Name[et]=Chalk TIFF-i ekspordifilter
+Name[fa]=پالایۀ صادرات Chalk TIFF
+Name[fi]=Chalk TIFF -vientisuodin
+Name[fr]=Filtre d'exportation TIFF de Chalk
+Name[fy]=Chalk TIFF Eksportfilter
+Name[ga]=Scagaire Easpórtála TIFF Chalk
+Name[gl]=Filtro de Exportación de TIFF para Chalk
+Name[he]=Chalk TIFF מסנן יצוא
+Name[hr]=Chalk TIFF filtar izvoza
+Name[hu]=Chalk TIFF exportszűrő
+Name[is]=Chalk TIFF útflutningssía
+Name[it]=Filtro di esportazione TIFF per Chalk
+Name[ja]=Chalk TIFF エクスポートフィルタ
+Name[km]=តម្រង​នាំចេញ TIFF សម្រាប់ Chalk
+Name[lt]=Chalk TIFF eksportavimo filtras
+Name[lv]=Chalk TIFF eksporta filtrs
+Name[nb]=TIFF-eksportfilter for Chalk
+Name[nds]=TIFF-Exportfilter för Chalk
+Name[ne]=क्रिता TIFF निर्यात फिल्टर
+Name[nl]=Chalk TIFF Exportfilter
+Name[pl]=Filtr eksportu do formatu TIFF dla Chalk
+Name[pt]=Filtro de Exportação de TIFF para o Chalk
+Name[pt_BR]=Filtro de Exportação de TIFF para o Chalk
+Name[ru]=Фильтр экспорта рисунков Chalk в TIFF
+Name[se]=Chalk Tiff-olggosfievrridansilli
+Name[sk]=Exportný filter Chalk TIFF
+Name[sl]=Izvozni filter TIFF za Krito
+Name[sr]=Chalk-ин филтер за извоз у TIFF
+Name[sr@Latn]=Chalk-in filter za izvoz u TIFF
+Name[sv]=Chalk TIFF-exportfilter
+Name[uk]=Фільтр експорту TIFF для Chalk
+Name[uz]=Chalk TIFF eksport filteri
+Name[uz@cyrillic]=Chalk TIFF экспорт филтери
+Name[zh_CN]=Chalk TIFF 导出过滤器
+Name[zh_TW]=Chalk TIFF 匯出過濾程式
+ServiceTypes=KOfficeFilter
+Type=Service
+X-KDE-Export=image/tiff
+X-KDE-Import=application/x-chalk
+X-KDE-Library=libchalktiffexport
+X-KDE-Weight=1
diff --git a/filters/chalk/tiff/chalk_tiff_import.desktop b/filters/chalk/tiff/chalk_tiff_import.desktop
new file mode 100644
index 00000000..593b0eee
--- /dev/null
+++ b/filters/chalk/tiff/chalk_tiff_import.desktop
@@ -0,0 +1,52 @@
+[Desktop Entry]
+Icon=
+Name=Chalk TIFF Import Filter
+Name[bg]=Филтър за импортиране от TIFF в Chalk
+Name[br]=Sil enporzh TIFF evit Chalk
+Name[ca]=Filtre d'importació TIFF per a Chalk
+Name[da]=Chalk TIFF-importfilter
+Name[de]=Chalk TIFF-Importfilter
+Name[el]=Φίλτρο εισαγωγής TIFF του Chalk
+Name[eo]=Chalk TIFF-importfiltrilo
+Name[es]=Filtro de importación desde TIFF de Chalk
+Name[et]=Chalk TIFF-i impordifilter
+Name[fa]=پالایۀ واردات Chalk TIFF
+Name[fi]=Chalk TIFF -tuontisuodin
+Name[fr]=Filtre d'importation TIFF de Chalk
+Name[fy]=Chalk TIFF Ymportfilter
+Name[ga]=Scagaire Iompórtála TIFF Chalk
+Name[gl]=Filtro de Importación de TIFF para Chalk
+Name[he]=Chalk TIFF מסנן יבוא
+Name[hr]=Chalk TIFF filtar uvoza
+Name[hu]=Chalk TIFF importszűrő
+Name[is]=Chalk TIFF innflutningssía
+Name[it]=Filtro di importazione TIFF per Chalk
+Name[ja]=Chalk TIFF インポートフィルタ
+Name[km]=តម្រង​នាំចូល TIFF សម្រាប់ Chalk
+Name[lt]=Chalk TIFF importavimo filtras
+Name[lv]=Chalk TIFF importa filtrs
+Name[nb]=TIFF-importfilter for Chalk
+Name[nds]=TIFF-Importfilter för Chalk
+Name[ne]=क्रिता TIFF आयात फिल्टर
+Name[nl]=Chalk TIFF Importfilter
+Name[pl]=Filtr importu formatu TIFF dla Chalk
+Name[pt]=Filtro de Importação de TIFF para o Chalk
+Name[pt_BR]=Filtro de Importação de TIFF para o Chalk
+Name[ru]=Фильтр импорта рисунков TIFF в Chalk
+Name[se]=Chalk TIFF-sisafievrridansilli
+Name[sk]=TIFF filter pre import do Chalk
+Name[sl]=Uvozni filter TIFF za Krito
+Name[sr]=Chalk-ин филтер за увоз из TIFF-а
+Name[sr@Latn]=Chalk-in filter za uvoz iz TIFF-a
+Name[sv]=Chalk TIFF-importfilter
+Name[uk]=Фільтр імпорту TIFF для Chalk
+Name[uz]=Chalk TIFF import filteri
+Name[uz@cyrillic]=Chalk TIFF импорт филтери
+Name[zh_CN]=Chalk TIFF 导入过滤器
+Name[zh_TW]=Chalk TIFF 匯入過濾程式
+ServiceTypes=KOfficeFilter
+Type=Service
+X-KDE-Export=application/x-chalk
+X-KDE-Import=image/tiff
+X-KDE-Library=libchalktiffimport
+X-KDE-Weight=1
diff --git a/filters/chalk/tiff/configure.in.bot b/filters/chalk/tiff/configure.in.bot
new file mode 100644
index 00000000..8458154d
--- /dev/null
+++ b/filters/chalk/tiff/configure.in.bot
@@ -0,0 +1,7 @@
+if test -z "$LIBTIFF"; then
+ echo ""
+ echo "You're missing libtiff (binaries and/or headers), chalk won't be able"
+ echo "to import/export tiff"
+ echo ""
+ all_tests=bad
+fi
diff --git a/filters/chalk/tiff/kis_dlg_options_tiff.cpp b/filters/chalk/tiff/kis_dlg_options_tiff.cpp
new file mode 100644
index 00000000..345f7e7e
--- /dev/null
+++ b/filters/chalk/tiff/kis_dlg_options_tiff.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_dlg_options_tiff.h"
+
+#include <tqcheckbox.h>
+#include <tqgroupbox.h>
+#include <tqslider.h>
+#include <tqwidgetstack.h>
+
+#include <kapplication.h>
+#include <kcombobox.h>
+#include <klocale.h>
+
+#include "kis_wdg_options_tiff.h"
+
+KisDlgOptionsTIFF::KisDlgOptionsTIFF(TQWidget *tqparent, const char *name)
+ : KDialogBase(tqparent, name, false, i18n("TIFF Export Options"), KDialogBase::Ok | KDialogBase::Cancel)
+{
+ optionswdg = new KisWdgOptionsTIFF(this);
+ activated(0);
+ connect(optionswdg->kComboBoxCompressionType, TQT_SIGNAL(activated ( int )), this, TQT_SLOT(activated ( int ) ));
+ connect(optionswdg->flatten, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(flattenToggled( bool) ) );
+ setMainWidget(optionswdg);
+ kapp->restoreOverrideCursor();
+ tqsetSizePolicy(TQSizePolicy(TQSizePolicy::Minimum, TQSizePolicy::Minimum) );
+}
+
+KisDlgOptionsTIFF::~KisDlgOptionsTIFF()
+{
+}
+
+void KisDlgOptionsTIFF::activated ( int index )
+{
+/* optionswdg->groupBoxJPEG->hide();
+ optionswdg->groupBoxDeflate->hide();
+ optionswdg->groupBoxCCITGroupCCITG3->hide();
+ optionswdg->groupBoxPixarLog->hide();*/
+ switch(index)
+ {
+ case 1:
+ optionswdg->codecsOptionsStack->raiseWidget(1);
+// optionswdg->groupBoxJPEG->show();
+ break;
+ case 2:
+ optionswdg->codecsOptionsStack->raiseWidget(2);
+// optionswdg->groupBoxDeflate->show();
+ break;
+ case 6:
+ optionswdg->codecsOptionsStack->raiseWidget(3);
+// optionswdg->groupBoxCCITGroupCCITG3->show();
+ break;
+ case 8:
+ optionswdg->codecsOptionsStack->raiseWidget(4);
+// optionswdg->groupBoxPixarLog->show();
+ break;
+ default:
+ optionswdg->codecsOptionsStack->raiseWidget(0);
+ }
+}
+
+void KisDlgOptionsTIFF::flattenToggled(bool t)
+{
+ optionswdg->alpha->setEnabled(t);
+ if(!t)
+ {
+ optionswdg->alpha->setChecked(true);
+ }
+}
+
+
+KisTIFFOptions KisDlgOptionsTIFF::options()
+{
+ KisTIFFOptions options;
+ switch(optionswdg->kComboBoxCompressionType->currentItem ())
+ {
+ case 0:
+ options.compressionType = COMPRESSION_NONE;
+ break;
+ case 1:
+ options.compressionType = COMPRESSION_JPEG;
+ break;
+ case 2:
+ options.compressionType = COMPRESSION_DEFLATE;
+ break;
+ case 3:
+ options.compressionType = COMPRESSION_LZW;
+ break;
+#ifdef COMPRESSION_JP2000
+ case 4:
+ options.compressionType = COMPRESSION_JP2000;
+ break;
+#endif
+ case 5:
+ options.compressionType = COMPRESSION_CCITTRLE;
+ break;
+ case 6:
+ options.compressionType = COMPRESSION_CCITTFAX3;
+ break;
+ case 7:
+ options.compressionType = COMPRESSION_CCITTFAX4;
+ break;
+ case 8:
+ options.compressionType = COMPRESSION_PIXARLOG;
+ break;
+ }
+ options.predictor = optionswdg->kComboBoxPredictor->currentItem() + 1;
+ options.alpha = optionswdg->alpha->isChecked();
+ options.flatten = optionswdg->flatten->isChecked();
+ options.jpegQuality = optionswdg->qualityLevel->value();
+ options.deflateCompress = optionswdg->compressionLevelDeflate->value();
+ options.faxMode = optionswdg->kComboBoxFaxMode->currentItem() + 1;
+ options.pixarLogCompress = optionswdg->compressionLevelPixarLog->value();
+
+ return options;
+}
+
+#include "kis_dlg_options_tiff.moc"
diff --git a/filters/chalk/tiff/kis_dlg_options_tiff.h b/filters/chalk/tiff/kis_dlg_options_tiff.h
new file mode 100644
index 00000000..5fd1e48e
--- /dev/null
+++ b/filters/chalk/tiff/kis_dlg_options_tiff.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2005-2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KIS_DLG_OPTIONS_TIFF_H
+#define KIS_DLG_OPTIONS_TIFF_H
+
+#include <kdialogbase.h>
+#include <kis_tiff_converter.h>
+
+class KisWdgOptionsTIFF;
+/**
+ @author Cyrille Berger <cberger@cberger.net>
+*/
+class KisDlgOptionsTIFF : public KDialogBase
+{
+ Q_OBJECT
+ TQ_OBJECT
+ public:
+ KisDlgOptionsTIFF(TQWidget *tqparent=0, const char *name=0);
+ ~KisDlgOptionsTIFF();
+ public slots:
+ void activated ( int index );
+ void flattenToggled(bool);
+ KisTIFFOptions options();
+ public:
+ KisWdgOptionsTIFF* optionswdg;
+};
+
+#endif
diff --git a/filters/chalk/tiff/kis_tiff_converter.cc b/filters/chalk/tiff/kis_tiff_converter.cc
new file mode 100644
index 00000000..09a0ba99
--- /dev/null
+++ b/filters/chalk/tiff/kis_tiff_converter.cc
@@ -0,0 +1,677 @@
+/*
+ * Copyright (c) 2005-2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_tiff_converter.h"
+
+#include <stdio.h>
+
+#include <config.h>
+#include LCMS_HEADER
+
+#include <tqfile.h>
+
+#include <kapplication.h>
+#include <KoDocumentInfo.h>
+
+#include <kio/netaccess.h>
+
+#include <kis_abstract_colorspace.h>
+#include <kis_colorspace_factory_registry.h>
+#include <kis_doc.h>
+#include <kis_image.h>
+#include <kis_iterators_pixel.h>
+#include <kis_layer.h>
+#include <kis_meta_registry.h>
+#include <kis_profile.h>
+#include <kis_group_layer.h>
+#include <kis_paint_layer.h>
+
+#include "kis_tiff_reader.h"
+#include "kis_tiff_ycbcr_reader.h"
+#include "kis_tiff_stream.h"
+#include "kis_tiff_writer_visitor.h"
+
+namespace {
+
+ TQString getColorSpaceForColorType(uint16 color_type, uint16 color_nb_bits, TIFF *image, uint16 &nbchannels, uint16 &extrasamplescount, uint8 &destDepth, uint16 sampletype) {
+ if(color_type == PHOTOMETRIC_MINISWHITE || color_type == PHOTOMETRIC_MINISBLACK)
+ {
+ if(nbchannels == 0) nbchannels = 1;
+ extrasamplescount = nbchannels - 1; // FIX the extrasamples count in case of
+ if(color_nb_bits <= 8)
+ {
+ destDepth = 8;
+ return "GRAYA";
+ } else {
+ destDepth = 16;
+ return "GRAYA16";
+ }
+ } else if(color_type == PHOTOMETRIC_RGB /*|| color_type == */ ) {
+ if(nbchannels == 0) nbchannels = 3;
+ extrasamplescount = nbchannels - 3; // FIX the extrasamples count in case of
+ if(sampletype == SAMPLEFORMAT_IEEEFP)
+ {
+ if(color_nb_bits == 16)
+ {
+ destDepth = 16;
+ return "RGBAF16HALF";
+ } else if( color_nb_bits == 32) {
+ destDepth = 32;
+ return "RGBAF32";
+ }
+ return "";
+ } else {
+ if(color_nb_bits <= 8)
+ {
+ destDepth = 8;
+ return "RGBA";
+ } else {
+ destDepth = 16;
+ return "RGBA16";
+ }
+ }
+ } else if(color_type == PHOTOMETRIC_YCBCR ) {
+ if(nbchannels == 0) nbchannels = 3;
+ extrasamplescount = nbchannels - 3; // FIX the extrasamples count in case of
+ if(color_nb_bits <= 8)
+ {
+ destDepth = 8;
+ return "YCbCrAU8";
+ } else {
+ destDepth = 16;
+ return "YCbCrAU16";
+ }
+ } else if(color_type == PHOTOMETRIC_SEPARATED ) {
+ if(nbchannels == 0) nbchannels = 4;
+ // SEPARATED is in general CMYK but not allways, so we check
+ uint16 inkset;
+ if((TIFFGetField(image, TIFFTAG_INKSET, &inkset) == 0)){
+ kdDebug(41008) << "Image does not define the inkset." << endl;
+ inkset = 2;
+ }
+ if(inkset != INKSET_CMYK)
+ {
+ kdDebug(41008) << "Unsupported inkset (right now, only CMYK is supported)" << endl;
+ char** ink_names;
+ uint16 numberofinks;
+ if( TIFFGetField(image, TIFFTAG_INKNAMES, &ink_names) && TIFFGetField(image, TIFFTAG_NUMBEROFINKS, &numberofinks) )
+ {
+ kdDebug(41008) << "Inks are : " << endl;
+ for(uint i = 0; i < numberofinks; i++)
+ {
+ kdDebug(41008) << ink_names[i] << endl;
+ }
+ } else {
+ kdDebug(41008) << "inknames aren't defined !" << endl;
+ // To be able to read stupid adobe files, if there are no information about inks and four channels, then it's a CMYK file :
+ if( nbchannels - extrasamplescount != 4)
+ {
+ return "";
+ }
+ }
+ }
+ if(color_nb_bits <= 8)
+ {
+ destDepth = 8;
+ return "CMYK";
+ } else {
+ destDepth = 16;
+ return "CMYKA16";
+ }
+ } else if(color_type == PHOTOMETRIC_CIELAB
+#ifdef PHOTOMETRIC_ICCLAB
+ || color_type == PHOTOMETRIC_ICCLAB
+#endif
+ ) {
+ destDepth = 16;
+ if(nbchannels == 0) nbchannels = 3;
+ extrasamplescount = nbchannels - 3; // FIX the extrasamples count in case of
+ return "LABA"; // TODO add support for a 8bit LAB colorspace when it is written
+ } else if(color_type == PHOTOMETRIC_PALETTE) {
+ destDepth = 16;
+ if(nbchannels == 0) nbchannels = 2;
+ extrasamplescount = nbchannels - 2; // FIX the extrasamples count in case of
+ // <-- we will convert the index image to RGBA16 as the palette is allways on 16bits colors
+ return "RGBA16";
+ }
+ return "";
+ }
+}
+
+KisTIFFConverter::KisTIFFConverter(KisDoc *doc, KisUndoAdapter *adapter)
+{
+ m_doc = doc;
+ m_adapter = adapter;
+ m_job = 0;
+ m_stop = false;
+}
+
+KisTIFFConverter::~KisTIFFConverter()
+{
+}
+
+KisImageBuilder_Result KisTIFFConverter::decode(const KURL& uri)
+{
+ kdDebug(41008) << "Start decoding TIFF File" << endl;
+ // Opent the TIFF file
+ TIFF *image = 0;
+ if((image = TIFFOpen(TQFile::encodeName(uri.path()), "r")) == NULL){
+ kdDebug(41008) << "Could not open the file, either it doesn't exist, either it is not a TIFF : " << uri.path() << endl;
+
+ return (KisImageBuilder_RESULT_BAD_FETCH);
+ }
+ do {
+ kdDebug(41008) << "Read new sub-image" << endl;
+ KisImageBuilder_Result result = readTIFFDirectory(image);
+ if(result != KisImageBuilder_RESULT_OK){
+ return result;
+ }
+ } while (TIFFReadDirectory(image));
+ // Freeing memory
+ TIFFClose(image);
+ return KisImageBuilder_RESULT_OK;
+}
+
+KisImageBuilder_Result KisTIFFConverter::readTIFFDirectory( TIFF* image)
+{
+ // Read information about the tiff
+ uint32 width, height;
+ if(TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &width) == 0){
+ kdDebug(41008) << "Image does not define its width" << endl;
+ TIFFClose(image);
+ return KisImageBuilder_RESULT_INVALID_ARG;
+ }
+ if(TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height) == 0){
+ kdDebug(41008) << "Image does not define its height" << endl;
+ TIFFClose(image);
+ return KisImageBuilder_RESULT_INVALID_ARG;
+ }
+ uint16 depth;
+ if((TIFFGetField(image, TIFFTAG_BITSPERSAMPLE, &depth) == 0)){
+ kdDebug(41008) << "Image does not define its depth" << endl;
+ depth = 1;
+ }
+ uint16 sampletype;
+ if((TIFFGetField(image, TIFFTAG_SAMPLEFORMAT, &sampletype) == 0)){
+ kdDebug(41008) << "Image does not define its sample type" << endl;
+ sampletype = SAMPLEFORMAT_UINT;
+ }
+ // Determine the number of channels (usefull to know if a file has an alpha or not
+ uint16 nbchannels;
+ if(TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &nbchannels) == 0){
+ kdDebug(41008) << "Image has an undefined number of samples per pixel" << endl;
+ nbchannels = 0;
+ }
+ // Get the number of extrasamples and information about them
+ uint16 *sampleinfo, extrasamplescount;
+ if(TIFFGetField(image, TIFFTAG_EXTRASAMPLES, &extrasamplescount, &sampleinfo) == 0)
+ {
+ extrasamplescount = 0;
+ }
+ // Determine the colorspace
+ uint16 color_type;
+ if(TIFFGetField(image, TIFFTAG_PHOTOMETRIC, &color_type) == 0){
+ kdDebug(41008) << "Image has an undefined photometric interpretation" << endl;
+ color_type = PHOTOMETRIC_MINISWHITE;
+ }
+ uint8 dstDepth;
+ TQString csName = getColorSpaceForColorType(color_type, depth, image, nbchannels, extrasamplescount, dstDepth,sampletype);
+ if(csName.isEmpty()) {
+ kdDebug(41008) << "Image has an unsupported colorspace : " << color_type << " for this depth : "<< depth << endl;
+ TIFFClose(image);
+ return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
+ }
+ kdDebug(41008) << "Colorspace is : " << csName << " with a depth of " << depth << " and with a nb of channels of " << nbchannels << endl;
+
+ // Read image profile
+ kdDebug() << "Reading profile" << endl;
+ KisProfile* profile = 0;
+ DWORD EmbedLen;
+ LPBYTE EmbedBuffer;
+
+ if (TIFFGetField(image, TIFFTAG_ICCPROFILE, &EmbedLen, &EmbedBuffer)) {
+ kdDebug(41008) << "Profile found" << endl;
+ TQByteArray rawdata;
+ rawdata.resize(EmbedLen);
+ memcpy(rawdata.data(), EmbedBuffer, EmbedLen);
+ profile = new KisProfile(rawdata);
+ } else {
+ kdDebug(41008) << "No Profile found" << endl;
+ }
+
+ // Retrieve a pointer to the colorspace
+ KisColorSpace* cs = 0;
+ if (profile && profile->isSuitableForOutput())
+ {
+ kdDebug(41008) << "image has embedded profile: " << profile -> productName() << "\n";
+ cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(csName, profile);
+ }
+ else
+ cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName,""),"");
+
+ if(cs == 0) {
+ kdDebug(41008) << "Colorspace " << csName << " is not available, please check your installation." << endl;
+ TIFFClose(image);
+ return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
+ }
+
+ // Create the cmsTransform if needed
+ cmsHTRANSFORM transform = 0;
+ if(profile && !profile->isSuitableForOutput())
+ {
+ kdDebug(41008) << "The profile can't be used in chalk, need conversion" << endl;
+ transform = cmsCreateTransform(profile->profile(), cs->colorSpaceType(),
+ cs->getProfile()->profile() , cs->colorSpaceType(),
+ INTENT_PERCEPTUAL, 0);
+ }
+
+
+ // Check if there is an alpha channel
+ int8 alphapos = -1; // <- no alpha
+ // Check which extra is alpha if any
+ kdDebug(41008) << "There are " << nbchannels << " channels and " << extrasamplescount << " extra channels" << endl;
+ if(sampleinfo) // index images don't have any sampleinfo, and therefor sampleinfo == 0
+ {
+ for(int i = 0; i < extrasamplescount; i ++)
+ {
+ kdDebug(41008) << i << " " << extrasamplescount << " " << (cs->nColorChannels()) << nbchannels << " " << sampleinfo[i] << endl;
+ if(sampleinfo[i] == EXTRASAMPLE_ASSOCALPHA)
+ {
+ // XXX: dangelo: the color values are already multiplied with
+ // the alpha value. This needs to be reversed later (postprocessor?)
+ alphapos = i;
+ }
+
+ if (sampleinfo[i] == EXTRASAMPLE_UNASSALPHA)
+ {
+ // color values are not premultiplied with alpha, and can be used as they are.
+ alphapos = i;
+ }
+ }
+ }
+
+ // Read META Information
+ KoDocumentInfo * info = m_doc->documentInfo();
+ KoDocumentInfoAbout * aboutPage = static_cast<KoDocumentInfoAbout *>(info->page( "about" ));
+ KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor *>(info->page( "author"));
+ char* text;
+ if (TIFFGetField(image, TIFFTAG_ARTIST, &text)) {
+ authorPage->setFullName(text);
+ }
+ if (TIFFGetField(image, TIFFTAG_DOCUMENTNAME, &text)) {
+ aboutPage->setTitle(text);
+ }
+ if (TIFFGetField(image,TIFFTAG_IMAGEDESCRIPTION,&text) ) {
+ aboutPage->setAbstract( text );
+ }
+
+
+ // Get the planar configuration
+ uint16 planarconfig;
+ if(TIFFGetField(image, TIFFTAG_PLANARCONFIG, &planarconfig) == 0)
+ {
+ kdDebug(41008) << "Plannar configuration is not define" << endl;
+ TIFFClose(image);
+ return KisImageBuilder_RESULT_INVALID_ARG;
+ }
+ // Creating the KisImageSP
+ if( ! m_img ) {
+ m_img = new KisImage(m_doc->undoAdapter(), width, height, cs, "built image");
+ Q_CHECK_PTR(m_img);
+ m_img->blockSignals(true); // Don't send out signals while we're building the image
+ if(profile)
+ {
+ m_img -> addAnnotation( profile->annotation() );
+ }
+ } else {
+ if( m_img->width() < (TQ_INT32)width || m_img->height() < (TQ_INT32)height)
+ {
+ TQ_UINT32 newwidth = (m_img->width() < (TQ_INT32)width) ? width : m_img->width();
+ TQ_UINT32 newheight = (m_img->height() < (TQ_INT32)height) ? height : m_img->height();
+ m_img->resize(newwidth, newheight, false);
+ }
+ }
+ KisPaintLayer* layer = new KisPaintLayer(m_img, m_img -> nextLayerName(), TQ_UINT8_MAX);
+ tdata_t buf = 0;
+ tdata_t* ps_buf = 0; // used only for planar configuration seperated
+ TIFFStreamBase* tiffstream;
+
+ KisTIFFReaderBase* tiffReader = 0;
+
+ TQ_UINT8 poses[5];
+ KisTIFFPostProcessor* postprocessor = 0;
+
+ // Configure poses
+ uint8 nbcolorsamples = nbchannels - extrasamplescount;
+ switch(color_type)
+ {
+ case PHOTOMETRIC_MINISWHITE:
+ {
+ poses[0] = 0; poses[1] = 1;
+ postprocessor = new KisTIFFPostProcessorInvert(nbcolorsamples);
+ }
+ break;
+ case PHOTOMETRIC_MINISBLACK:
+ {
+ poses[0] = 0; poses[1] = 1;
+ postprocessor = new KisTIFFPostProcessor(nbcolorsamples);
+ }
+ break;
+ case PHOTOMETRIC_CIELAB:
+ {
+ poses[0] = 0; poses[1] = 1; poses[2] = 2; poses[3] = 3;
+ postprocessor = new KisTIFFPostProcessorICCLABtoCIELAB(nbcolorsamples);
+ }
+ break;
+#ifdef PHOTOMETRIC_ICCLAB
+ case PHOTOMETRIC_ICCLAB:
+ {
+ poses[0] = 0; poses[1] = 1; poses[2] = 2; poses[3] = 3;
+ postprocessor = new KisTIFFPostProcessor(nbcolorsamples);
+ }
+ break;
+#endif
+ case PHOTOMETRIC_RGB:
+ {
+ poses[0] = 2; poses[1] = 1; poses[2] = 0; poses[3] = 3;
+ postprocessor = new KisTIFFPostProcessor(nbcolorsamples);
+ }
+ break;
+ case PHOTOMETRIC_SEPARATED:
+ {
+ poses[0] = 0; poses[1] = 1; poses[2] = 2; poses[3] = 3; poses[4] = 4;
+ postprocessor = new KisTIFFPostProcessor(nbcolorsamples);
+ }
+ break;
+ default:
+ break;
+ }
+
+
+ // Initisalize tiffReader
+ uint16 * lineSizeCoeffs = new uint16[nbchannels];
+ uint16 vsubsampling = 1;
+ uint16 hsubsampling = 1;
+ for(uint i = 0; i < nbchannels; i++)
+ {
+ lineSizeCoeffs[i] = 1;
+ }
+ if( color_type == PHOTOMETRIC_PALETTE)
+ {
+ uint16 *red; // No need to free them they are free by libtiff
+ uint16 *green;
+ uint16 *blue;
+ if ((TIFFGetField(image, TIFFTAG_COLORMAP, &red, &green, &blue)) == 0)
+ {
+ kdDebug(41008) << "Indexed image does not define a palette" << endl;
+ TIFFClose(image);
+ return KisImageBuilder_RESULT_INVALID_ARG;
+ }
+
+ tiffReader = new KisTIFFReaderFromPalette( layer->paintDevice(), red, green, blue, poses, alphapos, depth, nbcolorsamples, extrasamplescount, transform, postprocessor);
+ } else if(color_type == PHOTOMETRIC_YCBCR ) {
+ TIFFGetFieldDefaulted( image, TIFFTAG_YCBCRSUBSAMPLING, &hsubsampling, &vsubsampling );
+ lineSizeCoeffs[1] = hsubsampling;
+ lineSizeCoeffs[2] = hsubsampling;
+ uint16 position;
+ TIFFGetFieldDefaulted( image, TIFFTAG_YCBCRPOSITIONING, &position );
+ if( dstDepth == 8 )
+ {
+ tiffReader = new KisTIFFYCbCrReaderTarget8Bit(layer->paintDevice(), poses, alphapos, depth, nbcolorsamples, extrasamplescount, transform, postprocessor, hsubsampling, vsubsampling, (KisTIFFYCbCr::Position)position);
+ } else if( dstDepth == 16 )
+ {
+ tiffReader = new KisTIFFYCbCrReaderTarget16Bit( layer->paintDevice(), poses, alphapos, depth, nbcolorsamples, extrasamplescount, transform, postprocessor, hsubsampling, vsubsampling, (KisTIFFYCbCr::Position)position);
+ }
+ } else if(dstDepth == 8)
+ {
+ tiffReader = new KisTIFFReaderTarget8bit( layer->paintDevice(), poses, alphapos, depth, nbcolorsamples, extrasamplescount, transform, postprocessor);
+ } else if(dstDepth == 16) {
+ tiffReader = new KisTIFFReaderTarget16bit( layer->paintDevice(), poses, alphapos, depth, nbcolorsamples, extrasamplescount, transform, postprocessor);
+ } else if(dstDepth == 32) {
+ tiffReader = new KisTIFFReaderTarget32bit( layer->paintDevice(), poses, alphapos, depth, nbcolorsamples, extrasamplescount, transform, postprocessor);
+ }
+
+ if(TIFFIsTiled(image))
+ {
+ kdDebug(41008) << "tiled image" << endl;
+ uint32 tileWidth, tileHeight;
+ uint32 x, y;
+ TIFFGetField(image, TIFFTAG_TILEWIDTH, &tileWidth);
+ TIFFGetField(image, TIFFTAG_TILELENGTH, &tileHeight);
+ uint32 linewidth = (tileWidth * depth * nbchannels) / 8;
+ if(planarconfig == PLANARCONFIG_CONTIG)
+ {
+ buf = _TIFFmalloc(TIFFTileSize(image));
+ if(depth < 16)
+ {
+ tiffstream = new TIFFStreamContigBelow16((uint8*)buf, depth, linewidth);
+ } else if(depth < 32)
+ {
+ tiffstream = new TIFFStreamContigBelow32((uint8*)buf, depth, linewidth);
+ } else {
+ tiffstream = new TIFFStreamContigAbove32((uint8*)buf, depth, linewidth);
+ }
+ } else {
+ ps_buf = new tdata_t[nbchannels];
+ uint32 * lineSizes = new uint32[nbchannels];
+ uint16 baseSize = TIFFTileSize(image)/nbchannels;
+ for(uint i = 0; i < nbchannels; i++)
+ {
+ ps_buf[i] = _TIFFmalloc(baseSize);
+ lineSizes[i] = baseSize / lineSizeCoeffs[i];
+ }
+ tiffstream = new TIFFStreamSeperate( (uint8**) ps_buf, nbchannels, depth, lineSizes);
+ delete [] lineSizes;
+ }
+ kdDebug(41008) << linewidth << " " << nbchannels << " " << layer->paintDevice()->colorSpace()->nColorChannels() << endl;
+ for (y = 0; y < height; y+= tileHeight)
+ {
+ for (x = 0; x < width; x += tileWidth)
+ {
+ kdDebug(41008) << "Reading tile x = " << x << " y = " << y << endl;
+ if( planarconfig == PLANARCONFIG_CONTIG )
+ {
+ TIFFReadTile(image, buf, x, y, 0, (tsample_t) -1);
+ } else {
+ for(uint i = 0; i < nbchannels; i++)
+ {
+ TIFFReadTile(image, ps_buf[i], x, y, 0, i);
+ }
+ }
+ uint32 realTileWidth = (x + tileWidth) < width ? tileWidth : width - x;
+ for (uint yintile = 0; y + yintile < height && yintile < tileHeight/vsubsampling; ) {
+ tiffReader->copyDataToChannels( x, y + yintile , realTileWidth, tiffstream);
+ yintile += 1;
+ tiffstream->moveToLine( yintile );
+ }
+ tiffstream->restart();
+ }
+ }
+ } else {
+ kdDebug(41008) << "striped image" << endl;
+ tsize_t stripsize = TIFFStripSize(image);
+ uint32 rowsPerStrip;
+ TIFFGetFieldDefaulted(image, TIFFTAG_ROWSPERSTRIP, &rowsPerStrip);
+ kdDebug() << rowsPerStrip << " " << height << endl;
+ rowsPerStrip = TQMIN(rowsPerStrip, height); // when TIFFNumberOfStrips(image) == 1 it might happen that rowsPerStrip is incorrectly set
+ if(planarconfig == PLANARCONFIG_CONTIG)
+ {
+ buf = _TIFFmalloc(stripsize);
+ if(depth < 16)
+ {
+ tiffstream = new TIFFStreamContigBelow16((uint8*)buf, depth, stripsize/rowsPerStrip);
+ } else if(depth < 32)
+ {
+ tiffstream = new TIFFStreamContigBelow32((uint8*)buf, depth, stripsize/rowsPerStrip);
+ } else {
+ tiffstream = new TIFFStreamContigAbove32((uint8*)buf, depth, stripsize/rowsPerStrip);
+ }
+ } else {
+ ps_buf = new tdata_t[nbchannels];
+ uint32 scanLineSize = stripsize/rowsPerStrip;
+ kdDebug(41008) << " scanLineSize for each plan = " << scanLineSize << endl;
+ uint32 * lineSizes = new uint32[nbchannels];
+ for(uint i = 0; i < nbchannels; i++)
+ {
+ ps_buf[i] = _TIFFmalloc(stripsize);
+ lineSizes[i] = scanLineSize / lineSizeCoeffs[i];
+ }
+ tiffstream = new TIFFStreamSeperate( (uint8**) ps_buf, nbchannels, depth, lineSizes);
+ delete [] lineSizes;
+ }
+
+ kdDebug(41008) << "Scanline size = " << TIFFRasterScanlineSize(image) << " / strip size = " << TIFFStripSize(image) << " / rowsPerStrip = " << rowsPerStrip << " stripsize/rowsPerStrip = " << stripsize/rowsPerStrip << endl;
+ uint32 y = 0;
+ kdDebug(41008) << " NbOfStrips = " << TIFFNumberOfStrips(image) << " rowsPerStrip = " << rowsPerStrip << " stripsize = " << stripsize << endl;
+ for (uint32 strip = 0; y < height; strip++)
+ {
+ if( planarconfig == PLANARCONFIG_CONTIG )
+ {
+ TIFFReadEncodedStrip(image, TIFFComputeStrip( image, y, 0 ) , buf, (tsize_t) -1);
+ } else {
+ for(uint i = 0; i < nbchannels; i++)
+ {
+ TIFFReadEncodedStrip(image, TIFFComputeStrip( image, y, i ), ps_buf[i], (tsize_t) -1);
+ }
+ }
+ for( uint32 yinstrip = 0 ; yinstrip < rowsPerStrip && y < height ; )
+ {
+ uint linesread = tiffReader->copyDataToChannels( 0, y, width, tiffstream);
+ y += linesread;
+ yinstrip += linesread;
+ tiffstream->moveToLine( yinstrip );
+ }
+ tiffstream->restart();
+ }
+ }
+ tiffReader->finalize();
+ delete lineSizeCoeffs;
+ delete tiffReader;
+ delete tiffstream;
+ if( planarconfig == PLANARCONFIG_CONTIG )
+ {
+ _TIFFfree(buf);
+ } else {
+ for(uint i = 0; i < nbchannels; i++)
+ {
+ _TIFFfree(ps_buf[i]);
+ }
+ delete[] ps_buf;
+ }
+
+ m_img->addLayer(layer, m_img->rootLayer(), 0);
+ return KisImageBuilder_RESULT_OK;
+}
+
+KisImageBuilder_Result KisTIFFConverter::buildImage(const KURL& uri)
+{
+ if (uri.isEmpty())
+ return KisImageBuilder_RESULT_NO_URI;
+
+ if (!KIO::NetAccess::exists(uri, false, tqApp -> mainWidget())) {
+ return KisImageBuilder_RESULT_NOT_EXIST;
+ }
+
+ // We're not set up to handle asynchronous loading at the moment.
+ KisImageBuilder_Result result = KisImageBuilder_RESULT_FAILURE;
+ TQString tmpFile;
+
+ if (KIO::NetAccess::download(uri, tmpFile, tqApp -> mainWidget())) {
+ KURL uriTF;
+ uriTF.setPath( tmpFile );
+ result = decode(uriTF);
+ KIO::NetAccess::removeTempFile(tmpFile);
+ }
+
+ return result;
+}
+
+
+KisImageSP KisTIFFConverter::image()
+{
+ return m_img;
+}
+
+
+KisImageBuilder_Result KisTIFFConverter::buildFile(const KURL& uri, KisImageSP img, KisTIFFOptions options)
+{
+ kdDebug(41008) << "Start writing TIFF File" << endl;
+ if (!img)
+ return KisImageBuilder_RESULT_EMPTY;
+
+ if (uri.isEmpty())
+ return KisImageBuilder_RESULT_NO_URI;
+
+ if (!uri.isLocalFile())
+ return KisImageBuilder_RESULT_NOT_LOCAL;
+
+ // Open file for writing
+ TIFF *image;
+ if((image = TIFFOpen(TQFile::encodeName(uri.path()), "w")) == NULL){
+ kdDebug(41008) << "Could not open the file for writting " << uri.path() << endl;
+ TIFFClose(image);
+ return (KisImageBuilder_RESULT_FAILURE);
+ }
+
+ // Set the document informations
+ KoDocumentInfo * info = m_doc->documentInfo();
+ KoDocumentInfoAbout * aboutPage = static_cast<KoDocumentInfoAbout *>(info->page( "about" ));
+ TQString title = aboutPage->title();
+ if(!title.isEmpty())
+ {
+ TIFFSetField(image, TIFFTAG_DOCUMENTNAME, title.ascii());
+ }
+ TQString abstract = aboutPage->abstract();
+ if(!abstract.isEmpty())
+ {
+ TIFFSetField(image, TIFFTAG_IMAGEDESCRIPTION, abstract.ascii());
+ }
+ KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor *>(info->page( "author" ));
+ TQString author = authorPage->fullName();
+ if(!author.isEmpty())
+ {
+ TIFFSetField(image, TIFFTAG_ARTIST, author.ascii());
+ }
+
+ KisTIFFWriterVisitor* visitor = new KisTIFFWriterVisitor(image, &options);
+ KisGroupLayer* root = dynamic_cast<KisGroupLayer*>(img->rootLayer().data());
+ if(root == 0)
+ {
+ KIO::del(uri);
+ TIFFClose(image);
+ return KisImageBuilder_RESULT_FAILURE;
+ }
+ if(!visitor->visit( root ))
+ {
+ KIO::del(uri);
+ TIFFClose(image);
+ return KisImageBuilder_RESULT_FAILURE;
+ }
+
+ TIFFClose(image);
+ return KisImageBuilder_RESULT_OK;
+}
+
+
+void KisTIFFConverter::cancel()
+{
+ m_stop = true;
+}
+
+#include "kis_tiff_converter.moc"
diff --git a/filters/chalk/tiff/kis_tiff_converter.h b/filters/chalk/tiff/kis_tiff_converter.h
new file mode 100644
index 00000000..7d7176b7
--- /dev/null
+++ b/filters/chalk/tiff/kis_tiff_converter.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2005-2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _KIS_TIFF_CONVERTER_H_
+#define _KIS_TIFF_CONVERTER_H_
+
+#include <stdio.h>
+#include <tiffio.h>
+
+#include <tqvaluevector.h>
+
+#include <kio/job.h>
+
+#include <kis_progress_subject.h>
+
+#include "kis_types.h"
+#include "kis_global.h"
+#include "kis_annotation.h"
+class KisDoc;
+class KisUndoAdapter;
+
+/**
+ * Image import/export plugins can use these results to report about success or failure.
+ */
+enum KisImageBuilder_Result {
+ KisImageBuilder_RESULT_FAILURE = -400,
+ KisImageBuilder_RESULT_NOT_EXIST = -300,
+ KisImageBuilder_RESULT_NOT_LOCAL = -200,
+ KisImageBuilder_RESULT_BAD_FETCH = -100,
+ KisImageBuilder_RESULT_INVALID_ARG = -50,
+ KisImageBuilder_RESULT_OK = 0,
+ KisImageBuilder_RESULT_PROGRESS = 1,
+ KisImageBuilder_RESULT_EMPTY = 100,
+ KisImageBuilder_RESULT_BUSY = 150,
+ KisImageBuilder_RESULT_NO_URI = 200,
+ KisImageBuilder_RESULT_UNSUPPORTED = 300,
+ KisImageBuilder_RESULT_INTR = 400,
+ KisImageBuilder_RESULT_PATH = 500,
+ KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE = 600
+};
+
+struct KisTIFFOptions {
+ TQ_UINT16 compressionType;
+ TQ_UINT16 predictor;
+ bool alpha;
+ bool flatten;
+ TQ_UINT16 jpegQuality;
+ TQ_UINT16 deflateCompress;
+ TQ_UINT16 faxMode;
+ TQ_UINT16 pixarLogCompress;
+};
+
+class KisTIFFConverter : public KisProgressSubject {
+ Q_OBJECT
+ TQ_OBJECT
+ public:
+ KisTIFFConverter(KisDoc *doc, KisUndoAdapter *adapter);
+ virtual ~KisTIFFConverter();
+ public:
+ KisImageBuilder_Result buildImage(const KURL& uri);
+ KisImageBuilder_Result buildFile(const KURL& uri, KisImageSP layer, KisTIFFOptions);
+ /** Retrieve the constructed image
+ */
+ KisImageSP image();
+ public slots:
+ virtual void cancel();
+ private:
+ KisImageBuilder_Result decode(const KURL& uri);
+ KisImageBuilder_Result readTIFFDirectory( TIFF* image);
+ private:
+ KisImageSP m_img;
+ KisDoc *m_doc;
+ KisUndoAdapter *m_adapter;
+ bool m_stop;
+ KIO::TransferJob *m_job;
+};
+
+#endif
diff --git a/filters/chalk/tiff/kis_tiff_export.cc b/filters/chalk/tiff/kis_tiff_export.cc
new file mode 100644
index 00000000..bcd3f22e
--- /dev/null
+++ b/filters/chalk/tiff/kis_tiff_export.cc
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_tiff_export.h"
+
+#include <tqcheckbox.h>
+#include <tqslider.h>
+
+#include <kapplication.h>
+#include <kcombobox.h>
+#include <kdialogbase.h>
+#include <kgenericfactory.h>
+
+#include <KoFilterChain.h>
+
+#include <kis_doc.h>
+#include <kis_group_layer.h>
+#include <kis_image.h>
+#include <kis_paint_layer.h>
+#include <kis_progress_display_interface.h>
+
+#include "kis_tiff_converter.h"
+#include "kis_dlg_options_tiff.h"
+#include "kis_wdg_options_tiff.h"
+
+typedef KGenericFactory<KisTIFFExport, KoFilter> KisTIFFExportFactory;
+K_EXPORT_COMPONENT_FACTORY(libchalktiffexport, KisTIFFExportFactory("kofficefilters"))
+
+KisTIFFExport::KisTIFFExport(KoFilter *, const char *, const TQStringList&) : KoFilter()
+{
+}
+
+KisTIFFExport::~KisTIFFExport()
+{
+}
+
+KoFilter::ConversiontqStatus KisTIFFExport::convert(const TQCString& from, const TQCString& to)
+{
+ kdDebug(41008) << "Tiff export! From: " << from << ", To: " << to << "\n";
+
+ if (from != "application/x-chalk")
+ return KoFilter::NotImplemented;
+
+
+ KisDlgOptionsTIFF* kdb = new KisDlgOptionsTIFF(0, "options dialog for tiff");
+
+ KisDoc *output = dynamic_cast<KisDoc*>(m_chain->inputDocument());
+
+ KisColorSpace* cs = output->currentImage()->colorSpace();
+ KisChannelInfo::enumChannelValueType type = cs->channels()[0]->channelValueType();
+ if( type == KisChannelInfo::FLOAT16 || type == KisChannelInfo::FLOAT32)
+ {
+ kdb->optionswdg->kComboBoxPredictor->removeItem(1);
+ } else {
+ kdb->optionswdg->kComboBoxPredictor->removeItem(2);
+ }
+
+ if(kdb->exec() == TQDialog::Rejected)
+ {
+ return KoFilter::OK; // FIXME Cancel doesn't exist :(
+ }
+
+ KisTIFFOptions options = kdb->options();
+
+ if( ( type == KisChannelInfo::FLOAT16 || type == KisChannelInfo::FLOAT32) && options.predictor == 2 )
+ { // FIXME THIS IS AN HACK FIX THAT IN 2.0 !!
+ options.predictor = 3;
+ }
+ delete kdb;
+
+ TQString filename = m_chain->outputFile();
+
+ if (!output)
+ return KoFilter::CreationError;
+
+ if (filename.isEmpty()) return KoFilter::FileNotFound;
+
+ KURL url;
+ url.setPath(filename);
+
+ KisImageSP img;
+
+ if(options.flatten)
+ {
+ img = new KisImage(0, output->currentImage()->width(), output->currentImage()->height(), output->currentImage()->colorSpace(), "");
+ KisPaintDeviceSP pd = new KisPaintDevice(*output->currentImage()->projection());
+ KisPaintLayerSP l = new KisPaintLayer(img, "projection", OPACITY_OPAQUE, pd);
+ img->addLayer(l.data(), img->rootLayer(), 0);
+ } else {
+ img = output->currentImage();
+ }
+
+
+ KisTIFFConverter ktc(output, output->undoAdapter());
+/* vKisAnnotationSP_it beginIt = img->beginAnnotations();
+ vKisAnnotationSP_it endIt = img->endAnnotations();*/
+ KisImageBuilder_Result res;
+ if ( (res = ktc.buildFile(url, img, options)) == KisImageBuilder_RESULT_OK) {
+ kdDebug(41008) << "success !" << endl;
+ return KoFilter::OK;
+ }
+ kdDebug(41008) << " Result = " << res << endl;
+ return KoFilter::InternalError;
+}
+
+#include <kis_tiff_export.moc>
+
diff --git a/filters/chalk/tiff/kis_tiff_export.h b/filters/chalk/tiff/kis_tiff_export.h
new file mode 100644
index 00000000..113747c7
--- /dev/null
+++ b/filters/chalk/tiff/kis_tiff_export.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _KIS_TIFF_EXPORT_H_
+#define _KIS_TIFF_EXPORT_H_
+
+#include <KoFilter.h>
+
+class KisTIFFExport : public KoFilter {
+ Q_OBJECT
+ TQ_OBJECT
+ public:
+ KisTIFFExport(KoFilter *tqparent, const char *name, const TQStringList&);
+ virtual ~KisTIFFExport();
+ public:
+ virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to);
+};
+
+#endif
diff --git a/filters/chalk/tiff/kis_tiff_import.cc b/filters/chalk/tiff/kis_tiff_import.cc
new file mode 100644
index 00000000..89d1763f
--- /dev/null
+++ b/filters/chalk/tiff/kis_tiff_import.cc
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_tiff_import.h"
+
+#include <kgenericfactory.h>
+
+#include <KoFilterChain.h>
+
+#include <kis_doc.h>
+#include <kis_image.h>
+#include <kis_progress_display_interface.h>
+#include <kis_view.h>
+
+#include "kis_tiff_converter.h"
+
+typedef KGenericFactory<KisTIFFImport, KoFilter> TIFFImportFactory;
+K_EXPORT_COMPONENT_FACTORY(libchalktiffimport, TIFFImportFactory("kofficefilters"))
+
+KisTIFFImport::KisTIFFImport(KoFilter *, const char *, const TQStringList&) : KoFilter()
+{
+}
+
+KisTIFFImport::~KisTIFFImport()
+{
+}
+
+KoFilter::ConversiontqStatus KisTIFFImport::convert(const TQCString&, const TQCString& to)
+{
+ kdDebug(41008) << "Importing using TIFFImport!\n";
+
+ if (to != "application/x-chalk")
+ return KoFilter::BadMimeType;
+
+ KisDoc * doc = dynamic_cast<KisDoc*>(m_chain -> outputDocument());
+ KisView * view = static_cast<KisView*>(doc -> views().getFirst());
+
+ TQString filename = m_chain -> inputFile();
+
+ if (!doc)
+ return KoFilter::CreationError;
+
+ doc -> prepareForImport();
+
+
+ if (!filename.isEmpty()) {
+
+ KURL url;
+ url.setPath(filename);
+
+ if (url.isEmpty())
+ return KoFilter::FileNotFound;
+
+ KisTIFFConverter ib(doc, doc -> undoAdapter());
+
+ if (view != 0)
+ view -> canvasSubject() -> progressDisplay() -> setSubject(&ib, false, true);
+
+ switch (ib.buildImage(url)) {
+ case KisImageBuilder_RESULT_UNSUPPORTED:
+ return KoFilter::NotImplemented;
+ break;
+ case KisImageBuilder_RESULT_INVALID_ARG:
+ return KoFilter::BadMimeType;
+ break;
+ case KisImageBuilder_RESULT_NO_URI:
+ case KisImageBuilder_RESULT_NOT_LOCAL:
+ return KoFilter::FileNotFound;
+ break;
+ case KisImageBuilder_RESULT_BAD_FETCH:
+ case KisImageBuilder_RESULT_EMPTY:
+ return KoFilter::ParsingError;
+ break;
+ case KisImageBuilder_RESULT_FAILURE:
+ return KoFilter::InternalError;
+ break;
+ case KisImageBuilder_RESULT_OK:
+ doc -> setCurrentImage( ib.image());
+ return KoFilter::OK;
+ default:
+ break;
+ }
+
+ }
+ return KoFilter::StorageCreationError;
+}
+
+#include <kis_tiff_import.moc>
+
diff --git a/filters/chalk/tiff/kis_tiff_import.h b/filters/chalk/tiff/kis_tiff_import.h
new file mode 100644
index 00000000..9fef7755
--- /dev/null
+++ b/filters/chalk/tiff/kis_tiff_import.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef _KIS_TIFF_IMPORT_H_
+#define _KIS_TIFF_IMPORT_H_
+
+#include <KoFilter.h>
+
+class KisTIFFImport : public KoFilter {
+ Q_OBJECT
+ TQ_OBJECT
+ public:
+ KisTIFFImport(KoFilter *tqparent, const char *name, const TQStringList&);
+ virtual ~KisTIFFImport();
+ public:
+ virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to);
+};
+
+#endif
diff --git a/filters/chalk/tiff/kis_tiff_reader.cc b/filters/chalk/tiff/kis_tiff_reader.cc
new file mode 100644
index 00000000..f2eabd87
--- /dev/null
+++ b/filters/chalk/tiff/kis_tiff_reader.cc
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2005-2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_tiff_reader.h"
+
+#include <kdebug.h>
+
+#include <kis_iterators_pixel.h>
+#include <kis_paint_device.h>
+
+#include "kis_tiff_stream.h"
+
+ uint KisTIFFReaderTarget8bit::copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream)
+ {
+ KisHLineIterator it = paintDevice() -> createHLineIterator(x, y, dataWidth, true);
+ double coeff = TQ_UINT8_MAX / (double)( pow(2, sourceDepth() ) - 1 );
+// kdDebug(41008) << " depth expension coefficient : " << coeff << endl;
+ while (!it.isDone()) {
+ TQ_UINT8 *d = it.rawData();
+ TQ_UINT8 i;
+ for(i = 0; i < nbColorsSamples() ; i++)
+ {
+ d[poses()[i]] = (TQ_UINT8)( tiffstream->nextValue() * coeff );
+ }
+ postProcessor()->postProcess8bit( d);
+ if(transform()) cmsDoTransform(transform(), d, d, 1);
+ d[poses()[i]] = TQ_UINT8_MAX;
+ for(int k = 0; k < nbExtraSamples(); k++)
+ {
+ if(k == alphaPos())
+ d[poses()[i]] = (TQ_UINT32) ( tiffstream->nextValue() * coeff );
+ else
+ tiffstream->nextValue();
+ }
+ ++it;
+ }
+ return 1;
+ }
+ uint KisTIFFReaderTarget16bit::copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream)
+ {
+ KisHLineIterator it = paintDevice() -> createHLineIterator(x, y, dataWidth, true);
+ double coeff = TQ_UINT16_MAX / (double)( pow(2, sourceDepth() ) - 1 );
+// kdDebug(41008) << " depth expension coefficient : " << coeff << endl;
+ while (!it.isDone()) {
+ TQ_UINT16 *d = reinterpret_cast<TQ_UINT16 *>(it.rawData());
+ TQ_UINT8 i;
+ for(i = 0; i < nbColorsSamples(); i++)
+ {
+ d[poses()[i]] = (TQ_UINT16)( tiffstream->nextValue() * coeff );
+ }
+ postProcessor()->postProcess16bit( d);
+ if(transform()) cmsDoTransform(transform(), d, d, 1);
+ d[poses()[i]] = TQ_UINT16_MAX;
+ for(int k = 0; k < nbExtraSamples(); k++)
+ {
+ if(k == alphaPos())
+ d[poses()[i]] = (TQ_UINT16) ( tiffstream->nextValue() * coeff );
+ else
+ tiffstream->nextValue();
+ }
+ ++it;
+ }
+ return 1;
+ }
+
+ uint KisTIFFReaderTarget32bit::copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream)
+ {
+ KisHLineIterator it = paintDevice() -> createHLineIterator(x, y, dataWidth, true);
+ double coeff = TQ_UINT32_MAX / (double)( pow(2, sourceDepth() ) - 1 );
+// kdDebug(41008) << " depth expension coefficient : " << coeff << endl;
+ while (!it.isDone()) {
+ TQ_UINT32 *d = reinterpret_cast<TQ_UINT32 *>(it.rawData());
+ TQ_UINT8 i;
+ for(i = 0; i < nbColorsSamples(); i++)
+ {
+ d[poses()[i]] = (TQ_UINT32)( tiffstream->nextValue() * coeff );
+ }
+ postProcessor()->postProcess32bit( d);
+ if(transform()) cmsDoTransform(transform(), d, d, 1);
+ d[poses()[i]] = TQ_UINT32_MAX;
+ for(int k = 0; k < nbExtraSamples(); k++)
+ {
+ if(k == alphaPos())
+ d[poses()[i]] = (TQ_UINT32) ( tiffstream->nextValue() * coeff );
+ else
+ tiffstream->nextValue();
+ }
+ ++it;
+ }
+ return 1;
+ }
+ uint KisTIFFReaderFromPalette::copyDataToChannels(TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream)
+ {
+ KisHLineIterator it = paintDevice() -> createHLineIterator(x, y, dataWidth, true);
+ while (!it.isDone()) {
+ TQ_UINT16* d = reinterpret_cast<TQ_UINT16 *>(it.rawData());
+ uint32 index = tiffstream->nextValue();
+ d[2] = m_red[index];
+ d[1] = m_green[index];
+ d[0] = m_blue[index];
+ d[3] = TQ_UINT16_MAX;
+ ++it;
+ }
+ return 1;
+ }
diff --git a/filters/chalk/tiff/kis_tiff_reader.h b/filters/chalk/tiff/kis_tiff_reader.h
new file mode 100644
index 00000000..2ab573dd
--- /dev/null
+++ b/filters/chalk/tiff/kis_tiff_reader.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _KIS_TIFF_READER_H_
+#define _KIS_TIFF_READER_H_
+
+// On some platforms, tiffio.h #defines NULL in a bad
+// way for C++, as (void *)0 instead of using the correct
+// C++ value 0. Include stdio.h first to get the right one.
+#include <stdio.h>
+#include <tiffio.h>
+
+// #include <tqvaluevector.h>
+// #include <kio/job.h>
+// #include <kis_progress_subject.h>
+
+#include <kis_paint_device.h>
+
+#include "kis_types.h"
+#include "kis_global.h"
+// #include "kis_annotation.h"
+
+#include <kis_iterator.h>
+#include <kis_paint_device.h>
+
+#define TQ_UINT32_MAX 4294967295u
+
+class TIFFStreamBase;
+
+class KisTIFFPostProcessor {
+ public:
+ KisTIFFPostProcessor(uint8 nbcolorssamples) : m_nbcolorssamples(nbcolorssamples) { }
+ public:
+ virtual void postProcess8bit( TQ_UINT8* ) { };
+ virtual void postProcess16bit( TQ_UINT16* ) { };
+ virtual void postProcess32bit( TQ_UINT32* ) { };
+ protected:
+ inline uint8 nbColorsSamples() { return m_nbcolorssamples; }
+ private:
+ uint8 m_nbcolorssamples;
+};
+
+class KisTIFFPostProcessorInvert : public KisTIFFPostProcessor {
+ public:
+ KisTIFFPostProcessorInvert(uint8 nbcolorssamples) : KisTIFFPostProcessor(nbcolorssamples) {}
+ public:
+ virtual void postProcess8bit( TQ_UINT8* data )
+ {
+ for(int i = 0; i < nbColorsSamples(); i++)
+ {
+ data[i] = TQ_UINT8_MAX - data[i];
+ }
+ }
+ virtual void postProcess16bit( TQ_UINT16* data )
+ {
+ TQ_UINT16* d = (TQ_UINT16*) data;
+ for(int i = 0; i < nbColorsSamples(); i++)
+ {
+ d[i] = TQ_UINT16_MAX - d[i];
+ }
+ }
+ virtual void postProcess32bit( TQ_UINT32* data )
+ {
+ TQ_UINT32* d = (TQ_UINT32*) data;
+ for(int i = 0; i < nbColorsSamples(); i++)
+ {
+ d[i] = TQ_UINT32_MAX - d[i];
+ }
+ }
+};
+
+class KisTIFFPostProcessorICCLABtoCIELAB : public KisTIFFPostProcessor {
+ public:
+ KisTIFFPostProcessorICCLABtoCIELAB(uint8 nbcolorssamples) : KisTIFFPostProcessor(nbcolorssamples) {}
+ public:
+ void postProcess8bit(TQ_UINT8* data)
+ {
+ TQ_INT8* ds = (TQ_INT8*) data;
+ for(int i = 1; i < nbColorsSamples(); i++)
+ {
+ ds[i] = data[i] - TQ_UINT8_MAX/2;
+ }
+ }
+ void postProcess16bit(TQ_UINT16* data)
+ {
+ TQ_UINT16* d = (TQ_UINT16*) data;
+ TQ_INT16* ds = (TQ_INT16*) data;
+ for(int i = 1; i < nbColorsSamples(); i++)
+ {
+ ds[i] = d[i] - TQ_UINT16_MAX /2;
+ }
+ }
+ void postProcess32bit(TQ_UINT32* data)
+ {
+ TQ_UINT32* d = (TQ_UINT32*) data;
+ TQ_INT32* ds = (TQ_INT32*) data;
+ for(int i = 1; i < nbColorsSamples(); i++)
+ {
+ ds[i] = d[i] - TQ_UINT32_MAX /2;
+ }
+ }
+};
+
+
+class KisTIFFReaderBase {
+ public:
+ KisTIFFReaderBase( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor) : m_device(device), m_alphapos(alphapos), m_sourceDepth(sourceDepth), m_nbcolorssamples(nbcolorssamples), m_nbextrasamples(extrasamplescount), m_poses(poses), m_transformProfile(transformProfile), m_postprocess(postprocessor)
+ {
+
+ }
+ public:
+ /**
+ * This function copy data from the tiff stream to the paint device starting at the given position.
+ * @param x horizontal start position
+ * @param y vertical start position
+ * @param dataWidth width of the data to copy
+ * @param tiffstream source of data
+ *
+ * @return the number of line which were copied
+ */
+ virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream) =0;
+ /**
+ * This function is called when all data has been read and should be used for any postprocessing.
+ */
+ virtual void finalize() { };
+ protected:
+ inline KisPaintDeviceSP paintDevice() { return m_device; }
+ inline TQ_UINT8 alphaPos() { return m_alphapos; }
+ inline TQ_UINT8 sourceDepth() { return m_sourceDepth; }
+ inline TQ_UINT8 nbColorsSamples() { return m_nbcolorssamples; }
+ inline TQ_UINT8 nbExtraSamples() { return m_nbextrasamples; }
+ inline TQ_UINT8* poses() { return m_poses; }
+ inline cmsHTRANSFORM transform() { return m_transformProfile; }
+ inline KisTIFFPostProcessor* postProcessor() { return m_postprocess; }
+ private:
+ KisPaintDeviceSP m_device;
+ TQ_UINT8 m_alphapos;
+ TQ_UINT8 m_sourceDepth;
+ TQ_UINT8 m_nbcolorssamples;
+ TQ_UINT8 m_nbextrasamples;
+ TQ_UINT8* m_poses;
+ cmsHTRANSFORM m_transformProfile;
+ KisTIFFPostProcessor* m_postprocess;
+ TQ_UINT32 m_tiffDataWidth;
+};
+
+class KisTIFFReaderTarget8bit : public KisTIFFReaderBase {
+ public:
+ KisTIFFReaderTarget8bit( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor) : KisTIFFReaderBase(device, poses, alphapos, sourceDepth, nbcolorssamples, extrasamplescount, transformProfile, postprocessor )
+ {
+
+ }
+ public:
+ virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream);
+};
+
+
+class KisTIFFReaderTarget16bit : public KisTIFFReaderBase {
+ public:
+ KisTIFFReaderTarget16bit( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor) : KisTIFFReaderBase(device, poses, alphapos, sourceDepth, nbcolorssamples, extrasamplescount, transformProfile, postprocessor )
+ {
+
+ }
+ public:
+ virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream) ;
+};
+
+class KisTIFFReaderTarget32bit : public KisTIFFReaderBase {
+ public:
+ KisTIFFReaderTarget32bit( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor) : KisTIFFReaderBase(device, poses, alphapos, sourceDepth, nbcolorssamples, extrasamplescount, transformProfile, postprocessor )
+ {
+
+ }
+ public:
+ virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream) ;
+};
+
+class KisTIFFReaderFromPalette : public KisTIFFReaderBase {
+ public:
+ KisTIFFReaderFromPalette( KisPaintDeviceSP device, uint16 *red, uint16 *green, uint16 *blue, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor) : KisTIFFReaderBase(device, poses, alphapos, sourceDepth, nbcolorssamples, extrasamplescount, transformProfile, postprocessor ), m_red(red), m_green(green), m_blue(blue)
+ {
+
+ }
+ public:
+ virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream) ;
+ private:
+ uint16 *m_red, *m_green, *m_blue;
+};
+
+#endif
diff --git a/filters/chalk/tiff/kis_tiff_stream.cc b/filters/chalk/tiff/kis_tiff_stream.cc
new file mode 100644
index 00000000..3d52d4dc
--- /dev/null
+++ b/filters/chalk/tiff/kis_tiff_stream.cc
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2005-2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_tiff_stream.h"
+
+TIFFStreamContigBase::TIFFStreamContigBase( uint8* src, uint16 depth, uint32 lineSize ) : TIFFStreamBase(depth), m_src(src), m_lineSize(lineSize) { restart(); }
+
+void TIFFStreamContigBase::restart()
+{
+ m_srcit = m_src;
+ m_posinc = 8;
+}
+
+void TIFFStreamContigBase::moveToLine(uint32 lineNumber)
+{
+ m_srcit = m_src + lineNumber * m_lineSize;
+ m_posinc = 8;
+}
+
+uint32 TIFFStreamContigBelow16::nextValue()
+{
+ register uint8 remain;
+ register uint32 value;
+ remain = m_depth;
+ value = 0;
+ while (remain > 0)
+ {
+ register uint8 toread;
+ toread = remain;
+ if (toread > m_posinc) toread = m_posinc;
+ remain -= toread;
+ m_posinc -= toread;
+ value = (value << toread) | (( (*m_srcit) >> (m_posinc) ) & ( ( 1 << toread ) - 1 ) );
+ if (m_posinc == 0)
+ {
+ m_srcit++;
+ m_posinc=8;
+ }
+ }
+ return value;
+}
+
+uint32 TIFFStreamContigBelow32::nextValue()
+{
+ register uint8 remain;
+ register uint32 value;
+ remain = m_depth;
+ value = 0;
+ while (remain > 0)
+ {
+ register uint8 toread;
+ toread = remain;
+ if (toread > m_posinc) toread = m_posinc;
+ remain -= toread;
+ m_posinc -= toread;
+ value = (value) | ( (( (*m_srcit) >> (m_posinc) ) & ( ( 1 << toread ) - 1 ) ) << ( m_depth - 8 - remain ) );
+ if (m_posinc == 0)
+ {
+ m_srcit++;
+ m_posinc=8;
+ }
+ }
+ return value;
+}
+
+uint32 TIFFStreamContigAbove32::nextValue()
+{
+ register uint8 remain;
+ register uint32 value;
+ remain = m_depth;
+ value = 0;
+ while (remain > 0)
+ {
+ register uint8 toread;
+ toread = remain;
+ if (toread > m_posinc) toread = m_posinc;
+ remain -= toread;
+ m_posinc -= toread;
+ if(remain < 32 )
+ {
+ value = (value) | ( (( (*m_srcit) >> (m_posinc) ) & ( ( 1 << toread ) - 1 ) ) << ( 24 - remain ) );
+ }
+ if (m_posinc == 0)
+ {
+ m_srcit++;
+ m_posinc=8;
+ }
+ }
+ return value;
+}
+
+TIFFStreamSeperate::TIFFStreamSeperate( uint8** srcs, uint8 nb_samples ,uint16 depth, uint32* lineSize) : TIFFStreamBase(depth), m_nb_samples(nb_samples)
+{
+ streams = new TIFFStreamContigBase*[nb_samples];
+ if(depth < 16)
+ {
+ for(uint8 i = 0; i < m_nb_samples; i++)
+ {
+ streams[i] = new TIFFStreamContigBelow16(srcs[i], depth, lineSize[i]);
+ }
+ } else if( depth < 32 )
+ {
+ for(uint8 i = 0; i < m_nb_samples; i++)
+ {
+ streams[i] = new TIFFStreamContigBelow32(srcs[i], depth, lineSize[i]);
+ }
+ } else {
+ for(uint8 i = 0; i < m_nb_samples; i++)
+ {
+ streams[i] = new TIFFStreamContigAbove32(srcs[i], depth, lineSize[i]);
+ }
+ }
+ restart();
+}
+
+TIFFStreamSeperate::~TIFFStreamSeperate()
+{
+ for(uint8 i = 0; i < m_nb_samples; i++)
+ {
+ delete streams[i];
+ }
+ delete[] streams;
+}
+
+uint32 TIFFStreamSeperate::nextValue()
+{
+ uint32 value = streams[ m_current_sample ]->nextValue();
+ if( (++m_current_sample) >= m_nb_samples)
+ m_current_sample = 0;
+ return value;
+}
+
+void TIFFStreamSeperate::restart()
+{
+ m_current_sample = 0;
+ for(uint8 i = 0; i < m_nb_samples; i++)
+ {
+ streams[i]->restart();
+ }
+}
+
+void TIFFStreamSeperate::moveToLine(uint32 lineNumber)
+{
+ for(uint8 i = 0; i < m_nb_samples; i++)
+ {
+ streams[i]->moveToLine(lineNumber);
+ }
+}
diff --git a/filters/chalk/tiff/kis_tiff_stream.h b/filters/chalk/tiff/kis_tiff_stream.h
new file mode 100644
index 00000000..f203568e
--- /dev/null
+++ b/filters/chalk/tiff/kis_tiff_stream.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2005-2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef TIFFSTREAM_H_
+#define TIFFSTREAM_H_
+
+#include <tiffio.h>
+
+class TIFFStreamBase {
+ public:
+ TIFFStreamBase( uint16 depth ) : m_depth(depth) {};
+ virtual uint32 nextValue() =0;
+ virtual void restart() =0;
+ virtual void moveToLine(uint32 lineNumber) =0;
+ protected:
+ uint16 m_depth;
+};
+
+class TIFFStreamContigBase : public TIFFStreamBase {
+ public:
+ TIFFStreamContigBase( uint8* src, uint16 depth, uint32 lineSize );
+ virtual void restart();
+ virtual void moveToLine(uint32 lineNumber);
+ protected:
+ uint8* m_src;
+ uint8* m_srcit;
+ uint8 m_posinc;
+ uint32 m_lineSize;
+};
+
+class TIFFStreamContigBelow16 : public TIFFStreamContigBase {
+ public:
+ TIFFStreamContigBelow16( uint8* src, uint16 depth, uint32 lineSize ) : TIFFStreamContigBase(src, depth, lineSize) { }
+ public:
+ virtual uint32 nextValue();
+};
+
+class TIFFStreamContigBelow32 : public TIFFStreamContigBase {
+ public:
+ TIFFStreamContigBelow32( uint8* src, uint16 depth, uint32 lineSize ) : TIFFStreamContigBase(src, depth, lineSize) { }
+ public:
+ virtual uint32 nextValue();
+};
+
+class TIFFStreamContigAbove32 : public TIFFStreamContigBase {
+ public:
+ TIFFStreamContigAbove32( uint8* src, uint16 depth, uint32 lineSize ) : TIFFStreamContigBase(src, depth, lineSize) { }
+ public:
+ virtual uint32 nextValue();
+};
+
+
+class TIFFStreamSeperate : public TIFFStreamBase {
+ public:
+ TIFFStreamSeperate( uint8** srcs, uint8 nb_samples ,uint16 depth, uint32* lineSize);
+ ~TIFFStreamSeperate();
+ virtual uint32 nextValue();
+ virtual void restart();
+ virtual void moveToLine(uint32 lineNumber);
+ private:
+ TIFFStreamContigBase** streams;
+ uint8 m_current_sample, m_nb_samples;
+};
+
+#endif
diff --git a/filters/chalk/tiff/kis_tiff_writer_visitor.cpp b/filters/chalk/tiff/kis_tiff_writer_visitor.cpp
new file mode 100644
index 00000000..681e66b7
--- /dev/null
+++ b/filters/chalk/tiff/kis_tiff_writer_visitor.cpp
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_tiff_writer_visitor.h"
+
+#include <kmessagebox.h>
+#include <klocale.h>
+
+#include <kis_annotation.h>
+#include <kis_colorspace.h>
+#include <kis_group_layer.h>
+#include <kis_image.h>
+#include <kis_paint_layer.h>
+#include <kis_types.h>
+
+#include "kis_tiff_converter.h"
+
+namespace {
+ bool writeColorSpaceInformation( TIFF* image, KisColorSpace * cs, uint16& color_type, uint16& sample_format )
+ {
+ sample_format = SAMPLEFORMAT_UINT;
+ if ( cs->id() == KisID("GRAYA") || cs->id() == KisID("GRAYA16") )
+ {
+ color_type = PHOTOMETRIC_MINISBLACK;
+ return true;
+ }
+ if ( cs->id() == KisID("RGBA") || cs->id() == KisID("RGBA16") )
+ {
+ color_type = PHOTOMETRIC_RGB;
+ return true;
+ }
+ if ( cs->id() == KisID("RGBAF16HALF") || cs->id() == KisID("RGBAF32") )
+ {
+ color_type = PHOTOMETRIC_RGB;
+ sample_format = SAMPLEFORMAT_IEEEFP;
+ return true;
+ }
+ if ( cs->id() == KisID("CMYK") || cs->id() == KisID("CMYKA16") )
+ {
+ color_type = PHOTOMETRIC_SEPARATED;
+ TIFFSetField(image, TIFFTAG_INKSET, INKSET_CMYK);
+ return true;
+ }
+ if ( cs->id() == KisID("LABA") )
+ {
+ color_type = PHOTOMETRIC_CIELAB;
+ return true;
+ }
+
+ KMessageBox::error(0, i18n("Cannot export images in %1.\n").tqarg(cs->id().name()) ) ;
+ return false;
+
+ }
+}
+
+KisTIFFWriterVisitor::KisTIFFWriterVisitor(TIFF*img, KisTIFFOptions* options) : m_image(img), m_options(options)
+{
+}
+
+KisTIFFWriterVisitor::~KisTIFFWriterVisitor()
+{
+}
+
+bool KisTIFFWriterVisitor::saveAlpha() { return m_options->alpha; }
+
+bool KisTIFFWriterVisitor::copyDataToStrips( KisHLineIterator it, tdata_t buff, uint8 depth, uint8 nbcolorssamples, TQ_UINT8* poses)
+{
+ if(depth == 32)
+ {
+ TQ_UINT32 *dst = reinterpret_cast<TQ_UINT32 *>(buff);
+ while (!it.isDone()) {
+ const TQ_UINT32 *d = reinterpret_cast<const TQ_UINT32 *>(it.rawData());
+ int i;
+ for(i = 0; i < nbcolorssamples; i++)
+ {
+ *(dst++) = d[poses[i]];
+ }
+ if(saveAlpha()) *(dst++) = d[poses[i]];
+ ++it;
+ }
+ return true;
+ } else if(depth == 16)
+ {
+ TQ_UINT16 *dst = reinterpret_cast<TQ_UINT16 *>(buff);
+ while (!it.isDone()) {
+ const TQ_UINT16 *d = reinterpret_cast<const TQ_UINT16 *>(it.rawData());
+ int i;
+ for(i = 0; i < nbcolorssamples; i++)
+ {
+ *(dst++) = d[poses[i]];
+ }
+ if(saveAlpha()) *(dst++) = d[poses[i]];
+ ++it;
+ }
+ return true;
+ } else if(depth == 8) {
+ TQ_UINT8 *dst = reinterpret_cast<TQ_UINT8 *>(buff);
+ while (!it.isDone()) {
+ const TQ_UINT8 *d = it.rawData();
+ int i;
+ for(i = 0; i < nbcolorssamples; i++)
+ {
+ *(dst++) = d[poses[i]];
+ }
+ if(saveAlpha()) *(dst++) = d[poses[i]];
+ ++it;
+ }
+ return true;
+ }
+ return false;
+}
+
+
+bool KisTIFFWriterVisitor::visit(KisPaintLayer *layer)
+{
+ kdDebug(41008) << "visiting on paint layer " << layer->name() << "\n";
+ KisPaintDeviceSP pd = layer->paintDevice();
+ // Save depth
+ int depth = 8 * pd->pixelSize() / pd->nChannels();
+ TIFFSetField(image(), TIFFTAG_BITSPERSAMPLE, depth);
+ // Save number of samples
+ if(saveAlpha())
+ {
+ TIFFSetField(image(), TIFFTAG_SAMPLESPERPIXEL, pd->nChannels());
+ uint16 sampleinfo[1] = { EXTRASAMPLE_UNASSALPHA };
+ TIFFSetField(image(), TIFFTAG_EXTRASAMPLES, 1, sampleinfo);
+ } else {
+ TIFFSetField(image(), TIFFTAG_SAMPLESPERPIXEL, pd->nChannels() - 1);
+ TIFFSetField(image(), TIFFTAG_EXTRASAMPLES, 0);
+ }
+ // Save colorspace information
+ uint16 color_type;
+ uint16 sample_format;
+ if(!writeColorSpaceInformation(image(), pd->colorSpace(), color_type, sample_format))
+ { // unsupported colorspace
+ return false;
+ }
+ TIFFSetField(image(), TIFFTAG_PHOTOMETRIC, color_type);
+ TIFFSetField(image(), TIFFTAG_SAMPLEFORMAT, sample_format);
+ TIFFSetField(image(), TIFFTAG_IMAGEWIDTH, layer->image()->width());
+ TIFFSetField(image(), TIFFTAG_IMAGELENGTH, layer->image()->height());
+
+ // Set the compression options
+ TIFFSetField(image(), TIFFTAG_COMPRESSION, m_options->compressionType);
+ TIFFSetField(image(), TIFFTAG_FAXMODE, m_options->faxMode);
+ TIFFSetField(image(), TIFFTAG_JPEGQUALITY, m_options->jpegQuality);
+ TIFFSetField(image(), TIFFTAG_ZIPQUALITY, m_options->deflateCompress);
+ TIFFSetField(image(), TIFFTAG_PIXARLOGQUALITY, m_options->pixarLogCompress);
+
+ // Set the predictor
+ TIFFSetField(image(), TIFFTAG_PREDICTOR, m_options->predictor);
+
+ // Use contiguous configuration
+ TIFFSetField(image(), TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ // Use 8 rows per strip
+ TIFFSetField(image(), TIFFTAG_ROWSPERSTRIP, 8);
+
+ // Save profile
+ KisProfile* profile = pd->colorSpace()->getProfile();
+ if(profile)
+ {
+ TQByteArray ba = profile->annotation()->annotation();
+ TIFFSetField(image(), TIFFTAG_ICCPROFILE, ba.size(),ba.data());
+ }
+ tsize_t stripsize = TIFFStripSize(image());
+ tdata_t buff = _TIFFmalloc(stripsize);
+ TQ_INT32 height = layer->image()->height();
+ TQ_INT32 width = layer->image()->width();
+ bool r = true;
+ for (int y = 0; y < height; y++) {
+ KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, y, width, false);
+ switch(color_type)
+ {
+ case PHOTOMETRIC_MINISBLACK:
+ {
+ TQ_UINT8 poses[]={ 0,1 };
+ r = copyDataToStrips(it, buff, depth, 1, poses);
+ }
+ break;
+ case PHOTOMETRIC_RGB:
+ {
+ TQ_UINT8 poses[]={ 2, 1, 0, 3};
+ r = copyDataToStrips(it, buff, depth, 3, poses);
+ }
+ break;
+ case PHOTOMETRIC_SEPARATED:
+ {
+ TQ_UINT8 poses[]={ 0, 1, 2, 3, 4 };
+ r = copyDataToStrips(it, buff, depth, 4, poses);
+ }
+ break;
+ case PHOTOMETRIC_CIELAB:
+ {
+ TQ_UINT8 poses[]={ 0, 1, 2, 3 };
+ r = copyDataToStrips(it, buff, depth, 3, poses);
+ }
+ break;
+ return false;
+ }
+ if(!r) return false;
+ TIFFWriteScanline(image(), buff, y, (tsample_t) -1);
+ }
+ _TIFFfree(buff);
+ TIFFWriteDirectory(image());
+ return true;
+}
+bool KisTIFFWriterVisitor::visit(KisGroupLayer *layer)
+{
+ kdDebug(41008) << "Visiting on grouplayer " << layer->name() << "\n";
+ KisLayerSP child = layer->firstChild();
+ while (child) {
+ child->accept(*this);
+ child = child->nextSibling();
+ }
+ return true;
+}
+
+bool KisTIFFWriterVisitor::visit(KisPartLayer *)
+{
+ return true;
+}
diff --git a/filters/chalk/tiff/kis_tiff_writer_visitor.h b/filters/chalk/tiff/kis_tiff_writer_visitor.h
new file mode 100644
index 00000000..abd1aec7
--- /dev/null
+++ b/filters/chalk/tiff/kis_tiff_writer_visitor.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KIS_TIFF_WRITER_VISITOR_H
+#define KIS_TIFF_WRITER_VISITOR_H
+
+#include <kis_layer_visitor.h>
+
+#include <kis_iterators_pixel.h>
+
+#include <tiffio.h>
+
+class KisTIFFOptions;
+
+/**
+ @author Cyrille Berger <cberger@cberger.net>
+*/
+class KisTIFFWriterVisitor : public KisLayerVisitor
+{
+ public:
+ KisTIFFWriterVisitor(TIFF*img, KisTIFFOptions* options);
+ ~KisTIFFWriterVisitor();
+ public:
+ virtual bool visit(KisPaintLayer *layer);
+ virtual bool visit(KisGroupLayer *layer);
+ virtual bool visit(KisPartLayer *layer);
+ virtual bool visit(KisAdjustmentLayer* ) { return true; }
+ private:
+ inline TIFF* image() { return m_image; }
+ inline bool saveAlpha();
+ bool copyDataToStrips( KisHLineIterator it, tdata_t buff, uint8 depth, uint8 nbcolorssamples, TQ_UINT8* poses);
+ private:
+ TIFF* m_image;
+ KisTIFFOptions* m_options;
+};
+
+#endif
diff --git a/filters/chalk/tiff/kis_tiff_ycbcr_reader.cc b/filters/chalk/tiff/kis_tiff_ycbcr_reader.cc
new file mode 100644
index 00000000..ce5e4ae9
--- /dev/null
+++ b/filters/chalk/tiff/kis_tiff_ycbcr_reader.cc
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_tiff_ycbcr_reader.h"
+
+#include <kis_iterators_pixel.h>
+#include <kis_paint_device.h>
+
+#include "kis_tiff_stream.h"
+
+
+KisTIFFYCbCrReaderTarget8Bit::KisTIFFYCbCrReaderTarget8Bit( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor, uint16 hsub, uint16 vsub, KisTIFFYCbCr::Position position ) : KisTIFFReaderBase(device, poses, alphapos, sourceDepth, nbcolorssamples, extrasamplescount, transformProfile, postprocessor), m_hsub(hsub), m_vsub(vsub), m_position(position)
+{
+ // Initialize the buffer
+ TQ_INT32 imagewidth = device->image()->width();
+ if(2*(imagewidth / 2) != imagewidth) imagewidth++;
+ m_bufferWidth = imagewidth / m_hsub;
+ TQ_INT32 imageheight = device->image()->height();
+ if(2*(imageheight / 2) != imageheight) imageheight++;
+ m_bufferHeight = imageheight / m_vsub;
+ m_bufferCb = new TQ_UINT8[ m_bufferWidth * m_bufferHeight ];
+ m_bufferCr = new TQ_UINT8[ m_bufferWidth * m_bufferHeight ];
+}
+
+KisTIFFYCbCrReaderTarget8Bit::~KisTIFFYCbCrReaderTarget8Bit()
+{
+ delete[] m_bufferCb;
+ delete[] m_bufferCr;
+}
+
+uint KisTIFFYCbCrReaderTarget8Bit::copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream)
+{
+ int numcols = dataWidth / m_hsub;
+ double coeff = TQ_UINT8_MAX / (double)( pow(2, sourceDepth() ) - 1 );
+// kdDebug(41008) << " depth expension coefficient : " << coeff << endl;
+// kdDebug(41008) << " y = " << y << endl;
+ uint buffPos = y / m_vsub * m_bufferWidth + x / m_hsub ;
+ for(int index = 0; index < numcols; index++)
+ {
+ KisHLineIterator it = paintDevice() -> createHLineIterator(x + m_hsub * index, y, m_hsub, true);
+ for( int vindex = 0; vindex < m_vsub; vindex++)
+ {
+ while( !it.isDone() )
+ {
+ TQ_UINT8 *d = it.rawData();
+ d[0] = (TQ_UINT8)( tiffstream->nextValue() * coeff );
+ d[3] = TQ_UINT8_MAX;
+ for(int k = 0; k < nbExtraSamples(); k++)
+ {
+ if(k == alphaPos())
+ d[3] = (TQ_UINT32) ( tiffstream->nextValue() * coeff );
+ else
+ tiffstream->nextValue();
+ }
+ ++it;
+ }
+ it.nextRow();
+ }
+ m_bufferCb[ buffPos ] = (TQ_UINT8)(tiffstream->nextValue() * coeff);
+ m_bufferCr[ buffPos ] = (TQ_UINT8)(tiffstream->nextValue() * coeff);
+ buffPos ++;
+ }
+ return m_vsub;
+}
+
+void KisTIFFYCbCrReaderTarget8Bit::finalize()
+{
+ KisHLineIterator it = paintDevice() -> createHLineIterator(0, 0, paintDevice()->image()->width(), true);
+ for(int y = 0; y < paintDevice()->image()->height(); y++)
+ {
+ int x = 0;
+ while(!it.isDone())
+ {
+ TQ_UINT8 *d = it.rawData();
+ int index = x/m_hsub + y/m_vsub * m_bufferWidth;
+ d[1] = m_bufferCb[ index ];
+ d[2] = m_bufferCr[ index ];
+ ++it; ++x;
+ }
+ it.nextRow();
+ }
+}
+
+KisTIFFYCbCrReaderTarget16Bit::KisTIFFYCbCrReaderTarget16Bit( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor, uint16 hsub, uint16 vsub, KisTIFFYCbCr::Position position ) : KisTIFFReaderBase(device, poses, alphapos, sourceDepth, nbcolorssamples, extrasamplescount, transformProfile, postprocessor), m_hsub(hsub), m_vsub(vsub), m_position(position)
+{
+ // Initialize the buffer
+ TQ_INT32 imagewidth = device->image()->width();
+ if(2*(imagewidth / 2) != imagewidth) imagewidth++;
+ m_bufferWidth = imagewidth / m_hsub;
+ TQ_INT32 imageheight = device->image()->height();
+ if(2*(imageheight / 2) != imageheight) imageheight++;
+ m_bufferHeight = imageheight / m_vsub;
+ m_bufferCb = new TQ_UINT16[ m_bufferWidth * m_bufferHeight ];
+ m_bufferCr = new TQ_UINT16[ m_bufferWidth * m_bufferHeight ];
+}
+
+KisTIFFYCbCrReaderTarget16Bit::~KisTIFFYCbCrReaderTarget16Bit()
+{
+ delete[] m_bufferCb;
+ delete[] m_bufferCr;
+}
+
+uint KisTIFFYCbCrReaderTarget16Bit::copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream)
+{
+ int numcols = dataWidth / m_hsub;
+ double coeff = TQ_UINT16_MAX / (double)( pow(2, sourceDepth() ) - 1 );
+// kdDebug(41008) << " depth expension coefficient : " << coeff << endl;
+// kdDebug(41008) << " y = " << y << endl;
+ uint buffPos = y / m_vsub * m_bufferWidth + x / m_hsub ;
+ for(int index = 0; index < numcols; index++)
+ {
+ KisHLineIterator it = paintDevice() -> createHLineIterator(x + m_hsub * index, y, m_hsub, true);
+ for( int vindex = 0; vindex < m_vsub; vindex++)
+ {
+ while( !it.isDone() )
+ {
+ TQ_UINT16 *d = reinterpret_cast<TQ_UINT16 *>(it.rawData());
+ d[0] = (TQ_UINT16)( tiffstream->nextValue() * coeff );
+ d[3] = TQ_UINT16_MAX;
+ for(int k = 0; k < nbExtraSamples(); k++)
+ {
+ if(k == alphaPos())
+ d[3] = (TQ_UINT32) ( tiffstream->nextValue() * coeff );
+ else
+ tiffstream->nextValue();
+ }
+ ++it;
+ }
+ it.nextRow();
+ }
+ m_bufferCb[ buffPos ] = (TQ_UINT16)(tiffstream->nextValue() * coeff);
+ m_bufferCr[ buffPos ] = (TQ_UINT16)(tiffstream->nextValue() * coeff);
+ buffPos ++;
+ }
+ return m_vsub;
+}
+
+void KisTIFFYCbCrReaderTarget16Bit::finalize()
+{
+ KisHLineIterator it = paintDevice() -> createHLineIterator(0, 0, paintDevice()->image()->width(), true);
+ for(int y = 0; y < paintDevice()->image()->height(); y++)
+ {
+ int x = 0;
+ while(!it.isDone())
+ {
+ TQ_UINT16 *d = reinterpret_cast<TQ_UINT16 *>(it.rawData());
+ int index = x/m_hsub + y/m_vsub * m_bufferWidth;
+ d[1] = m_bufferCb[ index ];
+ d[2] = m_bufferCr[ index ];
+ ++it; ++x;
+ }
+ it.nextRow();
+ }
+}
diff --git a/filters/chalk/tiff/kis_tiff_ycbcr_reader.h b/filters/chalk/tiff/kis_tiff_ycbcr_reader.h
new file mode 100644
index 00000000..e81e8893
--- /dev/null
+++ b/filters/chalk/tiff/kis_tiff_ycbcr_reader.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _KIS_TIFF_YCBCR_READER_H_
+#define _KIS_TIFF_YCBCR_READER_H_
+
+#include "kis_tiff_reader.h"
+
+namespace KisTIFFYCbCr {
+ enum Position {
+ POSITION_CENTERED = 1,
+ POSITION_COSITED = 2
+ };
+}
+
+class KisTIFFYCbCrReaderTarget8Bit : public KisTIFFReaderBase {
+ public:
+ /**
+ * @param hsub horizontal subsampling of Cb and Cr
+ * @param hsub vertical subsampling of Cb and Cr
+ */
+ KisTIFFYCbCrReaderTarget8Bit( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor, uint16 hsub, uint16 vsub, KisTIFFYCbCr::Position position );
+ ~KisTIFFYCbCrReaderTarget8Bit();
+ virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream);
+ virtual void finalize();
+ private:
+ TQ_UINT8* m_bufferCb;
+ TQ_UINT8* m_bufferCr;
+ TQ_UINT32 m_bufferWidth, m_bufferHeight;
+ uint16 m_hsub;
+ uint16 m_vsub;
+ KisTIFFYCbCr::Position m_position;
+
+};
+
+class KisTIFFYCbCrReaderTarget16Bit : public KisTIFFReaderBase {
+ public:
+ /**
+ * @param hsub horizontal subsampling of Cb and Cr
+ * @param hsub vertical subsampling of Cb and Cr
+ */
+ KisTIFFYCbCrReaderTarget16Bit( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor, uint16 hsub, uint16 vsub, KisTIFFYCbCr::Position position );
+ ~KisTIFFYCbCrReaderTarget16Bit();
+ virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream);
+ virtual void finalize();
+ private:
+ TQ_UINT16* m_bufferCb;
+ TQ_UINT16* m_bufferCr;
+ TQ_UINT32 m_bufferWidth, m_bufferHeight;
+ uint16 m_hsub;
+ uint16 m_vsub;
+ KisTIFFYCbCr::Position m_position;
+
+};
+
+
+#endif
diff --git a/filters/chalk/tiff/kis_wdg_options_tiff.ui b/filters/chalk/tiff/kis_wdg_options_tiff.ui
new file mode 100644
index 00000000..3ffc1bd4
--- /dev/null
+++ b/filters/chalk/tiff/kis_wdg_options_tiff.ui
@@ -0,0 +1,741 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KisWdgOptionsTIFF</class>
+<widget class="TQWidget">
+ <property name="name">
+ <cstring>KisWdgOptionsTIFF</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>452</width>
+ <height>267</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="caption">
+ <string>Options of Your TIFF</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="TQGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>TIFF Options</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>tqlayout10</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Compression type:</string>
+ </property>
+ </widget>
+ <widget class="KComboBox">
+ <item>
+ <property name="text">
+ <string>None</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>JPEG DCT Compression</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Deflate (ZIP)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Lempel-Ziv &amp; Welch (LZW)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Leadtools JPEG2000</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>CCITT Modified Huffman RLE</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>CCITT Group 3 Fax Encoding</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>CCITT Group 4 Fax Encoding</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Pixar Log</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kComboBoxCompressionType</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>tqlayout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Predictor:</string>
+ </property>
+ </widget>
+ <widget class="KComboBox">
+ <item>
+ <property name="text">
+ <string>None</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Horizontal Differencing</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Floating PointQt::Horizontal Differencing</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kComboBoxPredictor</cstring>
+ </property>
+ <property name="currentItem">
+ <number>0</number>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Using a predictor can improve the compression (mostly for LZW and deflate)</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="TQCheckBox">
+ <property name="name">
+ <cstring>alpha</cstring>
+ </property>
+ <property name="text">
+ <string>Store alpha &amp;channel (transparency)</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Disable to get smaller files if your image has no transparancy</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;The Portable Network Graphics (PNG) file format allows transparancy in your image to be stored by saving an alpha channel.
+You can uncheck the box if you are not using transparancy and you want to make the resulting file smaller .&lt;br&gt;Always saving the alpha channel is recommended.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="TQCheckBox">
+ <property name="name">
+ <cstring>flatten</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Flatten the &amp;image</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>This option will merge all layers. It is advisable to check this option, otherwise other applications might not be able to read your file correctly.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="TQWidgetStack">
+ <property name="name">
+ <cstring>codecsOptionsStack</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <widget class="TQWidget">
+ <property name="name">
+ <cstring>WStackPage</cstring>
+ </property>
+ <attribute name="id">
+ <number>0</number>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="TQFrame">
+ <property name="name">
+ <cstring>frame4</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="TQWidget">
+ <property name="name">
+ <cstring>WStackPage</cstring>
+ </property>
+ <attribute name="id">
+ <number>1</number>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="TQGroupBox">
+ <property name="name">
+ <cstring>groupBoxJPEG</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>JPEG Compression Options</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Quality:</string>
+ </property>
+ <property name="tqalignment">
+ <set>AlignTop</set>
+ </property>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>tqlayout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQSlider">
+ <property name="name">
+ <cstring>qualityLevel</cstring>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="lineStep">
+ <number>1</number>
+ </property>
+ <property name="pageStep">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>80</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="tickmarks">
+ <enum>Both</enum>
+ </property>
+ <property name="tickInterval">
+ <number>10</number>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>These settings determine how much information is lost during compression</string>
+ </property>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>tqlayout4_2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Smallest</string>
+ </property>
+ </widget>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Best</string>
+ </property>
+ <property name="tqalignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="TQWidget">
+ <property name="name">
+ <cstring>WStackPage</cstring>
+ </property>
+ <attribute name="id">
+ <number>2</number>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="TQGroupBox">
+ <property name="name">
+ <cstring>groupBoxDeflate</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Deflate Compression Options</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>Compress:</string>
+ </property>
+ <property name="tqalignment">
+ <set>AlignTop</set>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Note: the compression level does not change the quality of the result</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Adjust the compression time. Better compression takes longer.
+&lt;br&gt;Note: the compression level does not change the quality of the result.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>tqlayout5_2</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQSlider">
+ <property name="name">
+ <cstring>compressionLevelDeflate</cstring>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="maxValue">
+ <number>9</number>
+ </property>
+ <property name="pageStep">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>6</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="tickmarks">
+ <enum>Both</enum>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Note: the compression level doesn't change the quality of the result</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Adjust the compression time. Better compression takes longer.
+&lt;br&gt;Note: the compression level doesn't change the quality of the result.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>tqlayout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Fast</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Adjust the compression time. Better compression takes longer.
+&lt;br&gt;Note: the compression level doesn't change the quality of the result.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel4_2</cstring>
+ </property>
+ <property name="text">
+ <string>Small</string>
+ </property>
+ <property name="tqalignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Adjust the compression time. Better compression takes longer.
+&lt;br&gt;Note: the compression level doesn't change the quality of the result.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="TQWidget">
+ <property name="name">
+ <cstring>WStackPage</cstring>
+ </property>
+ <attribute name="id">
+ <number>3</number>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="TQGroupBox">
+ <property name="name">
+ <cstring>groupBoxCCITGroupCCITG3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>CCITT Group 3 fax encoding Options</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Fax mode:</string>
+ </property>
+ </widget>
+ <widget class="KComboBox">
+ <item>
+ <property name="text">
+ <string>Classic</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>No RTC</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>No EOL</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kComboBoxFaxMode</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="TQWidget">
+ <property name="name">
+ <cstring>WStackPage</cstring>
+ </property>
+ <attribute name="id">
+ <number>4</number>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="TQGroupBox">
+ <property name="name">
+ <cstring>groupBoxPixarLog</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Pixar Log Compression Options</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel1_4_2</cstring>
+ </property>
+ <property name="text">
+ <string>Compress:</string>
+ </property>
+ <property name="tqalignment">
+ <set>AlignTop</set>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Note: the compression level does not change the quality of the result</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Adjust the compression time. Better compression takes longer.
+&lt;br&gt;Note: the compression level does not change the quality of the result.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>tqlayout5_2_2</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQSlider">
+ <property name="name">
+ <cstring>compressionLevelPixarLog</cstring>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="maxValue">
+ <number>9</number>
+ </property>
+ <property name="pageStep">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>6</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="tickmarks">
+ <enum>Both</enum>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Note: the compression level doesn't change the quality of the result</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Adjust the compression time. Better compression takes longer.
+&lt;br&gt;Note: the compression level doesn't change the quality of the result.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>tqlayout4_3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel3_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Fast</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Adjust the compression time. Better compression takes longer.
+&lt;br&gt;Note: the compression level doesn't change the quality of the result.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>textLabel4_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Small</string>
+ </property>
+ <property name="tqalignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Adjust the compression time. Better compression takes longer.
+&lt;br&gt;Note: the compression level doesn't change the quality of the result.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ </hbox>
+ </widget>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="tqsizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<tabstops>
+ <tabstop>kComboBoxCompressionType</tabstop>
+ <tabstop>kComboBoxPredictor</tabstop>
+ <tabstop>alpha</tabstop>
+ <tabstop>flatten</tabstop>
+ <tabstop>qualityLevel</tabstop>
+ <tabstop>compressionLevelDeflate</tabstop>
+ <tabstop>kComboBoxFaxMode</tabstop>
+ <tabstop>compressionLevelPixarLog</tabstop>
+</tabstops>
+<tqlayoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kcombobox.h</includehint>
+</includehints>
+</UI>
diff --git a/filters/chalk/tiff/kis_ycbcr_colorspace.h b/filters/chalk/tiff/kis_ycbcr_colorspace.h
new file mode 100644
index 00000000..05220127
--- /dev/null
+++ b/filters/chalk/tiff/kis_ycbcr_colorspace.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KIS_YCBCR_COLORSPACE_H
+#define KIS_YCBCR_COLORSPACE_H
+namespace {
+ const TQ_INT32 MAX_CHANNEL_YCbCr = 3;
+ const TQ_INT32 MAX_CHANNEL_YCbCrA = 4;
+}
+#endif
+
diff --git a/filters/chalk/xcf/Makefile.am b/filters/chalk/xcf/Makefile.am
new file mode 100644
index 00000000..88822a23
--- /dev/null
+++ b/filters/chalk/xcf/Makefile.am
@@ -0,0 +1,42 @@
+kde_module_LTLIBRARIES = libchalkxcfimport.la libchalkxcfexport.la
+
+libchalkxcfexport_la_LDFLAGS = $(KDE_PLUGIN) $(LIBMAGICK_LDFLAGS) $(KDE_RPATH) $(LIBMAGICK_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalkxcfexport_la_LIBADD = \
+ $(KOFFICE_LIBS) \
+ $(LIBMAGICK_LIBS) \
+ $(top_builddir)/chalk/libchalkcommon.la
+
+libchalkxcfimport_la_LDFLAGS = $(KDE_PLUGIN) $(LIBMAGICK_LDFLAGS) $(KDE_RPATH) $(LIBMAGICK_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \
+ -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \
+ -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor
+libchalkxcfimport_la_LIBADD = \
+ $(KOFFICE_LIBS) \
+ $(LIBMAGICK_LIBS) \
+ $(top_builddir)/chalk/libchalkcommon.la
+
+INCLUDES= \
+ -I$(srcdir) \
+ $(KOFFICE_INCLUDES) \
+ -I$(top_srcdir)/chalk \
+ -I$(top_srcdir)/chalk/core \
+ -I$(top_srcdir)/chalk/sdk \
+ -I$(top_srcdir)/chalk/core/tiles \
+ -I$(top_srcdir)/chalk/chalkcolor \
+ -I$(top_srcdir)/chalk/ui \
+ $(KOFFICE_INCLUDES) -I$(interfacedir) \
+ $(KOPAINTER_INCLUDES) $(LIBMAGICK_CPPFLAGS) \
+ $(all_includes)
+
+service_DATA = chalk_xcf_import.desktop chalk_xcf_export.desktop
+servicedir = $(kde_servicesdir)
+
+libchalkxcfimport_la_SOURCES = xcfimport.cpp
+libchalkxcfexport_la_SOURCES = xcfexport.cpp
+
+METASOURCES = AUTO
+
+SUBDIRS=xcf
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
diff --git a/filters/chalk/xcf/chalk_xcf_export.desktop b/filters/chalk/xcf/chalk_xcf_export.desktop
new file mode 100644
index 00000000..b88afaed
--- /dev/null
+++ b/filters/chalk/xcf/chalk_xcf_export.desktop
@@ -0,0 +1,52 @@
+[Desktop Entry]
+Name=Chalk XCF Export Filter
+Name[bg]=Филтър за експортиране от Chalk в XCF
+Name[br]=Sil ezporzh XCF evit Chalk
+Name[ca]=Filtre d'exportació XCF per a Chalk
+Name[cy]=Hidl Allforio XCF Chalk
+Name[da]=Chalk XCF-eksportfilter
+Name[de]=Chalk XCF-Exportfilter
+Name[el]=Φίλτρο εξαγωγής XCF του Chalk
+Name[eo]=Chalk XCF-importfiltrilo
+Name[es]=Filtro de exportación a XCF de Chalk
+Name[et]=Chalk XCF-i ekspordifilter
+Name[fa]=پالایۀ صادرات Chalk XCF
+Name[fi]=Chalk XCF -vientisuodin
+Name[fr]=Filtre d'exportation XCF de Chalk
+Name[fy]=Chalk XCF Eksportfilter
+Name[ga]=Scagaire Easpórtála XCF Chalk
+Name[gl]=Filtro de Exportación de XCF para Chalk
+Name[he]=Chalk XCF מסנן יצוא
+Name[hr]=Chalk XCF filtar izvoza
+Name[hu]=Chalk XCF exportszűrő
+Name[is]=Chalk XCF útflutningssía
+Name[it]=Filtro di esportazione XCF per Chalk
+Name[ja]=Chalk XCF エクスポートフィルタ
+Name[km]=តម្រង​នាំចេញ XCF សម្រាប់ Chalk
+Name[lt]=Chalk XCF eksportavimo filtras
+Name[lv]=Chalk XCF eksporta filtrs
+Name[nb]=XCF-eksportfilter for Chalk
+Name[nds]=XCF-Exportfilter för Chalk
+Name[ne]=क्रिता XFC निर्यात फिल्टर
+Name[nl]=Chalk XCF Exportfilter
+Name[pl]=Filtr eksportu do formatu XCF dla Chalk
+Name[pt]=Filtro de Exportação de XCF para o Chalk
+Name[pt_BR]=Filtro de Exportação de XCF para o Chalk
+Name[ru]=Фильтр экспорта рисунков Chalk в XCF
+Name[se]=Chalk XCF-olggosfievrridansilli
+Name[sk]=Exportný filter Chalk XCF
+Name[sl]=Izvozni filter XCF za Krito
+Name[sr]=Chalk-ин филтер за извоз у XCF
+Name[sr@Latn]=Chalk-in filter za izvoz u XCF
+Name[sv]=Chalk XCF-exportfilter
+Name[uk]=Фільтр експорту XCF для Chalk
+Name[uz]=Chalk XCF eksport filteri
+Name[uz@cyrillic]=Chalk XCF экспорт филтери
+Name[zh_CN]=Chalk XCF 导出过滤器
+Name[zh_TW]=Chalk XCF 匯出過濾程式
+X-KDE-Export=image/x-xcf-gimp
+ServiceTypes=KOfficeFilter
+Type=Service
+X-KDE-Import=application/x-chalk
+X-KDE-Weight=1
+X-KDE-Library=libchalkxcfexport
diff --git a/filters/chalk/xcf/chalk_xcf_import.desktop b/filters/chalk/xcf/chalk_xcf_import.desktop
new file mode 100644
index 00000000..b2e68d13
--- /dev/null
+++ b/filters/chalk/xcf/chalk_xcf_import.desktop
@@ -0,0 +1,52 @@
+[Desktop Entry]
+Type=Service
+Name=Chalk XCF Import Filter
+Name[bg]=Филтър за импортиране от XCF в Chalk
+Name[br]=Sil enporzh XCF evit Chalk
+Name[ca]=Filtre d'importació XCF per a Chalk
+Name[cy]=Hidl Mewnforio XCF Chalk
+Name[da]=Chalk XCF-importfilter
+Name[de]=Chalk XCF-Importfilter
+Name[el]=Φίλτρο εισαγωγής XCF του Chalk
+Name[eo]=Chalk XCF-importfiltrilo
+Name[es]=Filtro de importación a XCF de Chalk
+Name[et]=Chalk XCF-i impordifilter
+Name[fa]=پالایۀ واردات Chalk XCF
+Name[fi]=Chalk XCF -tuontisuodin
+Name[fr]=Filtre d'importation XCF de Chalk
+Name[fy]=Chalk XCF Ymportfilter
+Name[ga]=Scagaire Iompórtála XCF Chalk
+Name[gl]=Filtro de Importación de XCF para Chalk
+Name[he]=Chalk XCF מסנן יבוא
+Name[hr]=Chalk XCF filtar uvoza
+Name[hu]=Chalk XCF importszűrő
+Name[is]=Chalk XCF innflutningssía
+Name[it]=Filtro di importazione XCF per Chalk
+Name[ja]=Chalk XCF インポートフィルタ
+Name[km]=តម្រង​នាំចូល XCF សម្រាប់ Chalk
+Name[lt]=Chalk XCF importavimo filtras
+Name[lv]=Chalk XCF importa filtrs
+Name[nb]=XCF-importfilter for Chalk
+Name[nds]=XCF-Importfilter för Chalk
+Name[ne]=क्रिता XCF आयात फिल्टर
+Name[nl]=Chalk XCF Importfilter
+Name[pl]=Filtr importu formatu XCF dla Chalk
+Name[pt]=Filtro de Importação de XCF para o Chalk
+Name[pt_BR]=Filtro de Importação de XCF para o Chalk
+Name[ru]=Фильтр импорта рисунков XCF в Chalk
+Name[se]=Chalk XCF-sisafievrridansilli
+Name[sk]=XCF filter pre import do Chalk
+Name[sl]=Uvozni filter XCF za Krito
+Name[sr]=Chalk-ин филтер за увоз из XCF-а
+Name[sr@Latn]=Chalk-in filter za uvoz iz XCF-a
+Name[sv]=Chalk XCF-importfilter
+Name[uk]=Фільтр імпорту XCF для Chalk
+Name[uz]=Chalk XCF import filteri
+Name[uz@cyrillic]=Chalk XCF импорт филтери
+Name[zh_CN]=Chalk XCF 导入过滤器
+Name[zh_TW]=Chalk XCF 匯入過濾程式
+X-KDE-Export=application/x-chalk
+X-KDE-Import=image/x-xcf-gimp
+X-KDE-Weight=1
+X-KDE-Library=libchalkxcfimport
+ServiceTypes=KOfficeFilter
diff --git a/filters/chalk/xcf/xcf/README b/filters/chalk/xcf/xcf/README
new file mode 100644
index 00000000..567d2ab1
--- /dev/null
+++ b/filters/chalk/xcf/xcf/README
@@ -0,0 +1,2 @@
+Note: this is source copy of 6 feb. 2006; when updated, use a diff from the gimp cvs
+to check for changes in their file format.
diff --git a/filters/chalk/xcf/xcf/xcf-load.cc b/filters/chalk/xcf/xcf/xcf-load.cc
new file mode 100644
index 00000000..07b6a145
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-load.cc
@@ -0,0 +1,1740 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h> /* strcmp, memcmp */
+
+//#include <glib-object.h>
+
+//#include "libgimpbase/gimpbase.h"
+//#include "libgimpcolor/gimpcolor.h"
+
+//#include "core/core-types.h"
+
+//#include "base/tile.h"
+//#include "base/tile-manager.h"
+//#include "base/tile-manager-private.h"
+
+//#include "config/gimpcoreconfig.h"
+
+//#include "core/gimp.h"
+//#include "core/gimpcontainer.h"
+//#include "core/gimpdrawable.h"
+//#include "core/gimpgrid.h"
+//#include "core/gimpimage.h"
+//#include "core/gimpimage-grid.h"
+//#include "core/gimpimage-guides.h"
+//#include "core/gimplayer.h"
+//#include "core/gimplayer-floating-sel.h"
+//#include "core/gimplayertqmask.h"
+//#include "core/gimpparasitelist.h"
+//#include "core/gimpselection.h"
+//#include "core/gimptemplate.h"
+//#include "core/gimpunit.h"
+
+//#include "text/gimptextlayer.h"
+//#include "text/gimptextlayer-xcf.h"
+
+//#include "vectors/gimpanchor.h"
+//#include "vectors/gimpstroke.h"
+//#include "vectors/gimpbezierstroke.h"
+//#include "vectors/gimpvectors.h"
+//#include "vectors/gimpvectors-compat.h"
+
+#include "xcf-private.h"
+#include "xcf-load.h"
+#include "xcf-read.h"
+#include "xcf-seek.h"
+
+//#include "gimp-intl.h"
+
+static bool xcf_load_image_props (XcfInfo * info, KisImage * gimage);
+static bool xcf_load_layer_props (XcfInfo * info,
+ KisImage * gimage,
+ KisLayer * layer,
+ bool * apply_tqmask,
+ bool * edit_tqmask,
+ bool * show_tqmask,
+ TQ_INT32 * text_layer_flags);
+static bool xcf_load_channel_props (XcfInfo * info,
+ KisImage * gimage,
+ GimpChannel ** channel);
+static bool xcf_load_prop (XcfInfo * info,
+ PropType * prop_type, TQ_INT32 * prop_size);
+static KisLayer *xcf_load_layer (XcfInfo * info, KisImage * gimage);
+//static GimpChannel * xcf_load_channel (XcfInfo *info,
+// KisImage *gimage);
+//static GimpLayerMask * xcf_load_layer_tqmask (XcfInfo *info,
+// KisImage *gimage);
+static bool xcf_load_hierarchy (XcfInfo * info, TileManager * tiles);
+static bool xcf_load_level (XcfInfo * info, TileManager * tiles);
+static bool xcf_load_tile (XcfInfo * info, Tile * tile);
+static bool xcf_load_tile_rle (XcfInfo * info,
+ Tile * tile, TQ_INT32 data_length);
+//static GimpParasite * xcf_load_parasite (XcfInfo *info);
+static bool xcf_load_old_paths (XcfInfo * info, KisImage * gimage);
+static bool xcf_load_old_path (XcfInfo * info, KisImage * gimage);
+static bool xcf_load_vectors (XcfInfo * info, KisImage * gimage);
+static bool xcf_load_vector (XcfInfo * info, KisImage * gimage);
+
+#ifdef SWAP_FROM_FILE
+static bool xcf_swap_func (TQ_INT32 fd,
+ Tile * tile, TQ_INT32 cmd, gpointer user_data);
+#endif
+
+
+KisImage *
+xcf_load_image (XcfInfo * info)
+{
+ KisImage *gimage;
+ KisLayer *layer;
+ //GimpChannel *channel;
+ //KisAnnotation *parasite;
+ TQ_INT32 saved_pos;
+ TQ_INT32 offset;
+ TQ_INT32 width;
+ TQ_INT32 height;
+ TQ_INT32 image_type;
+ TQ_INT32 num_successful_elements = 0;
+
+ /* read in the image width, height and type */
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & width, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & height, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & image_type, 1);
+
+ gimage = gimp_create_image (gimp, width, height, image_type, FALSE);
+
+ gimp_image_undo_disable (gimage);
+
+ /* read the image properties */
+ if (!xcf_load_image_props (info, gimage))
+ goto hard_error;
+
+ /* check for a GimpGrid parasite */
+ parasite = gimp_image_parasite_tqfind (GIMP_IMAGE (gimage),
+ gimp_grid_parasite_name ());
+ if (parasite)
+ {
+ GimpGrid *grid = gimp_grid_from_parasite (parasite);
+
+ if (grid)
+ {
+ gimp_parasite_list_remove (GIMP_IMAGE (gimage)->parasites,
+ gimp_parasite_name (parasite));
+
+ gimp_image_set_grid (GIMP_IMAGE (gimage), grid, FALSE);
+ }
+ }
+
+ while (TRUE)
+ {
+ /* read in the offset of the next layer */
+ info->cp += xcf_read_int32 (info->fp, &offset, 1);
+
+ /* if the offset is 0 then we are at the end
+ * of the layer list.
+ */
+ if (offset == 0)
+ break;
+
+ /* save the current position as it is where the
+ * next layer offset is stored.
+ */
+ saved_pos = info->cp;
+
+ /* seek to the layer offset */
+ if (!xcf_seek_pos (info, offset, NULL))
+ goto error;
+
+ /* read in the layer */
+ layer = xcf_load_layer (info, gimage);
+ if (!layer)
+ goto error;
+
+ num_successful_elements++;
+
+ /* add the layer to the image if its not the floating selection */
+ if (layer != info->floating_sel)
+ gimp_image_add_layer (gimage, layer,
+ gimp_container_num_tqchildren (gimage->layers));
+
+ /* restore the saved position so we'll be ready to
+ * read the next offset.
+ */
+ if (!xcf_seek_pos (info, saved_pos, NULL))
+ goto error;
+ }
+
+ while (TRUE)
+ {
+ /* read in the offset of the next channel */
+ info->cp += xcf_read_int32 (info->fp, &offset, 1);
+
+ /* if the offset is 0 then we are at the end
+ * of the channel list.
+ */
+ if (offset == 0)
+ break;
+
+ /* save the current position as it is where the
+ * next channel offset is stored.
+ */
+ saved_pos = info->cp;
+
+ /* seek to the channel offset */
+ if (!xcf_seek_pos (info, offset, NULL))
+ goto error;
+
+ /* read in the layer */
+ channel = xcf_load_channel (info, gimage);
+ if (!channel)
+ goto error;
+
+ num_successful_elements++;
+
+ /* add the channel to the image if its not the selection */
+ if (channel != gimage->selection_tqmask)
+ gimp_image_add_channel (gimage, channel, -1);
+
+ /* restore the saved position so we'll be ready to
+ * read the next offset.
+ */
+ if (!xcf_seek_pos (info, saved_pos, NULL))
+ goto error;
+ }
+
+ if (info->floating_sel && info->floating_sel_drawable)
+ floating_sel_attach (info->floating_sel, info->floating_sel_drawable);
+
+ if (info->active_layer)
+ gimp_image_set_active_layer (gimage, info->active_layer);
+
+ if (info->active_channel)
+ gimp_image_set_active_channel (gimage, info->active_channel);
+
+ gimp_image_set_filename (gimage, info->filename);
+
+ if (info->tattoo_state > 0)
+ gimp_image_set_tattoo_state (gimage, info->tattoo_state);
+
+ gimp_image_undo_enable (gimage);
+
+ return gimage;
+
+error:
+ if (num_successful_elements == 0)
+ goto hard_error;
+
+ g_message ("XCF: This file is corrupt! I have loaded as much\n"
+ "of it as I can, but it is incomplete.");
+
+ gimp_image_undo_enable (gimage);
+
+ return gimage;
+
+hard_error:
+ g_message ("XCF: This file is corrupt! I could not even\n"
+ "salvage any partial image data from it.");
+
+ g_object_unref (gimage);
+
+ return NULL;
+}
+
+static bool
+xcf_load_image_props (XcfInfo * info, KisImage * gimage)
+{
+ PropType prop_type;
+ TQ_INT32 prop_size;
+
+ while (TRUE)
+ {
+ if (!xcf_load_prop (info, &prop_type, &prop_size))
+ return FALSE;
+
+ switch (prop_type)
+ {
+ case PROP_END:
+ return TRUE;
+
+ case PROP_COLORMAP:
+ if (info->file_version == 0)
+ {
+ TQ_INT32 i;
+
+ g_message (_("XCF warning: version 0 of XCF file format\n"
+ "did not save indexed colormaps correctly.\n"
+ "Substituting grayscale map."));
+ info->cp +=
+ xcf_read_int32 (info->fp, (TQ_INT32 *) & gimage->num_cols, 1);
+ gimage->cmap = g_new (guchar, gimage->num_cols * 3);
+ if (!xcf_seek_pos (info, info->cp + gimage->num_cols, NULL))
+ return FALSE;
+
+ for (i = 0; i < gimage->num_cols; i++)
+ {
+ gimage->cmap[i * 3 + 0] = i;
+ gimage->cmap[i * 3 + 1] = i;
+ gimage->cmap[i * 3 + 2] = i;
+ }
+ }
+ else
+ {
+ info->cp +=
+ xcf_read_int32 (info->fp, (TQ_INT32 *) & gimage->num_cols, 1);
+ gimage->cmap = g_new (guchar, gimage->num_cols * 3);
+ info->cp +=
+ xcf_read_int8 (info->fp,
+ (TQ_UINT8 *) gimage->cmap,
+ gimage->num_cols * 3);
+ }
+
+ /* discard color map, if image is not indexed, this is just
+ * sanity checking to make sure gimp doesn't end up with an
+ * image state that is impossible.
+ */
+ if (gimp_image_base_type (gimage) != GIMP_INDEXED)
+ {
+ g_free (gimage->cmap);
+ gimage->cmap = NULL;
+ gimage->num_cols = 0;
+ }
+ break;
+
+ case PROP_COMPRESSION:
+ {
+ TQ_UINT8 compression;
+
+ info->cp +=
+ xcf_read_int8 (info->fp, (TQ_UINT8 *) & compression, 1);
+
+ if ((compression != COMPRESS_NONE) &&
+ (compression != COMPRESS_RLE) &&
+ (compression != COMPRESS_ZLIB) &&
+ (compression != COMPRESS_FRACTAL))
+ {
+ g_message ("unknown compression type: %d", (int) compression);
+ return FALSE;
+ }
+
+ info->compression = compression;
+ }
+ break;
+
+ case PROP_GUIDES:
+ {
+ TQ_INT3232 position;
+ TQ_INT328 orientation;
+ TQ_INT32 i, nguides;
+
+ nguides = prop_size / (4 + 1);
+ for (i = 0; i < nguides; i++)
+ {
+ info->cp +=
+ xcf_read_int32 (info->fp, (TQ_INT32 *) & position, 1);
+ info->cp +=
+ xcf_read_int8 (info->fp, (TQ_UINT8 *) & orientation, 1);
+
+ /* skip -1 guides from old XCFs */
+ if (position < 0)
+ continue;
+
+ switch (orientation)
+ {
+ case XCF_ORIENTATION_HORIZONTAL:
+ gimp_image_add_hguide (gimage, position, FALSE);
+ break;
+
+ case XCF_ORIENTATION_VERTICAL:
+ gimp_image_add_vguide (gimage, position, FALSE);
+ break;
+
+ default:
+ g_message ("guide orientation out of range in XCF file");
+ continue;
+ }
+ }
+
+ /* this is silly as the order of guides doesn't really matter,
+ * but it restores the list to it's original order, which
+ * cannot be wrong --Mitch
+ */
+ gimage->guides = g_list_reverse (gimage->guides);
+ }
+ break;
+
+ case PROP_RESOLUTION:
+ {
+ float xres, yres;
+
+ info->cp += xcf_read_float (info->fp, &xres, 1);
+ info->cp += xcf_read_float (info->fp, &yres, 1);
+ if (xres < GIMP_MIN_RESOLUTION || xres > GIMP_MAX_RESOLUTION ||
+ yres < GIMP_MIN_RESOLUTION || yres > GIMP_MAX_RESOLUTION)
+ {
+ g_message ("Warning, resolution out of range in XCF file");
+ xres = gimage->gimp->config->default_image->xresolution;
+ yres = gimage->gimp->config->default_image->yresolution;
+ }
+ gimage->xresolution = xres;
+ gimage->yresolution = yres;
+ }
+ break;
+
+ case PROP_TATTOO:
+ {
+ info->cp += xcf_read_int32 (info->fp, &info->tattoo_state, 1);
+ }
+ break;
+
+ case PROP_PARASITES:
+ {
+ glong base = info->cp;
+ KisAnnotation *p;
+
+ while (info->cp - base < prop_size)
+ {
+ p = xcf_load_parasite (info);
+ gimp_image_parasite_attach (gimage, p);
+ gimp_parasite_free (p);
+ }
+ if (info->cp - base != prop_size)
+ g_message ("Error while loading an image's parasites");
+ }
+ break;
+
+ case PROP_UNIT:
+ {
+ TQ_INT32 unit;
+
+ info->cp += xcf_read_int32 (info->fp, &unit, 1);
+
+ if ((unit <= GIMP_UNIT_PIXEL) ||
+ (unit >=
+ _gimp_unit_get_number_of_built_in_units (gimage->gimp)))
+ {
+ g_message ("Warning, unit out of range in XCF file, "
+ "falling back to inches");
+ unit = GIMP_UNIT_INCH;
+ }
+
+ gimage->resolution_unit = unit;
+ }
+ break;
+
+ case PROP_PATHS:
+ xcf_load_old_paths (info, gimage);
+ break;
+
+ case PROP_USER_UNIT:
+ {
+ TQCString *unit_strings[5];
+ float factor;
+ TQ_INT32 digits;
+ GimpUnit unit;
+ TQ_INT32 num_units;
+ TQ_INT32 i;
+
+ info->cp += xcf_read_float (info->fp, &factor, 1);
+ info->cp += xcf_read_int32 (info->fp, &digits, 1);
+ info->cp += xcf_read_string (info->fp, unit_strings, 5);
+
+ for (i = 0; i < 5; i++)
+ if (unit_strings[i] == NULL)
+ unit_strings[i] = g_strdup ("");
+
+ num_units = _gimp_unit_get_number_of_units (gimage->gimp);
+
+ for (unit =
+ _gimp_unit_get_number_of_built_in_units (gimage->gimp);
+ unit < num_units; unit++)
+ {
+ /* if the factor and the identifier match some unit
+ * in unitrc, use the unitrc unit
+ */
+ if ((ABS (_gimp_unit_get_factor (gimage->gimp,
+ unit) - factor) < 1e-5) &&
+ (strcmp (unit_strings[0],
+ _gimp_unit_get_identifier (gimage->gimp,
+ unit)) == 0))
+ {
+ break;
+ }
+ }
+
+ /* no match */
+ if (unit == num_units)
+ unit = _gimp_unit_new (gimage->gimp,
+ unit_strings[0],
+ factor,
+ digits,
+ unit_strings[1],
+ unit_strings[2],
+ unit_strings[3], unit_strings[4]);
+
+ gimage->resolution_unit = unit;
+
+ for (i = 0; i < 5; i++)
+ g_free (unit_strings[i]);
+ }
+ break;
+
+ case PROP_VECTORS:
+ {
+ TQ_INT32 base = info->cp;
+
+ if (xcf_load_vectors (info, gimage))
+ {
+ if (base + prop_size != info->cp)
+ {
+ g_warning
+ ("Mismatch in PROP_VECTORS size: skipping %d bytes.",
+ base + prop_size - info->cp);
+ xcf_seek_pos (info, base + prop_size, NULL);
+ }
+ }
+ else
+ {
+ /* skip silently since we don't understand the format and
+ * xcf_load_vectors already explained what was wrong
+ */
+ xcf_seek_pos (info, base + prop_size, NULL);
+ }
+ }
+ break;
+
+ default:
+#ifdef GIMP_UNSTABLE
+ g_printerr ("unexpected/unknown image property: %d (skipping)",
+ prop_type);
+#endif
+ {
+ TQ_UINT8 buf[16];
+ TQ_UINT32 amount;
+
+ while (prop_size > 0)
+ {
+ amount = MIN (16, prop_size);
+ info->cp += xcf_read_int8 (info->fp, buf, amount);
+ prop_size -= MIN (16, amount);
+ }
+ }
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+static bool
+xcf_load_layer_props (XcfInfo * info,
+ KisImage * gimage,
+ KisLayer * layer,
+ bool * apply_tqmask,
+ bool * edit_tqmask,
+ bool * show_tqmask, TQ_INT32 * text_layer_flags)
+{
+ PropType prop_type;
+ TQ_INT32 prop_size;
+
+ while (TRUE)
+ {
+ if (!xcf_load_prop (info, &prop_type, &prop_size))
+ return FALSE;
+
+ switch (prop_type)
+ {
+ case PROP_END:
+ return TRUE;
+
+ case PROP_ACTIVE_LAYER:
+ info->active_layer = layer;
+ break;
+
+ case PROP_FLOATING_SELECTION:
+ info->floating_sel = layer;
+ info->cp +=
+ xcf_read_int32 (info->fp,
+ (TQ_INT32 *) & info->floating_sel_offset, 1);
+ break;
+
+ case PROP_OPACITY:
+ {
+ TQ_INT32 opacity;
+
+ info->cp += xcf_read_int32 (info->fp, &opacity, 1);
+ layer->opacity = CLAMP ((gdouble) opacity / 255.0,
+ GIMP_OPACITY_TRANSPARENT,
+ GIMP_OPACITY_OPAQUE);
+ }
+ break;
+
+ case PROP_VISIBLE:
+ {
+ bool visible;
+
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & visible, 1);
+ gimp_item_set_visible (GIMP_ITEM (layer),
+ visible ? TRUE : FALSE, FALSE);
+ }
+ break;
+
+ case PROP_LINKED:
+ {
+ bool linked;
+
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & linked, 1);
+ gimp_item_set_linked (GIMP_ITEM (layer),
+ linked ? TRUE : FALSE, FALSE);
+ }
+ break;
+
+ case PROP_LOCK_ALPHA:
+ info->cp +=
+ xcf_read_int32 (info->fp, (TQ_INT32 *) & layer->lock_alpha, 1);
+ break;
+
+ case PROP_APPLY_MASK:
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) apply_tqmask, 1);
+ break;
+
+ case PROP_EDIT_MASK:
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) edit_tqmask, 1);
+ break;
+
+ case PROP_SHOW_MASK:
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) show_tqmask, 1);
+ break;
+
+ case PROP_OFFSETS:
+ info->cp +=
+ xcf_read_int32 (info->fp,
+ (TQ_INT32 *) & GIMP_ITEM (layer)->offset_x, 1);
+ info->cp +=
+ xcf_read_int32 (info->fp,
+ (TQ_INT32 *) & GIMP_ITEM (layer)->offset_y, 1);
+ break;
+
+ case PROP_MODE:
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & layer->mode, 1);
+ break;
+
+ case PROP_TATTOO:
+ info->cp += xcf_read_int32 (info->fp,
+ (TQ_INT32 *) & GIMP_ITEM (layer)->tattoo,
+ 1);
+ break;
+
+ case PROP_PARASITES:
+ {
+ glong base = info->cp;
+ KisAnnotation *p;
+
+ while (info->cp - base < prop_size)
+ {
+ p = xcf_load_parasite (info);
+ gimp_item_parasite_attach (GIMP_ITEM (layer), p);
+ gimp_parasite_free (p);
+ }
+ if (info->cp - base != prop_size)
+ g_message ("Error while loading a layer's parasites");
+ }
+ break;
+
+ case PROP_TEXT_LAYER_FLAGS:
+ info->cp += xcf_read_int32 (info->fp, text_layer_flags, 1);
+ break;
+
+ default:
+ {
+ TQ_UINT8 buf[16];
+ TQ_UINT32 amount;
+
+#ifdef GIMP_UNSTABLE
+ g_printerr ("unexpected/unknown layer property: %d (skipping)",
+ prop_type);
+#endif
+ while (prop_size > 0)
+ {
+ amount = MIN (16, prop_size);
+ info->cp += xcf_read_int8 (info->fp, buf, amount);
+ prop_size -= MIN (16, amount);
+ }
+ }
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+static bool
+xcf_load_channel_props (XcfInfo * info,
+ KisImage * gimage, GimpChannel ** channel)
+{
+ PropType prop_type;
+ TQ_INT32 prop_size;
+
+ while (TRUE)
+ {
+ if (!xcf_load_prop (info, &prop_type, &prop_size))
+ return FALSE;
+
+ switch (prop_type)
+ {
+ case PROP_END:
+ return TRUE;
+
+ case PROP_ACTIVE_CHANNEL:
+ info->active_channel = *channel;
+ break;
+
+ case PROP_SELECTION:
+ g_object_unref (gimage->selection_tqmask);
+ gimage->selection_tqmask =
+ gimp_selection_new (gimage,
+ gimp_item_width (GIMP_ITEM (*channel)),
+ gimp_item_height (GIMP_ITEM (*channel)));
+ g_object_ref (gimage->selection_tqmask);
+ gimp_item_sink (GIMP_ITEM (gimage->selection_tqmask));
+
+ tile_manager_unref (GIMP_DRAWABLE (gimage->selection_tqmask)->tiles);
+ GIMP_DRAWABLE (gimage->selection_tqmask)->tiles =
+ GIMP_DRAWABLE (*channel)->tiles;
+ GIMP_DRAWABLE (*channel)->tiles = NULL;
+ g_object_unref (*channel);
+ *channel = gimage->selection_tqmask;
+ (*channel)->boundary_known = FALSE;
+ (*channel)->bounds_known = FALSE;
+ break;
+
+ case PROP_OPACITY:
+ {
+ TQ_INT32 opacity;
+
+ info->cp += xcf_read_int32 (info->fp, &opacity, 1);
+ (*channel)->color.a = opacity / 255.0;
+ }
+ break;
+
+ case PROP_VISIBLE:
+ {
+ bool visible;
+
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & visible, 1);
+ gimp_item_set_visible (GIMP_ITEM (*channel),
+ visible ? TRUE : FALSE, FALSE);
+ }
+ break;
+
+ case PROP_LINKED:
+ {
+ bool linked;
+
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & linked, 1);
+ gimp_item_set_linked (GIMP_ITEM (*channel),
+ linked ? TRUE : FALSE, FALSE);
+ }
+ break;
+
+ case PROP_SHOW_MASKED:
+ {
+ bool show_tqmasked;
+
+ info->cp +=
+ xcf_read_int32 (info->fp, (TQ_INT32 *) & show_tqmasked, 1);
+ gimp_channel_set_show_tqmasked (*channel, show_tqmasked);
+ }
+ break;
+
+ case PROP_COLOR:
+ {
+ guchar col[3];
+
+ info->cp += xcf_read_int8 (info->fp, (TQ_UINT8 *) col, 3);
+
+ gimp_rgb_set_uchar (&(*channel)->color, col[0], col[1], col[2]);
+ }
+ break;
+
+ case PROP_TATTOO:
+ info->cp +=
+ xcf_read_int32 (info->fp, &GIMP_ITEM (*channel)->tattoo, 1);
+ break;
+
+ case PROP_PARASITES:
+ {
+ glong base = info->cp;
+ KisAnnotation *p;
+
+ while ((info->cp - base) < prop_size)
+ {
+ p = xcf_load_parasite (info);
+ gimp_item_parasite_attach (GIMP_ITEM (*channel), p);
+ gimp_parasite_free (p);
+ }
+ if (info->cp - base != prop_size)
+ g_message ("Error while loading a channel's parasites");
+ }
+ break;
+
+ default:
+#ifdef GIMP_UNSTABLE
+ g_printerr ("unexpected/unknown channel property: %d (skipping)",
+ prop_type);
+#endif
+
+ {
+ TQ_UINT8 buf[16];
+ TQ_UINT32 amount;
+
+ while (prop_size > 0)
+ {
+ amount = MIN (16, prop_size);
+ info->cp += xcf_read_int8 (info->fp, buf, amount);
+ prop_size -= MIN (16, amount);
+ }
+ }
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+static bool
+xcf_load_prop (XcfInfo * info, PropType * prop_type, TQ_INT32 * prop_size)
+{
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) prop_type, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) prop_size, 1);
+ return TRUE;
+}
+
+static KisLayer *
+xcf_load_layer (XcfInfo * info, KisImage * gimage)
+{
+ KisLayer *layer;
+ GimpLayerMask *layer_tqmask;
+ TQ_INT32 hierarchy_offset;
+ TQ_INT32 layer_tqmask_offset;
+ bool apply_tqmask = TRUE;
+ bool edit_tqmask = FALSE;
+ bool show_tqmask = FALSE;
+ bool active;
+ bool floating;
+ TQ_INT32 text_layer_flags = 0;
+ TQ_INT32 width;
+ TQ_INT32 height;
+ TQ_INT32 type;
+ bool is_fs_drawable;
+ TQCString *name;
+
+ /* check and see if this is the drawable the floating selection
+ * is attached to. if it is then we'll do the attachment in our caller.
+ */
+ is_fs_drawable = (info->cp == info->floating_sel_offset);
+
+ /* read in the layer width, height, type and name */
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & width, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & height, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & type, 1);
+ info->cp += xcf_read_string (info->fp, &name, 1);
+
+ /* create a new layer */
+ layer = gimp_layer_new (gimage, width, height,
+ type, name, 255, GIMP_NORMAL_MODE);
+ g_free (name);
+ if (!layer)
+ return NULL;
+
+ /* read in the layer properties */
+ if (!xcf_load_layer_props (info, gimage, layer,
+ &apply_tqmask, &edit_tqmask, &show_tqmask,
+ &text_layer_flags))
+ goto error;
+
+ /* call the evil text layer hack that might change our layer pointer */
+ active = (info->active_layer == layer);
+ floating = (info->floating_sel == layer);
+
+ if (gimp_text_layer_xcf_load_hack (&layer))
+ {
+ gimp_text_layer_set_xcf_flags (GIMP_TEXT_LAYER (layer),
+ text_layer_flags);
+
+ if (active)
+ info->active_layer = layer;
+ if (floating)
+ info->floating_sel = layer;
+ }
+
+ /* read the hierarchy and layer tqmask offsets */
+ info->cp += xcf_read_int32 (info->fp, &hierarchy_offset, 1);
+ info->cp += xcf_read_int32 (info->fp, &layer_tqmask_offset, 1);
+
+ /* read in the hierarchy */
+ if (!xcf_seek_pos (info, hierarchy_offset, NULL))
+ goto error;
+
+ if (!xcf_load_hierarchy (info, GIMP_DRAWABLE (layer)->tiles))
+ goto error;
+
+ /* read in the layer tqmask */
+ if (layer_tqmask_offset != 0)
+ {
+ if (!xcf_seek_pos (info, layer_tqmask_offset, NULL))
+ goto error;
+
+ layer_tqmask = xcf_load_layer_tqmask (info, gimage);
+ if (!layer_tqmask)
+ goto error;
+
+ layer_tqmask->apply_tqmask = apply_tqmask;
+ layer_tqmask->edit_tqmask = edit_tqmask;
+ layer_tqmask->show_tqmask = show_tqmask;
+
+ gimp_layer_add_tqmask (layer, layer_tqmask, FALSE);
+ }
+
+ /* attach the floating selection... */
+ if (is_fs_drawable)
+ info->floating_sel_drawable = GIMP_DRAWABLE (layer);
+
+ return layer;
+
+error:
+ g_object_unref (layer);
+ return NULL;
+}
+
+static GimpChannel *
+xcf_load_channel (XcfInfo * info, KisImage * gimage)
+{
+ GimpChannel *channel;
+ TQ_INT32 hierarchy_offset;
+ TQ_INT32 width;
+ TQ_INT32 height;
+ bool is_fs_drawable;
+ TQCString *name;
+ GimpRGB color = { 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE };
+
+ /* check and see if this is the drawable the floating selection
+ * is attached to. if it is then we'll do the attachment in our caller.
+ */
+ is_fs_drawable = (info->cp == info->floating_sel_offset);
+
+ /* read in the layer width, height and name */
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & width, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & height, 1);
+ info->cp += xcf_read_string (info->fp, &name, 1);
+
+ /* create a new channel */
+ channel = gimp_channel_new (gimage, width, height, name, &color);
+ g_free (name);
+ if (!channel)
+ return NULL;
+
+ /* read in the channel properties */
+ if (!xcf_load_channel_props (info, gimage, &channel))
+ goto error;
+
+ /* read the hierarchy and layer tqmask offsets */
+ info->cp += xcf_read_int32 (info->fp, &hierarchy_offset, 1);
+
+ /* read in the hierarchy */
+ if (!xcf_seek_pos (info, hierarchy_offset, NULL))
+ goto error;
+
+ if (!xcf_load_hierarchy (info, GIMP_DRAWABLE (channel)->tiles))
+ goto error;
+
+ if (is_fs_drawable)
+ info->floating_sel_drawable = GIMP_DRAWABLE (channel);
+
+ return channel;
+
+error:
+ g_object_unref (channel);
+ return NULL;
+}
+
+static GimpLayerMask *
+xcf_load_layer_tqmask (XcfInfo * info, KisImage * gimage)
+{
+ GimpLayerMask *layer_tqmask;
+ GimpChannel *channel;
+ TQ_INT32 hierarchy_offset;
+ TQ_INT32 width;
+ TQ_INT32 height;
+ bool is_fs_drawable;
+ TQCString *name;
+ GimpRGB color = { 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE };
+
+ /* check and see if this is the drawable the floating selection
+ * is attached to. if it is then we'll do the attachment in our caller.
+ */
+ is_fs_drawable = (info->cp == info->floating_sel_offset);
+
+ /* read in the layer width, height and name */
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & width, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & height, 1);
+ info->cp += xcf_read_string (info->fp, &name, 1);
+
+ /* create a new layer tqmask */
+ layer_tqmask = gimp_layer_tqmask_new (gimage, width, height, name, &color);
+ g_free (name);
+ if (!layer_tqmask)
+ return NULL;
+
+ /* read in the layer_tqmask properties */
+ channel = GIMP_CHANNEL (layer_tqmask);
+ if (!xcf_load_channel_props (info, gimage, &channel))
+ goto error;
+
+ /* read the hierarchy and layer tqmask offsets */
+ info->cp += xcf_read_int32 (info->fp, &hierarchy_offset, 1);
+
+ /* read in the hierarchy */
+ if (!xcf_seek_pos (info, hierarchy_offset, NULL))
+ goto error;
+
+ if (!xcf_load_hierarchy (info, GIMP_DRAWABLE (layer_tqmask)->tiles))
+ goto error;
+
+ /* attach the floating selection... */
+ if (is_fs_drawable)
+ info->floating_sel_drawable = GIMP_DRAWABLE (layer_tqmask);
+
+ return layer_tqmask;
+
+error:
+ g_object_unref (layer_tqmask);
+ return NULL;
+}
+
+static bool
+xcf_load_hierarchy (XcfInfo * info, TileManager * tiles)
+{
+ TQ_INT32 saved_pos;
+ TQ_INT32 offset;
+ TQ_INT32 junk;
+ TQ_INT32 width;
+ TQ_INT32 height;
+ TQ_INT32 bpp;
+
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & width, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & height, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & bpp, 1);
+
+ /* make sure the values in the file correspond to the values
+ * calculated when the TileManager was created.
+ */
+ if (width != tile_manager_width (tiles) ||
+ height != tile_manager_height (tiles) ||
+ bpp != tile_manager_bpp (tiles))
+ return FALSE;
+
+ /* load in the levels...we make sure that the number of levels
+ * calculated when the TileManager was created is the same
+ * as the number of levels found in the file.
+ */
+
+ info->cp += xcf_read_int32 (info->fp, &offset, 1); /* top level */
+
+ /* discard offsets for layers below first, if any.
+ */
+ do
+ {
+ info->cp += xcf_read_int32 (info->fp, &junk, 1);
+ }
+ while (junk != 0);
+
+ /* save the current position as it is where the
+ * next level offset is stored.
+ */
+ saved_pos = info->cp;
+
+ /* seek to the level offset */
+ if (!xcf_seek_pos (info, offset, NULL))
+ return FALSE;
+
+ /* read in the level */
+ if (!xcf_load_level (info, tiles))
+ return FALSE;
+
+ /* restore the saved position so we'll be ready to
+ * read the next offset.
+ */
+ if (!xcf_seek_pos (info, saved_pos, NULL))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static bool
+xcf_load_level (XcfInfo * info, TileManager * tiles)
+{
+ TQ_INT32 saved_pos;
+ TQ_INT32 offset, offset2;
+ TQ_UINT32 ntiles;
+ TQ_INT32 width;
+ TQ_INT32 height;
+ TQ_INT32 i;
+ TQ_INT32 fail;
+ Tile *previous;
+ Tile *tile;
+
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & width, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & height, 1);
+
+ if (width != tile_manager_width (tiles) ||
+ height != tile_manager_height (tiles))
+ return FALSE;
+
+ /* read in the first tile offset.
+ * if it is '0', then this tile level is empty
+ * and we can simply return.
+ */
+ info->cp += xcf_read_int32 (info->fp, &offset, 1);
+ if (offset == 0)
+ return TRUE;
+
+ /* Initialise the reference for the in-memory tile-compression
+ */
+ previous = NULL;
+
+ ntiles = tiles->ntile_rows * tiles->ntile_cols;
+ for (i = 0; i < ntiles; i++)
+ {
+ fail = FALSE;
+
+ if (offset == 0)
+ {
+ g_message ("not enough tiles found in level");
+ return FALSE;
+ }
+
+ /* save the current position as it is where the
+ * next tile offset is stored.
+ */
+ saved_pos = info->cp;
+
+ /* read in the offset of the next tile so we can calculate the amount
+ of data needed for this tile */
+ info->cp += xcf_read_int32 (info->fp, &offset2, 1);
+
+ /* if the offset is 0 then we need to read in the maximum possible
+ allowing for negative compression */
+ if (offset2 == 0)
+ offset2 = offset + TILE_WIDTH * TILE_WIDTH * 4 * 1.5;
+ /* 1.5 is probably more
+ than we need to allow */
+
+ /* seek to the tile offset */
+ if (!xcf_seek_pos (info, offset, NULL))
+ return FALSE;
+
+ /* get the tile from the tile manager */
+ tile = tile_manager_get (tiles, i, TRUE, TRUE);
+
+ /* read in the tile */
+ switch (info->compression)
+ {
+ case COMPRESS_NONE:
+ if (!xcf_load_tile (info, tile))
+ fail = TRUE;
+ break;
+ case COMPRESS_RLE:
+ if (!xcf_load_tile_rle (info, tile, offset2 - offset))
+ fail = TRUE;
+ break;
+ case COMPRESS_ZLIB:
+ g_error ("xcf: zlib compression unimplemented");
+ fail = TRUE;
+ break;
+ case COMPRESS_FRACTAL:
+ g_error ("xcf: fractal compression unimplemented");
+ fail = TRUE;
+ break;
+ }
+
+ if (fail)
+ {
+ tile_release (tile, TRUE);
+ return FALSE;
+ }
+
+ /* To potentially save memory, we compare the
+ * newly-fetched tile against the last one, and
+ * if they're the same we copy-on-write mirror one against
+ * the other.
+ */
+ if (previous != NULL)
+ {
+ tile_lock (previous);
+ if (tile_ewidth (tile) == tile_ewidth (previous) &&
+ tile_eheight (tile) == tile_eheight (previous) &&
+ tile_bpp (tile) == tile_bpp (previous) &&
+ memcmp (tile_data_pointer (tile, 0, 0),
+ tile_data_pointer (previous, 0, 0),
+ tile_size (tile)) == 0)
+ tile_manager_map (tiles, i, previous);
+ tile_release (previous, FALSE);
+ }
+ tile_release (tile, TRUE);
+ previous = tile_manager_get (tiles, i, FALSE, FALSE);
+
+ /* restore the saved position so we'll be ready to
+ * read the next offset.
+ */
+ if (!xcf_seek_pos (info, saved_pos, NULL))
+ return FALSE;
+
+ /* read in the offset of the next tile */
+ info->cp += xcf_read_int32 (info->fp, &offset, 1);
+ }
+
+ if (offset != 0)
+ {
+ g_message ("encountered garbage after reading level: %d", offset);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool
+xcf_load_tile (XcfInfo * info, Tile * tile)
+{
+#ifdef SWAP_FROM_FILE
+
+ if (!info->swap_num)
+ {
+ info->ref_count = g_new (int, 1);
+ info->swap_num = tile_swap_add (info->filename,
+ xcf_swap_func, info->ref_count);
+ }
+
+ tile->swap_num = info->swap_num;
+ tile->swap_offset = info->cp;
+ *info->ref_count += 1;
+
+#else
+
+ info->cp += xcf_read_int8 (info->fp, tile_data_pointer (tile, 0, 0),
+ tile_size (tile));
+
+#endif
+
+ return TRUE;
+}
+
+static bool
+xcf_load_tile_rle (XcfInfo * info, Tile * tile, int data_length)
+{
+ guchar *data;
+ guchar val;
+ TQ_INT32 size;
+ TQ_INT32 count;
+ TQ_INT32 length;
+ TQ_INT32 bpp;
+ TQ_INT32 i, j;
+ TQ_INT32 nmemb_read_successfully;
+ guchar *xcfdata, *xcfodata, *xcfdatalimit;
+
+ data = tile_data_pointer (tile, 0, 0);
+ bpp = tile_bpp (tile);
+
+ xcfdata = xcfodata = g_malloc (data_length);
+
+ /* we have to use fread instead of xcf_read_* because we may be
+ reading past the end of the file here */
+ nmemb_read_successfully = fread ((TQCString *) xcfdata, sizeof (TQCString),
+ data_length, info->fp);
+ info->cp += nmemb_read_successfully;
+
+ xcfdatalimit = &xcfodata[nmemb_read_successfully - 1];
+
+ for (i = 0; i < bpp; i++)
+ {
+ data = (guchar *) tile_data_pointer (tile, 0, 0) + i;
+ size = tile_ewidth (tile) * tile_eheight (tile);
+ count = 0;
+
+ while (size > 0)
+ {
+ if (xcfdata > xcfdatalimit)
+ {
+ goto bogus_rle;
+ }
+
+ val = *xcfdata++;
+
+ length = val;
+ if (length >= 128)
+ {
+ length = 255 - (length - 1);
+ if (length == 128)
+ {
+ if (xcfdata >= xcfdatalimit)
+ {
+ goto bogus_rle;
+ }
+
+ length = (*xcfdata << 8) + xcfdata[1];
+ xcfdata += 2;
+ }
+
+ count += length;
+ size -= length;
+
+ if (size < 0)
+ {
+ goto bogus_rle;
+ }
+
+ if (&xcfdata[length - 1] > xcfdatalimit)
+ {
+ goto bogus_rle;
+ }
+
+ while (length-- > 0)
+ {
+ *data = *xcfdata++;
+ data += bpp;
+ }
+ }
+ else
+ {
+ length += 1;
+ if (length == 128)
+ {
+ if (xcfdata >= xcfdatalimit)
+ {
+ goto bogus_rle;
+ }
+
+ length = (*xcfdata << 8) + xcfdata[1];
+ xcfdata += 2;
+ }
+
+ count += length;
+ size -= length;
+
+ if (size < 0)
+ {
+ goto bogus_rle;
+ }
+
+ if (xcfdata > xcfdatalimit)
+ {
+ goto bogus_rle;
+ }
+
+ val = *xcfdata++;
+
+ for (j = 0; j < length; j++)
+ {
+ *data = val;
+ data += bpp;
+ }
+ }
+ }
+ }
+ g_free (xcfodata);
+ return TRUE;
+
+bogus_rle:
+ if (xcfodata)
+ g_free (xcfodata);
+ return FALSE;
+}
+
+static KisAnnotation *
+xcf_load_parasite (XcfInfo * info)
+{
+ KisAnnotation *p;
+
+ p = g_new (KisAnnotation, 1);
+ info->cp += xcf_read_string (info->fp, &p->name, 1);
+ info->cp += xcf_read_int32 (info->fp, &p->flags, 1);
+ info->cp += xcf_read_int32 (info->fp, &p->size, 1);
+ p->data = g_new (TQCString, p->size);
+ info->cp += xcf_read_int8 (info->fp, p->data, p->size);
+
+ return p;
+}
+
+static bool
+xcf_load_old_paths (XcfInfo * info, KisImage * gimage)
+{
+ TQ_INT32 num_paths;
+ TQ_INT32 last_selected_row;
+ GimpVectors *active_vectors;
+
+ info->cp += xcf_read_int32 (info->fp, &last_selected_row, 1);
+ info->cp += xcf_read_int32 (info->fp, &num_paths, 1);
+
+ while (num_paths-- > 0)
+ xcf_load_old_path (info, gimage);
+
+ active_vectors = (GimpVectors *)
+ gimp_container_get_child_by_index (gimage->vectors, last_selected_row);
+
+ if (active_vectors)
+ gimp_image_set_active_vectors (gimage, active_vectors);
+
+ return TRUE;
+}
+
+static bool
+xcf_load_old_path (XcfInfo * info, KisImage * gimage)
+{
+ TQCString *name;
+ TQ_INT32 locked;
+ TQ_UINT8 state;
+ TQ_INT32 closed;
+ TQ_INT32 num_points;
+ TQ_INT32 version; /* changed from num_paths */
+ GimpTattoo tattoo = 0;
+ GimpVectors *vectors;
+ GimpVectorsCompatPoint *points;
+ TQ_INT32 i;
+
+ info->cp += xcf_read_string (info->fp, &name, 1);
+ info->cp += xcf_read_int32 (info->fp, &locked, 1);
+ info->cp += xcf_read_int8 (info->fp, &state, 1);
+ info->cp += xcf_read_int32 (info->fp, &closed, 1);
+ info->cp += xcf_read_int32 (info->fp, &num_points, 1);
+ info->cp += xcf_read_int32 (info->fp, &version, 1);
+
+ if (version == 2)
+ {
+ TQ_INT32 dummy;
+
+ /* Had extra type field and points are stored as doubles */
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & dummy, 1);
+ }
+ else if (version == 3)
+ {
+ TQ_INT32 dummy;
+
+ /* Has extra tatto field */
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & dummy, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & tattoo, 1);
+ }
+ else if (version != 1)
+ {
+ g_warning ("Unknown path type. Possibly corrupt XCF file");
+
+ return FALSE;
+ }
+
+ /* skip empty compatibility paths */
+ if (num_points == 0)
+ return FALSE;
+
+ points = g_new0 (GimpVectorsCompatPoint, num_points);
+
+ for (i = 0; i < num_points; i++)
+ {
+ if (version == 1)
+ {
+ TQ_INT3232 x;
+ TQ_INT3232 y;
+
+ info->cp += xcf_read_int32 (info->fp, &points[i].type, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & x, 1);
+ info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & y, 1);
+
+ points[i].x = x;
+ points[i].y = y;
+ }
+ else
+ {
+ float x;
+ float y;
+
+ info->cp += xcf_read_int32 (info->fp, &points[i].type, 1);
+ info->cp += xcf_read_float (info->fp, &x, 1);
+ info->cp += xcf_read_float (info->fp, &y, 1);
+
+ points[i].x = x;
+ points[i].y = y;
+ }
+ }
+
+ vectors =
+ gimp_vectors_compat_new (gimage, name, points, num_points, closed);
+
+ g_free (name);
+ g_free (points);
+
+ GIMP_ITEM (vectors)->linked = locked;
+
+ if (tattoo)
+ GIMP_ITEM (vectors)->tattoo = tattoo;
+
+ gimp_image_add_vectors (gimage, vectors,
+ gimp_container_num_tqchildren (gimage->vectors));
+
+ return TRUE;
+}
+
+static bool
+xcf_load_vectors (XcfInfo * info, KisImage * gimage)
+{
+ TQ_INT32 version;
+ TQ_INT32 active_index;
+ TQ_INT32 num_paths;
+ GimpVectors *active_vectors;
+ TQ_INT32 base;
+
+#ifdef GIMP_XCF_PATH_DEBUG
+ g_printerr ("xcf_load_vectors\n");
+#endif
+
+ base = info->cp;
+
+ info->cp += xcf_read_int32 (info->fp, &version, 1);
+
+ if (version != 1)
+ {
+ g_message ("Unknown vectors version: %d (skipping)", version);
+ return FALSE;
+ }
+
+ info->cp += xcf_read_int32 (info->fp, &active_index, 1);
+ info->cp += xcf_read_int32 (info->fp, &num_paths, 1);
+
+#ifdef GIMP_XCF_PATH_DEBUG
+ g_printerr ("%d paths (active: %d)\n", num_paths, active_index);
+#endif
+
+ while (num_paths-- > 0)
+ if (!xcf_load_vector (info, gimage))
+ return FALSE;
+
+ active_vectors = (GimpVectors *)
+ gimp_container_get_child_by_index (gimage->vectors, active_index);
+
+ if (active_vectors)
+ gimp_image_set_active_vectors (gimage, active_vectors);
+
+#ifdef GIMP_XCF_PATH_DEBUG
+ g_printerr ("xcf_load_vectors: loaded %d bytes\n", info->cp - base);
+#endif
+ return TRUE;
+}
+
+static bool
+xcf_load_vector (XcfInfo * info, KisImage * gimage)
+{
+ TQCString *name;
+ GimpTattoo tattoo = 0;
+ TQ_INT32 visible;
+ TQ_INT32 linked;
+ TQ_INT32 num_parasites;
+ TQ_INT32 num_strokes;
+ GimpVectors *vectors;
+ TQ_INT32 i;
+
+#ifdef GIMP_XCF_PATH_DEBUG
+ g_printerr ("xcf_load_vector\n");
+#endif
+
+ info->cp += xcf_read_string (info->fp, &name, 1);
+ info->cp += xcf_read_int32 (info->fp, &tattoo, 1);
+ info->cp += xcf_read_int32 (info->fp, &visible, 1);
+ info->cp += xcf_read_int32 (info->fp, &linked, 1);
+ info->cp += xcf_read_int32 (info->fp, &num_parasites, 1);
+ info->cp += xcf_read_int32 (info->fp, &num_strokes, 1);
+
+#ifdef GIMP_XCF_PATH_DEBUG
+ g_printerr
+ ("name: %s, tattoo: %d, visible: %d, linked: %d, num_parasites %d, "
+ "num_strokes %d\n", name, tattoo, visible, linked, num_parasites,
+ num_strokes);
+#endif
+
+ vectors = gimp_vectors_new (gimage, name);
+
+ GIMP_ITEM (vectors)->visible = visible ? TRUE : FALSE;
+ GIMP_ITEM (vectors)->linked = linked ? TRUE : FALSE;
+
+ if (tattoo)
+ GIMP_ITEM (vectors)->tattoo = tattoo;
+
+ for (i = 0; i < num_parasites; i++)
+ {
+ KisAnnotation *parasite;
+
+ parasite = xcf_load_parasite (info);
+
+ if (!parasite)
+ return FALSE;
+
+ gimp_item_parasite_attach (GIMP_ITEM (vectors), parasite);
+ gimp_parasite_free (parasite);
+ }
+
+ for (i = 0; i < num_strokes; i++)
+ {
+ TQ_INT32 stroke_type_id;
+ TQ_INT32 closed;
+ TQ_INT32 num_axes;
+ TQ_INT32 num_control_points;
+ TQ_INT32 type;
+ float coords[6] = { 0.0, 0.0, 1.0, 0.5, 0.5, 0.5 };
+ GimpStroke *stroke;
+ TQ_INT32 j;
+
+ GValueArray *control_points;
+ GValue value = { 0, };
+ GimpAnchor anchor;
+ GType stroke_type;
+
+ g_value_init (&value, GIMP_TYPE_ANCHOR);
+
+ info->cp += xcf_read_int32 (info->fp, &stroke_type_id, 1);
+ info->cp += xcf_read_int32 (info->fp, &closed, 1);
+ info->cp += xcf_read_int32 (info->fp, &num_axes, 1);
+ info->cp += xcf_read_int32 (info->fp, &num_control_points, 1);
+
+#ifdef GIMP_XCF_PATH_DEBUG
+ g_printerr ("stroke_type: %d, closed: %d, num_axes %d, len %d\n",
+ stroke_type_id, closed, num_axes, num_control_points);
+#endif
+
+ switch (stroke_type_id)
+ {
+ case XCF_STROKETYPE_BEZIER_STROKE:
+ stroke_type = GIMP_TYPE_BEZIER_STROKE;
+ break;
+
+ default:
+ g_printerr ("skipping unknown stroke type\n");
+ xcf_seek_pos (info,
+ info->cp + 4 * num_axes * num_control_points, NULL);
+ continue;
+ }
+
+ control_points = g_value_array_new (num_control_points);
+
+ anchor.selected = FALSE;
+
+ for (j = 0; j < num_control_points; j++)
+ {
+ info->cp += xcf_read_int32 (info->fp, &type, 1);
+ info->cp += xcf_read_float (info->fp, coords, num_axes);
+
+ anchor.type = type;
+ anchor.position.x = coords[0];
+ anchor.position.y = coords[1];
+ anchor.position.pressure = coords[2];
+ anchor.position.xtilt = coords[3];
+ anchor.position.ytilt = coords[4];
+ anchor.position.wheel = coords[5];
+
+ g_value_set_boxed (&value, &anchor);
+ g_value_array_append (control_points, &value);
+
+#ifdef GIMP_XCF_PATH_DEBUG
+ g_printerr ("Anchor: %d, (%f, %f, %f, %f, %f, %f)\n", type,
+ coords[0], coords[1], coords[2], coords[3],
+ coords[4], coords[5]);
+#endif
+ }
+
+ g_value_unset (&value);
+
+ stroke = g_object_new (stroke_type,
+ "closed", closed,
+ "control-points", control_points, NULL);
+
+ gimp_vectors_stroke_add (vectors, stroke);
+ }
+
+ gimp_image_add_vectors (gimage, vectors,
+ gimp_container_num_tqchildren (gimage->vectors));
+
+ return TRUE;
+}
+
+#ifdef SWAP_FROM_FILE
+
+static bool
+xcf_swap_func (TQ_INT32 fd, Tile * tile, TQ_INT32 cmd, gpointer user_data)
+{
+ TQ_INT32 bytes;
+ TQ_INT32 err;
+ TQ_INT32 nleft;
+ TQ_INT32 *ref_count;
+
+ switch (cmd)
+ {
+ case SWAP_IN:
+ lseek (fd, tile->swap_offset, SEEK_SET);
+
+ bytes = tile_size (tile);
+ tile_alloc (tile);
+
+ nleft = bytes;
+ while (nleft > 0)
+ {
+ do
+ {
+ err = read (fd, tile->data + bytes - nleft, nleft);
+ }
+ while ((err == -1) && ((errno == EAGAIN) || (errno == EINTR)));
+
+ if (err <= 0)
+ {
+ g_message ("unable to read tile data from xcf file: "
+ "%d ( %d ) bytes read", err, nleft);
+ return FALSE;
+ }
+
+ nleft -= err;
+ }
+ break;
+
+ case SWAP_OUT:
+ case SWAP_DELETE:
+ case SWAP_COMPRESS:
+ ref_count = user_data;
+ *ref_count -= 1;
+ if (*ref_count == 0)
+ {
+ tile_swap_remove (tile->swap_num);
+ g_free (ref_count);
+ }
+
+ tile->swap_num = 1;
+ tile->swap_offset = -1;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+#endif
diff --git a/filters/chalk/xcf/xcf/xcf-load.h b/filters/chalk/xcf/xcf/xcf-load.h
new file mode 100644
index 00000000..75bc0e9c
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-load.h
@@ -0,0 +1,27 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __XCF_LOAD_H__
+#define __XCF_LOAD_H__
+
+class KisImage;
+class XcfInfo;
+
+KisImage * xcf_load_image (XcfInfo *info);
+
+#endif /* __XCF_LOAD_H__ */
diff --git a/filters/chalk/xcf/xcf/xcf-private.h b/filters/chalk/xcf/xcf/xcf-private.h
new file mode 100644
index 00000000..3a832fbd
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-private.h
@@ -0,0 +1,95 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __XCF_PRIVATE_H__
+#define __XCF_PRIVATE_H__
+
+#include <tqcstring.h>
+
+typedef enum
+{
+ PROP_END = 0,
+ PROP_COLORMAP = 1,
+ PROP_ACTIVE_LAYER = 2,
+ PROP_ACTIVE_CHANNEL = 3,
+ PROP_SELECTION = 4,
+ PROP_FLOATING_SELECTION = 5,
+ PROP_OPACITY = 6,
+ PROP_MODE = 7,
+ PROP_VISIBLE = 8,
+ PROP_LINKED = 9,
+ PROP_LOCK_ALPHA = 10,
+ PROP_APPLY_MASK = 11,
+ PROP_EDIT_MASK = 12,
+ PROP_SHOW_MASK = 13,
+ PROP_SHOW_MASKED = 14,
+ PROP_OFFSETS = 15,
+ PROP_COLOR = 16,
+ PROP_COMPRESSION = 17,
+ PROP_GUIDES = 18,
+ PROP_RESOLUTION = 19,
+ PROP_TATTOO = 20,
+ PROP_PARASITES = 21,
+ PROP_UNIT = 22,
+ PROP_PATHS = 23,
+ PROP_USER_UNIT = 24,
+ PROP_VECTORS = 25,
+ PROP_TEXT_LAYER_FLAGS = 26
+} PropType;
+
+typedef enum
+{
+ COMPRESS_NONE = 0,
+ COMPRESS_RLE = 1,
+ COMPRESS_ZLIB = 2, /* unused */
+ COMPRESS_FRACTAL = 3 /* unused */
+} XcfCompressionType;
+
+typedef enum
+{
+ XCF_ORIENTATION_HORIZONTAL = 1,
+ XCF_ORIENTATION_VERTICAL = 2
+} XcfQt::OrientationType;
+
+typedef enum
+{
+ XCF_STROKETYPE_STROKE = 0,
+ XCF_STROKETYPE_BEZIER_STROKE = 1
+} XcfStrokeType;
+
+typedef struct _XcfInfo XcfInfo;
+
+struct _XcfInfo
+{
+ FILE *fp;
+ TQ_UINT32 cp;
+ const TQCString filename;
+ //GimpTattoo tattoo_state;
+ KisLayer *active_layer;
+ //GimpChannel *active_channel;
+ //GimpDrawable *floating_sel_drawable;
+ KisLayer *floating_sel;
+ TQ_UINT32 floating_sel_offset;
+ TQ_INT32 swap_num;
+ TQ_INT32 *ref_count;
+ XcfCompressionType compression;
+ TQ_INT32 file_version;
+};
+
+
+#endif /* __XCF_PRIVATE_H__ */
diff --git a/filters/chalk/xcf/xcf/xcf-read.cc b/filters/chalk/xcf/xcf/xcf-read.cc
new file mode 100644
index 00000000..314daa90
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-read.cc
@@ -0,0 +1,118 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include <glib-object.h>
+
+#include "libgimpbase/gimpbase.h"
+
+#include "xcf-read.h"
+
+#include "gimp-intl.h"
+
+
+TQ_UINT32
+xcf_read_int32 (FILE *fp,
+ TQ_INT32 *data,
+ TQ_INT32 count)
+{
+ TQ_UINT32 total;
+
+ total = count;
+ if (count > 0)
+ {
+ xcf_read_int8 (fp, (TQ_UINT8 *) data, count * 4);
+
+ while (count--)
+ {
+ *data = g_ntohl (*data);
+ data++;
+ }
+ }
+
+ return total * 4;
+}
+
+TQ_UINT32
+xcf_read_float (FILE *fp,
+ float *data,
+ TQ_INT32 count)
+{
+ return xcf_read_int32 (fp, (TQ_INT32 *) ((void *) data), count);
+}
+
+TQ_UINT32
+xcf_read_int8 (FILE *fp,
+ TQ_UINT8 *data,
+ TQ_INT32 count)
+{
+ TQ_UINT32 total;
+ TQ_INT32 bytes;
+
+ total = count;
+ while (count > 0)
+ {
+ bytes = fread ((char *) data, sizeof (char), count, fp);
+ if (bytes <= 0) /* something bad happened */
+ break;
+ count -= bytes;
+ data += bytes;
+ }
+
+ return total;
+}
+
+TQ_UINT32
+xcf_read_string (FILE *fp,
+ TQCString **data,
+ TQ_INT32 count)
+{
+ TQ_INT32 tmp;
+ TQ_UINT32 total;
+ TQ_INT32 i;
+
+ total = 0;
+ for (i = 0; i < count; i++)
+ {
+ total += xcf_read_int32 (fp, &tmp, 1);
+ if (tmp > 0)
+ {
+ TQCString *str;
+
+ str = g_new (TQCString, tmp);
+ total += xcf_read_int8 (fp, (TQ_UINT8*) str, tmp);
+
+ if (str[tmp - 1] != '\0')
+ str[tmp - 1] = '\0';
+
+ data[i] = gimp_any_to_utf8 (str, -1,
+ _("Invalid UTF-8 string in XCF file"));
+
+ g_free (str);
+ }
+ else
+ {
+ data[i] = NULL;
+ }
+ }
+
+ return total;
+}
diff --git a/filters/chalk/xcf/xcf/xcf-read.h b/filters/chalk/xcf/xcf/xcf-read.h
new file mode 100644
index 00000000..b90b8a41
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-read.h
@@ -0,0 +1,37 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __XCF_READ_H__
+#define __XCF_READ_H__
+
+
+TQ_UINT32 xcf_read_int32 (FILE *fp,
+ TQ_INT32 *data,
+ TQ_INT32 count);
+TQ_UINT32 xcf_read_float (FILE *fp,
+ float *data,
+ TQ_INT32 count);
+TQ_UINT32 xcf_read_int8 (FILE *fp,
+ TQ_UINT8 *data,
+ TQ_INT32 count);
+TQ_UINT32 xcf_read_string (FILE *fp,
+ TQCString **data,
+ TQ_INT32 count);
+
+
+#endif /* __XCF_READ_H__ */
diff --git a/filters/chalk/xcf/xcf/xcf-save.cc b/filters/chalk/xcf/xcf/xcf-save.cc
new file mode 100644
index 00000000..50e5fb17
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-save.cc
@@ -0,0 +1,1826 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h> /* strcpy, strlen */
+
+#include <glib-object.h>
+
+#include "libgimpbase/gimpbase.h"
+#include "libgimpcolor/gimpcolor.h"
+
+#include "core/core-types.h"
+
+#include "base/tile.h"
+#include "base/tile-manager.h"
+#include "base/tile-manager-private.h"
+
+#include "core/gimpchannel.h"
+#include "core/gimpdrawable.h"
+#include "core/gimpgrid.h"
+#include "core/gimpimage.h"
+#include "core/gimpimage-grid.h"
+#include "core/gimpimage-guides.h"
+#include "core/gimplayer.h"
+#include "core/gimplayer-floating-sel.h"
+#include "core/gimplayertqmask.h"
+#include "core/gimplist.h"
+#include "core/gimpparasitelist.h"
+#include "core/gimpunit.h"
+
+#include "text/gimptextlayer.h"
+#include "text/gimptextlayer-xcf.h"
+
+#include "vectors/gimpanchor.h"
+#include "vectors/gimpstroke.h"
+#include "vectors/gimpbezierstroke.h"
+#include "vectors/gimpvectors.h"
+#include "vectors/gimpvectors-compat.h"
+
+#include "xcf-private.h"
+#include "xcf-read.h"
+#include "xcf-seek.h"
+#include "xcf-write.h"
+
+#include "gimp-intl.h"
+
+
+static bool xcf_save_image_props (XcfInfo *info,
+ KisImage *gimage,
+ GError **error);
+static bool xcf_save_layer_props (XcfInfo *info,
+ KisImage *gimage,
+ KisLayer *layer,
+ GError **error);
+static bool xcf_save_channel_props (XcfInfo *info,
+ KisImage *gimage,
+ GimpChannel *channel,
+ GError **error);
+static bool xcf_save_prop (XcfInfo *info,
+ KisImage *gimage,
+ PropType prop_type,
+ GError **error,
+ ...);
+static bool xcf_save_layer (XcfInfo *info,
+ KisImage *gimage,
+ KisLayer *layer,
+ GError **error);
+static bool xcf_save_channel (XcfInfo *info,
+ KisImage *gimage,
+ GimpChannel *channel,
+ GError **error);
+static bool xcf_save_hierarchy (XcfInfo *info,
+ TileManager *tiles,
+ GError **error);
+static bool xcf_save_level (XcfInfo *info,
+ TileManager *tiles,
+ GError **error);
+static bool xcf_save_tile (XcfInfo *info,
+ Tile *tile,
+ GError **error);
+static bool xcf_save_tile_rle (XcfInfo *info,
+ Tile *tile,
+ guchar *rlebuf,
+ GError **error);
+static bool xcf_save_parasite (XcfInfo *info,
+ KisAnnotation *parasite,
+ GError **error);
+static bool xcf_save_parasite_list (XcfInfo *info,
+ KisAnnotationList *parasite,
+ GError **error);
+static bool xcf_save_old_paths (XcfInfo *info,
+ KisImage *gimage,
+ GError **error);
+static bool xcf_save_vectors (XcfInfo *info,
+ KisImage *gimage,
+ GError **error);
+
+
+/* private convenience macros */
+#define xcf_write_int32_check_error(info, data, count) G_STMT_START { \
+ info->cp += xcf_write_int32 (info->fp, data, count, &tmp_error); \
+ if (tmp_error) \
+ { \
+ g_propagate_error (error, tmp_error); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+#define xcf_write_int8_check_error(info, data, count) G_STMT_START { \
+ info->cp += xcf_write_int8 (info->fp, data, count, &tmp_error); \
+ if (tmp_error) \
+ { \
+ g_propagate_error (error, tmp_error); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+#define xcf_write_float_check_error(info, data, count) G_STMT_START { \
+ info->cp += xcf_write_float (info->fp, data, count, &tmp_error); \
+ if (tmp_error) \
+ { \
+ g_propagate_error (error, tmp_error); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+#define xcf_write_string_check_error(info, data, count) G_STMT_START { \
+ info->cp += xcf_write_string (info->fp, data, count, &tmp_error); \
+ if (tmp_error) \
+ { \
+ g_propagate_error (error, tmp_error); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+#define xcf_write_int32_print_error(info, data, count) G_STMT_START { \
+ info->cp += xcf_write_int32 (info->fp, data, count, &error); \
+ if (error) \
+ { \
+ g_message (_("Error saving XCF file: %s"), \
+ error->message); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+#define xcf_write_int8_print_error(info, data, count) G_STMT_START { \
+ info->cp += xcf_write_int8 (info->fp, data, count, &error); \
+ if (error) \
+ { \
+ g_message (_("Error saving XCF file: %s"), \
+ error->message); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+#define xcf_write_float_print_error(info, data, count) G_STMT_START { \
+ info->cp += xcf_write_float (info->fp, data, count, &error); \
+ if (error) \
+ { \
+ g_message (_("Error saving XCF file: %s"), \
+ error->message); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+#define xcf_write_string_print_error(info, data, count) G_STMT_START { \
+ info->cp += xcf_write_string (info->fp, data, count, &error); \
+ if (error) \
+ { \
+ g_message (_("Error saving XCF file: %s"), \
+ error->message); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+#define xcf_write_prop_type_check_error(info, prop_type) G_STMT_START { \
+ TQ_INT32 _prop_int32 = prop_type; \
+ xcf_write_int32_check_error (info, &_prop_int32, 1); \
+ } G_STMT_END
+
+#define xcf_write_prop_type_print_error(info, prop_type) G_STMT_START { \
+ TQ_INT32 _prop_int32 = prop_type; \
+ xcf_write_int32_print_error (info, &_prop_int32, 1); \
+ } G_STMT_END
+
+#define xcf_check_error(x) G_STMT_START { \
+ if (! (x)) \
+ return FALSE; \
+ } G_STMT_END
+
+#define xcf_print_error(x) G_STMT_START { \
+ if (! (x)) \
+ { \
+ g_message (_("Error saving XCF file: %s"), \
+ error->message); \
+ return FALSE; \
+ } \
+ } G_STMT_END
+
+
+void
+xcf_save_choose_format (XcfInfo *info,
+ KisImage *gimage)
+{
+ KisLayer *layer;
+ GList *list;
+
+ TQ_INT32 save_version = 0; /* default to oldest */
+
+ if (gimage->cmap)
+ save_version = 1; /* need version 1 for colormaps */
+
+ for (list = GIMP_LIST (gimage->layers)->list;
+ list && save_version < 2;
+ list = g_list_next (list))
+ {
+ layer = GIMP_LAYER (list->data);
+
+ switch (layer->mode)
+ {
+ /* new layer modes not supported by gimp-1.2 */
+ case GIMP_SOFTLIGHT_MODE:
+ case GIMP_GRAIN_EXTRACT_MODE:
+ case GIMP_GRAIN_MERGE_MODE:
+ case GIMP_COLOR_ERASE_MODE:
+ save_version = 2;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ info->file_version = save_version;
+}
+
+TQ_INT32
+xcf_save_image (XcfInfo *info,
+ KisImage *gimage)
+{
+ KisLayer *layer;
+ KisLayer *floating_layer;
+ GimpChannel *channel;
+ TQ_INT32 saved_pos;
+ TQ_INT32 offset;
+ TQ_UINT32 nlayers;
+ TQ_UINT32 nchannels;
+ GList *list;
+ bool have_selection;
+ TQ_INT32 t1, t2, t3, t4;
+ TQCString version_tag[14];
+ GError *error = NULL;
+
+ floating_layer = gimp_image_floating_sel (gimage);
+ if (floating_layer)
+ floating_sel_relax (floating_layer, FALSE);
+
+ /* write out the tag information for the image */
+ if (info->file_version > 0)
+ {
+ sprintf (version_tag, "gimp xcf v%03d", info->file_version);
+ }
+ else
+ {
+ strcpy (version_tag, "gimp xcf file");
+ }
+ xcf_write_int8_print_error (info, (TQ_UINT8 *) version_tag, 14);
+
+ /* write out the width, height and image type information for the image */
+ xcf_write_int32_print_error (info, (TQ_INT32 *) &gimage->width, 1);
+ xcf_write_int32_print_error (info, (TQ_INT32 *) &gimage->height, 1);
+ xcf_write_int32_print_error (info, (TQ_INT32 *) &gimage->base_type, 1);
+
+ /* determine the number of layers and channels in the image */
+ nlayers = (TQ_UINT32) gimp_container_num_tqchildren (gimage->layers);
+ nchannels = (TQ_UINT32) gimp_container_num_tqchildren (gimage->channels);
+
+ /* check and see if we have to save out the selection */
+ have_selection = gimp_channel_bounds (gimp_image_get_tqmask (gimage),
+ &t1, &t2, &t3, &t4);
+ if (have_selection)
+ nchannels += 1;
+
+ /* write the property information for the image.
+ */
+
+ xcf_print_error (xcf_save_image_props (info, gimage, &error));
+
+ /* save the current file position as it is the start of where
+ * we place the layer offset information.
+ */
+ saved_pos = info->cp;
+
+ /* seek to after the offset lists */
+ xcf_print_error (xcf_seek_pos (info,
+ info->cp + (nlayers + nchannels + 2) * 4,
+ &error));
+
+ for (list = GIMP_LIST (gimage->layers)->list;
+ list;
+ list = g_list_next (list))
+ {
+ layer = (KisLayer *) list->data;
+
+ /* save the start offset of where we are writing
+ * out the next layer.
+ */
+ offset = info->cp;
+
+ /* write out the layer. */
+ xcf_print_error (xcf_save_layer (info, gimage, layer, &error));
+
+ /* seek back to where we are to write out the next
+ * layer offset and write it out.
+ */
+ xcf_print_error (xcf_seek_pos (info, saved_pos, &error));
+ xcf_write_int32_print_error (info, &offset, 1);
+
+ /* increment the location we are to write out the
+ * next offset.
+ */
+ saved_pos = info->cp;
+
+ /* seek to the end of the file which is where
+ * we will write out the next layer.
+ */
+ xcf_print_error (xcf_seek_end (info, &error));
+ }
+
+ /* write out a '0' offset position to indicate the end
+ * of the layer offsets.
+ */
+ offset = 0;
+ xcf_print_error (xcf_seek_pos (info, saved_pos, &error));
+ xcf_write_int32_print_error (info, &offset, 1);
+ saved_pos = info->cp;
+ xcf_print_error (xcf_seek_end (info, &error));
+
+ list = GIMP_LIST (gimage->channels)->list;
+
+ while (list || have_selection)
+ {
+ if (list)
+ {
+ channel = (GimpChannel *) list->data;
+
+ list = g_list_next (list);
+ }
+ else
+ {
+ channel = gimage->selection_tqmask;
+ have_selection = FALSE;
+ }
+
+ /* save the start offset of where we are writing
+ * out the next channel.
+ */
+ offset = info->cp;
+
+ /* write out the layer. */
+ xcf_print_error (xcf_save_channel (info, gimage, channel, &error));
+
+ /* seek back to where we are to write out the next
+ * channel offset and write it out.
+ */
+ xcf_print_error (xcf_seek_pos (info, saved_pos, &error));
+ xcf_write_int32_print_error (info, &offset, 1);
+
+ /* increment the location we are to write out the
+ * next offset.
+ */
+ saved_pos = info->cp;
+
+ /* seek to the end of the file which is where
+ * we will write out the next channel.
+ */
+ xcf_print_error (xcf_seek_end (info, &error));
+ }
+
+ /* write out a '0' offset position to indicate the end
+ * of the channel offsets.
+ */
+ offset = 0;
+ xcf_print_error (xcf_seek_pos (info, saved_pos, &error));
+ xcf_write_int32_print_error (info, &offset, 1);
+ saved_pos = info->cp;
+
+ if (floating_layer)
+ floating_sel_rigor (floating_layer, FALSE);
+
+ return !ferror(info->fp);
+}
+
+static bool
+xcf_save_image_props (XcfInfo *info,
+ KisImage *gimage,
+ GError **error)
+{
+ KisAnnotation *parasite = NULL;
+ GimpUnit unit = gimp_image_get_unit (gimage);
+
+ /* check and see if we should save the colormap property */
+ if (gimage->cmap)
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_COLORMAP, error,
+ gimage->num_cols, gimage->cmap));
+
+ if (info->compression != COMPRESS_NONE)
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_COMPRESSION,
+ error, info->compression));
+
+ if (gimage->guides)
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_GUIDES,
+ error, gimage->guides));
+
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_RESOLUTION, error,
+ gimage->xresolution, gimage->yresolution));
+
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_TATTOO, error,
+ gimage->tattoo_state));
+
+ if (gimp_parasite_list_length (gimage->parasites) > 0)
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_PARASITES,
+ error, gimage->parasites));
+
+ if (unit < _gimp_unit_get_number_of_built_in_units (gimage->gimp))
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_UNIT, error, unit));
+
+ if (gimp_container_num_tqchildren (gimage->vectors) > 0)
+ {
+ if (gimp_vectors_compat_is_compatible (gimage))
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_PATHS, error));
+ else
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_VECTORS, error));
+ }
+
+ if (unit >= _gimp_unit_get_number_of_built_in_units (gimage->gimp))
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_USER_UNIT, error, unit));
+
+ if (GIMP_IS_GRID (gimage->grid))
+ {
+ GimpGrid *grid = gimp_image_get_grid (gimage);
+
+ parasite = gimp_grid_to_parasite (grid);
+ gimp_parasite_list_add (GIMP_IMAGE (gimage)->parasites, parasite);
+ }
+
+ if (gimp_parasite_list_length (GIMP_IMAGE (gimage)->parasites) > 0)
+ {
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_PARASITES, error,
+ GIMP_IMAGE (gimage)->parasites));
+ }
+
+ if (parasite)
+ {
+ gimp_parasite_list_remove (GIMP_IMAGE (gimage)->parasites,
+ gimp_parasite_name (parasite));
+ gimp_parasite_free (parasite);
+ }
+
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_END, error));
+
+ return TRUE;
+}
+
+static bool
+xcf_save_layer_props (XcfInfo *info,
+ KisImage *gimage,
+ KisLayer *layer,
+ GError **error)
+{
+ KisAnnotation *parasite = NULL;
+
+ if (layer == gimp_image_get_active_layer (gimage))
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_ACTIVE_LAYER, error));
+
+ if (layer == gimp_image_floating_sel (gimage))
+ {
+ info->floating_sel_drawable = layer->fs.drawable;
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_FLOATING_SELECTION,
+ error));
+ }
+
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_OPACITY, error,
+ layer->opacity));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_VISIBLE, error,
+ gimp_item_get_visible (GIMP_ITEM (layer))));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_LINKED, error,
+ gimp_item_get_linked (GIMP_ITEM (layer))));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_LOCK_ALPHA,
+ error, layer->lock_alpha));
+
+ if (layer->tqmask)
+ {
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_APPLY_MASK,
+ error, layer->tqmask->apply_tqmask));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_EDIT_MASK,
+ error, layer->tqmask->edit_tqmask));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_SHOW_MASK,
+ error, layer->tqmask->show_tqmask));
+ }
+ else
+ {
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_APPLY_MASK,
+ error, FALSE));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_EDIT_MASK,
+ error, FALSE));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_SHOW_MASK,
+ error, FALSE));
+ }
+
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_OFFSETS, error,
+ GIMP_ITEM (layer)->offset_x,
+ GIMP_ITEM (layer)->offset_y));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_MODE, error,
+ layer->mode));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_TATTOO, error,
+ GIMP_ITEM (layer)->tattoo));
+
+ if (GIMP_IS_TEXT_LAYER (layer) && GIMP_TEXT_LAYER (layer)->text)
+ {
+ GimpTextLayer *text_layer = GIMP_TEXT_LAYER (layer);
+ TQ_INT32 flags = gimp_text_layer_get_xcf_flags (text_layer);
+
+ gimp_text_layer_xcf_save_prepare (text_layer);
+
+ if (flags)
+ xcf_check_error (xcf_save_prop (info,
+ gimage, PROP_TEXT_LAYER_FLAGS, error,
+ flags));
+ }
+
+ if (gimp_parasite_list_length (GIMP_ITEM (layer)->parasites) > 0)
+ {
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_PARASITES, error,
+ GIMP_ITEM (layer)->parasites));
+ }
+
+ if (parasite)
+ {
+ gimp_parasite_list_remove (GIMP_ITEM (layer)->parasites,
+ gimp_parasite_name (parasite));
+ gimp_parasite_free (parasite);
+ }
+
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_END, error));
+
+ return TRUE;
+}
+
+static bool
+xcf_save_channel_props (XcfInfo *info,
+ KisImage *gimage,
+ GimpChannel *channel,
+ GError **error)
+{
+ guchar col[3];
+
+ if (channel == gimp_image_get_active_channel (gimage))
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_ACTIVE_CHANNEL, error));
+
+ if (channel == gimage->selection_tqmask)
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_SELECTION, error));
+
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_OPACITY, error,
+ channel->color.a));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_VISIBLE, error,
+ gimp_item_get_visible (GIMP_ITEM (channel))));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_LINKED, error,
+ gimp_item_get_linked (GIMP_ITEM (channel))));
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_SHOW_MASKED, error,
+ channel->show_tqmasked));
+
+ gimp_rgb_get_uchar (&channel->color, &col[0], &col[1], &col[2]);
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_COLOR, error, col));
+
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_TATTOO, error,
+ GIMP_ITEM (channel)->tattoo));
+
+ if (gimp_parasite_list_length (GIMP_ITEM (channel)->parasites) > 0)
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_PARASITES, error,
+ GIMP_ITEM (channel)->parasites));
+
+ xcf_check_error (xcf_save_prop (info, gimage, PROP_END, error));
+
+ return TRUE;
+}
+
+static bool
+xcf_save_prop (XcfInfo *info,
+ KisImage *gimage,
+ PropType prop_type,
+ GError **error,
+ ...)
+{
+ TQ_INT32 size;
+ va_list args;
+
+ GError *tmp_error = NULL;
+
+ va_start (args, error);
+
+ switch (prop_type)
+ {
+ case PROP_END:
+ size = 0;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ break;
+
+ case PROP_COLORMAP:
+ {
+ TQ_INT32 ncolors;
+ guchar *colors;
+
+ ncolors = va_arg (args, TQ_INT32);
+ colors = va_arg (args, guchar*);
+ size = 4 + ncolors * 3;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &ncolors, 1);
+ xcf_write_int8_check_error (info, colors, ncolors * 3);
+ }
+ break;
+
+ case PROP_ACTIVE_LAYER:
+ case PROP_ACTIVE_CHANNEL:
+ case PROP_SELECTION:
+ size = 0;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ break;
+
+ case PROP_FLOATING_SELECTION:
+ {
+ TQ_INT32 dummy;
+
+ dummy = 0;
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ info->floating_sel_offset = info->cp;
+ xcf_write_int32_check_error (info, &dummy, 1);
+ }
+ break;
+
+ case PROP_OPACITY:
+ {
+ gdouble opacity;
+ TQ_INT32 uint_opacity;
+
+ opacity = va_arg (args, gdouble);
+
+ uint_opacity = opacity * 255.999;
+
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &uint_opacity, 1);
+ }
+ break;
+
+ case PROP_MODE:
+ {
+ TQ_INT3232 mode;
+
+ mode = va_arg (args, TQ_INT3232);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &mode, 1);
+ }
+ break;
+
+ case PROP_VISIBLE:
+ {
+ TQ_INT32 visible;
+
+ visible = va_arg (args, TQ_INT32);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &visible, 1);
+ }
+ break;
+
+ case PROP_LINKED:
+ {
+ TQ_INT32 linked;
+
+ linked = va_arg (args, TQ_INT32);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &linked, 1);
+ }
+ break;
+
+ case PROP_LOCK_ALPHA:
+ {
+ TQ_INT32 lock_alpha;
+
+ lock_alpha = va_arg (args, TQ_INT32);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &lock_alpha, 1);
+ }
+ break;
+
+ case PROP_APPLY_MASK:
+ {
+ TQ_INT32 apply_tqmask;
+
+ apply_tqmask = va_arg (args, TQ_INT32);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &apply_tqmask, 1);
+ }
+ break;
+
+ case PROP_EDIT_MASK:
+ {
+ TQ_INT32 edit_tqmask;
+
+ edit_tqmask = va_arg (args, TQ_INT32);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &edit_tqmask, 1);
+ }
+ break;
+
+ case PROP_SHOW_MASK:
+ {
+ TQ_INT32 show_tqmask;
+
+ show_tqmask = va_arg (args, TQ_INT32);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &show_tqmask, 1);
+ }
+ break;
+
+ case PROP_SHOW_MASKED:
+ {
+ TQ_INT32 show_tqmasked;
+
+ show_tqmasked = va_arg (args, TQ_INT32);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &show_tqmasked, 1);
+ }
+ break;
+
+ case PROP_OFFSETS:
+ {
+ TQ_INT3232 offsets[2];
+
+ offsets[0] = va_arg (args, TQ_INT3232);
+ offsets[1] = va_arg (args, TQ_INT3232);
+ size = 8;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, (TQ_INT32 *) offsets, 2);
+ }
+ break;
+
+ case PROP_COLOR:
+ {
+ guchar *color;
+
+ color = va_arg (args, guchar*);
+ size = 3;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int8_check_error (info, color, 3);
+ }
+ break;
+
+ case PROP_COMPRESSION:
+ {
+ TQ_UINT8 compression;
+
+ compression = (TQ_UINT8) va_arg (args, TQ_INT32);
+ size = 1;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int8_check_error (info, &compression, 1);
+ }
+ break;
+
+ case PROP_GUIDES:
+ {
+ GList *guides;
+ GimpGuide *guide;
+ TQ_INT3232 position;
+ TQ_INT328 orientation;
+ TQ_INT32 nguides;
+
+ guides = va_arg (args, GList *);
+ nguides = g_list_length (guides);
+
+ size = nguides * (4 + 1);
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+
+ for (; guides; guides = g_list_next (guides))
+ {
+ guide = (GimpGuide *) guides->data;
+
+ position = guide->position;
+
+ switch (guide->orientation)
+ {
+ case GIMP_ORIENTATION_HORIZONTAL:
+ orientation = XCF_ORIENTATION_HORIZONTAL;
+ break;
+
+ case GIMP_ORIENTATION_VERTICAL:
+ orientation = XCF_ORIENTATION_VERTICAL;
+ break;
+
+ default:
+ g_warning ("%s: skipping guide with bad orientation",
+ G_STRFUNC);
+ continue;
+ }
+
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &position, 1);
+ xcf_write_int8_check_error (info, (TQ_UINT8 *) &orientation, 1);
+ }
+ }
+ break;
+
+ case PROP_RESOLUTION:
+ {
+ float xresolution, yresolution;
+
+ /* we pass in floats,
+ but they are promoted to double by the compiler */
+ xresolution = va_arg (args, double);
+ yresolution = va_arg (args, double);
+
+ size = 4*2;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+
+ xcf_write_float_check_error (info, &xresolution, 1);
+ xcf_write_float_check_error (info, &yresolution, 1);
+ }
+ break;
+
+ case PROP_TATTOO:
+ {
+ TQ_INT32 tattoo;
+
+ tattoo = va_arg (args, TQ_INT32);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &tattoo, 1);
+ }
+ break;
+
+ case PROP_PARASITES:
+ {
+ KisAnnotationList *list;
+ TQ_INT32 base, length;
+ long pos;
+
+ list = va_arg (args, KisAnnotationList *);
+
+ if (gimp_parasite_list_persistent_length (list) > 0)
+ {
+ xcf_write_prop_type_check_error (info, prop_type);
+
+ /* because we don't know how much room the parasite list will take
+ * we save the file position and write the length later
+ */
+ pos = info->cp;
+ xcf_write_int32_check_error (info, &length, 1);
+ base = info->cp;
+
+ xcf_check_error (xcf_save_parasite_list (info, list, error));
+
+ length = info->cp - base;
+ /* go back to the saved position and write the length */
+ xcf_check_error (xcf_seek_pos (info, pos, error));
+ xcf_write_int32 (info->fp, &length, 1, &tmp_error);
+ if (tmp_error)
+ {
+ g_propagate_error (error, tmp_error);
+ return FALSE;
+ }
+
+ xcf_check_error (xcf_seek_end (info, error));
+ }
+ }
+ break;
+
+ case PROP_UNIT:
+ {
+ TQ_INT32 unit;
+
+ unit = va_arg (args, TQ_INT32);
+
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &unit, 1);
+ }
+ break;
+
+ case PROP_PATHS:
+ {
+ TQ_INT32 base, length;
+ glong pos;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+
+ /* because we don't know how much room the paths list will take
+ * we save the file position and write the length later
+ */
+ pos = info->cp;
+ xcf_write_int32_check_error (info, &length, 1);
+
+ base = info->cp;
+
+ xcf_check_error (xcf_save_old_paths (info, gimage, error));
+
+ length = info->cp - base;
+
+ /* go back to the saved position and write the length */
+ xcf_check_error (xcf_seek_pos (info, pos, error));
+ xcf_write_int32 (info->fp, &length, 1, &tmp_error);
+ if (tmp_error)
+ {
+ g_propagate_error (error, tmp_error);
+ return FALSE;
+ }
+
+ xcf_check_error (xcf_seek_end (info, error));
+ }
+ break;
+
+ case PROP_USER_UNIT:
+ {
+ GimpUnit unit;
+ const TQCString *unit_strings[5];
+ float factor;
+ TQ_INT32 digits;
+
+ unit = va_arg (args, TQ_INT32);
+
+ /* write the entire unit definition */
+ unit_strings[0] = _gimp_unit_get_identifier (gimage->gimp, unit);
+ factor = _gimp_unit_get_factor (gimage->gimp, unit);
+ digits = _gimp_unit_get_digits (gimage->gimp, unit);
+ unit_strings[1] = _gimp_unit_get_symbol (gimage->gimp, unit);
+ unit_strings[2] = _gimp_unit_get_abbreviation (gimage->gimp, unit);
+ unit_strings[3] = _gimp_unit_get_singular (gimage->gimp, unit);
+ unit_strings[4] = _gimp_unit_get_plural (gimage->gimp, unit);
+
+ size =
+ 2 * 4 +
+ strlen (unit_strings[0]) ? strlen (unit_strings[0]) + 5 : 4 +
+ strlen (unit_strings[1]) ? strlen (unit_strings[1]) + 5 : 4 +
+ strlen (unit_strings[2]) ? strlen (unit_strings[2]) + 5 : 4 +
+ strlen (unit_strings[3]) ? strlen (unit_strings[3]) + 5 : 4 +
+ strlen (unit_strings[4]) ? strlen (unit_strings[4]) + 5 : 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_float_check_error (info, &factor, 1);
+ xcf_write_int32_check_error (info, &digits, 1);
+ xcf_write_string_check_error (info, (TQCString **) unit_strings, 5);
+ }
+ break;
+
+ case PROP_VECTORS:
+ {
+ TQ_INT32 base, length;
+ glong pos;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+
+ /* because we don't know how much room the paths list will take
+ * we save the file position and write the length later
+ */
+ pos = info->cp;
+ xcf_write_int32_check_error (info, &length, 1);
+
+ base = info->cp;
+
+ xcf_check_error (xcf_save_vectors (info, gimage, error));
+
+ length = info->cp - base;
+
+ /* go back to the saved position and write the length */
+ xcf_check_error (xcf_seek_pos (info, pos, error));
+ xcf_write_int32 (info->fp, &length, 1, &tmp_error);
+ if (tmp_error)
+ {
+ g_propagate_error (error, tmp_error);
+ return FALSE;
+ }
+
+ xcf_check_error (xcf_seek_end (info, error));
+ }
+ break;
+
+ case PROP_TEXT_LAYER_FLAGS:
+ {
+ TQ_INT32 flags;
+
+ flags = va_arg (args, TQ_INT32);
+ size = 4;
+
+ xcf_write_prop_type_check_error (info, prop_type);
+ xcf_write_int32_check_error (info, &size, 1);
+ xcf_write_int32_check_error (info, &flags, 1);
+ }
+ break;
+ }
+
+ va_end (args);
+
+ return TRUE;
+}
+
+static bool
+xcf_save_layer (XcfInfo *info,
+ KisImage *gimage,
+ KisLayer *layer,
+ GError **error)
+{
+ TQ_INT32 saved_pos;
+ TQ_INT32 offset;
+
+ GError *tmp_error = NULL;
+
+ /* check and see if this is the drawable that the floating
+ * selection is attached to.
+ */
+ if (GIMP_DRAWABLE (layer) == info->floating_sel_drawable)
+ {
+ saved_pos = info->cp;
+ xcf_check_error (xcf_seek_pos (info, info->floating_sel_offset, error));
+ xcf_write_int32_check_error (info, &saved_pos, 1);
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
+ }
+
+ /* write out the width, height and image type information for the layer */
+ xcf_write_int32_check_error (info,
+ (TQ_INT32 *) &GIMP_ITEM (layer)->width, 1);
+ xcf_write_int32_check_error (info,
+ (TQ_INT32 *) &GIMP_ITEM (layer)->height, 1);
+ xcf_write_int32_check_error (info,
+ (TQ_INT32 *) &GIMP_DRAWABLE (layer)->type, 1);
+
+ /* write out the layers name */
+ xcf_write_string_check_error (info, &GIMP_OBJECT (layer)->name, 1);
+
+ /* write out the layer properties */
+ xcf_save_layer_props (info, gimage, layer, error);
+
+ /* save the current position which is where the hierarchy offset
+ * will be stored.
+ */
+ saved_pos = info->cp;
+
+ /* write out the layer tile hierarchy */
+ xcf_check_error (xcf_seek_pos (info, info->cp + 8, error));
+ offset = info->cp;
+
+ xcf_check_error (xcf_save_hierarchy (info,
+ GIMP_DRAWABLE(layer)->tiles, error));
+
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
+ xcf_write_int32_check_error (info, &offset, 1);
+ saved_pos = info->cp;
+
+ /* write out the layer tqmask */
+ if (layer->tqmask)
+ {
+ xcf_check_error (xcf_seek_end (info, error));
+ offset = info->cp;
+
+ xcf_check_error (xcf_save_channel (info,
+ gimage, GIMP_CHANNEL(layer->tqmask),
+ error));
+ }
+ else
+ offset = 0;
+
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
+ xcf_write_int32_check_error (info, &offset, 1);
+
+ return TRUE;
+}
+
+static bool
+xcf_save_channel (XcfInfo *info,
+ KisImage *gimage,
+ GimpChannel *channel,
+ GError **error)
+{
+ TQ_INT32 saved_pos;
+ TQ_INT32 offset;
+
+ GError *tmp_error = NULL;
+
+ /* check and see if this is the drawable that the floating
+ * selection is attached to.
+ */
+ if (GIMP_DRAWABLE (channel) == info->floating_sel_drawable)
+ {
+ saved_pos = info->cp;
+ xcf_check_error (xcf_seek_pos (info, info->floating_sel_offset, error));
+ xcf_write_int32_check_error (info, &saved_pos, 1);
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
+ }
+
+ /* write out the width and height information for the channel */
+ xcf_write_int32_check_error (info,
+ (TQ_INT32 *) &GIMP_ITEM (channel)->width, 1);
+ xcf_write_int32_check_error (info,
+ (TQ_INT32 *) &GIMP_ITEM (channel)->height, 1);
+
+ /* write out the channels name */
+ xcf_write_string_check_error (info, &GIMP_OBJECT (channel)->name, 1);
+
+ /* write out the channel properties */
+ xcf_save_channel_props (info, gimage, channel, error);
+
+ /* save the current position which is where the hierarchy offset
+ * will be stored.
+ */
+ saved_pos = info->cp;
+
+ /* write out the channel tile hierarchy */
+ xcf_check_error (xcf_seek_pos (info, info->cp + 4, error));
+ offset = info->cp;
+
+ xcf_check_error (xcf_save_hierarchy (info,
+ GIMP_DRAWABLE (channel)->tiles, error));
+
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
+ xcf_write_int32_check_error (info, &offset, 1);
+ saved_pos = info->cp;
+
+ return TRUE;
+}
+
+static TQ_INT32
+xcf_calc_levels (TQ_INT32 size,
+ TQ_INT32 tile_size)
+{
+ int levels;
+
+ levels = 1;
+ while (size > tile_size)
+ {
+ size /= 2;
+ levels += 1;
+ }
+
+ return levels;
+}
+
+
+static bool
+xcf_save_hierarchy (XcfInfo *info,
+ TileManager *tiles,
+ GError **error)
+{
+ TQ_INT32 saved_pos;
+ TQ_INT32 offset;
+ TQ_INT32 width;
+ TQ_INT32 height;
+ TQ_INT32 bpp;
+ TQ_INT32 i;
+ TQ_INT32 nlevels;
+ TQ_INT32 tmp1, tmp2;
+
+ GError *tmp_error = NULL;
+
+ width = tile_manager_width (tiles);
+ height = tile_manager_height (tiles);
+ bpp = tile_manager_bpp (tiles);
+
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &width, 1);
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &height, 1);
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &bpp, 1);
+
+ saved_pos = info->cp;
+
+ tmp1 = xcf_calc_levels (width, TILE_WIDTH);
+ tmp2 = xcf_calc_levels (height, TILE_HEIGHT);
+ nlevels = MAX (tmp1, tmp2);
+
+ xcf_check_error (xcf_seek_pos (info, info->cp + (1 + nlevels) * 4, error));
+
+ for (i = 0; i < nlevels; i++)
+ {
+ offset = info->cp;
+
+ if (i == 0)
+ {
+ /* write out the level. */
+ xcf_check_error (xcf_save_level (info, tiles, error));
+ }
+ else
+ {
+ /* fake an empty level */
+ tmp1 = 0;
+ width /= 2;
+ height /= 2;
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &width, 1);
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &height, 1);
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &tmp1, 1);
+ }
+
+ /* seek back to where we are to write out the next
+ * level offset and write it out.
+ */
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
+ xcf_write_int32_check_error (info, &offset, 1);
+
+ /* increment the location we are to write out the
+ * next offset.
+ */
+ saved_pos = info->cp;
+
+ /* seek to the end of the file which is where
+ * we will write out the next level.
+ */
+ xcf_check_error (xcf_seek_end (info, error));
+ }
+
+ /* write out a '0' offset position to indicate the end
+ * of the level offsets.
+ */
+ offset = 0;
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
+ xcf_write_int32_check_error (info, &offset, 1);
+
+ return TRUE;
+}
+
+static bool
+xcf_save_level (XcfInfo *info,
+ TileManager *level,
+ GError **error)
+{
+ TQ_INT32 saved_pos;
+ TQ_INT32 offset;
+ TQ_INT32 width;
+ TQ_INT32 height;
+ TQ_UINT32 ntiles;
+ TQ_INT32 i;
+ guchar *rlebuf;
+
+ GError *tmp_error = NULL;
+
+ width = tile_manager_width (level);
+ height = tile_manager_height (level);
+
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &width, 1);
+ xcf_write_int32_check_error (info, (TQ_INT32 *) &height, 1);
+
+ saved_pos = info->cp;
+
+ /* allocate a temporary buffer to store the rle data before it is
+ written to disk */
+ rlebuf =
+ g_malloc (TILE_WIDTH * TILE_HEIGHT * tile_manager_bpp (level) * 1.5);
+
+ if (level->tiles)
+ {
+ ntiles = level->ntile_rows * level->ntile_cols;
+ xcf_check_error (xcf_seek_pos (info, info->cp + (ntiles + 1) * 4, error));
+
+ for (i = 0; i < ntiles; i++)
+ {
+ /* save the start offset of where we are writing
+ * out the next tile.
+ */
+ offset = info->cp;
+
+ /* write out the tile. */
+ switch (info->compression)
+ {
+ case COMPRESS_NONE:
+ xcf_check_error(xcf_save_tile (info, level->tiles[i], error));
+ break;
+ case COMPRESS_RLE:
+ xcf_check_error (xcf_save_tile_rle (info, level->tiles[i],
+ rlebuf, error));
+ break;
+ case COMPRESS_ZLIB:
+ g_error ("xcf: zlib compression unimplemented");
+ break;
+ case COMPRESS_FRACTAL:
+ g_error ("xcf: fractal compression unimplemented");
+ break;
+ }
+
+ /* seek back to where we are to write out the next
+ * tile offset and write it out.
+ */
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
+ xcf_write_int32_check_error (info, &offset, 1);
+
+ /* increment the location we are to write out the
+ * next offset.
+ */
+ saved_pos = info->cp;
+
+ /* seek to the end of the file which is where
+ * we will write out the next tile.
+ */
+ xcf_check_error (xcf_seek_end (info, error));
+ }
+ }
+
+ g_free (rlebuf);
+
+ /* write out a '0' offset position to indicate the end
+ * of the level offsets.
+ */
+ offset = 0;
+ xcf_check_error (xcf_seek_pos (info, saved_pos, error));
+ xcf_write_int32_check_error (info, &offset, 1);
+
+ return TRUE;
+
+}
+
+static bool
+xcf_save_tile (XcfInfo *info,
+ Tile *tile,
+ GError **error)
+{
+ GError *tmp_error = NULL;
+
+ tile_lock (tile);
+ xcf_write_int8_check_error (info, tile_data_pointer (tile, 0, 0),
+ tile_size (tile));
+ tile_release (tile, FALSE);
+
+ return TRUE;
+}
+
+static bool
+xcf_save_tile_rle (XcfInfo *info,
+ Tile *tile,
+ guchar *rlebuf,
+ GError **error)
+{
+ guchar *data, *t;
+ unsigned int last;
+ TQ_INT32 state;
+ TQ_INT32 length;
+ TQ_INT32 count;
+ TQ_INT32 size;
+ TQ_INT32 bpp;
+ TQ_INT32 i, j;
+ TQ_INT32 len = 0;
+
+ GError *tmp_error = NULL;
+
+ tile_lock (tile);
+
+ bpp = tile_bpp (tile);
+
+ for (i = 0; i < bpp; i++)
+ {
+ data = (guchar*) tile_data_pointer (tile, 0, 0) + i;
+
+ state = 0;
+ length = 0;
+ count = 0;
+ size = tile_ewidth(tile) * tile_eheight(tile);
+ last = -1;
+
+ while (size > 0)
+ {
+ switch (state)
+ {
+ case 0:
+ /* in state 0 we try to find a long sequence of
+ * matching values.
+ */
+ if ((length == 32768) ||
+ ((size - length) <= 0) ||
+ ((length > 1) && (last != *data)))
+ {
+ count += length;
+ if (length >= 128)
+ {
+ rlebuf[len++] = 127;
+ rlebuf[len++] = (length >> 8);
+ rlebuf[len++] = length & 0x00FF;
+ rlebuf[len++] = last;
+ }
+ else
+ {
+ rlebuf[len++] = length - 1;
+ rlebuf[len++] = last;
+ }
+ size -= length;
+ length = 0;
+ }
+ else if ((length == 1) && (last != *data))
+ state = 1;
+ break;
+
+ case 1:
+ /* in state 1 we try and find a long sequence of
+ * non-matching values.
+ */
+ if ((length == 32768) ||
+ ((size - length) == 0) ||
+ ((length > 0) && (last == *data) &&
+ ((size - length) == 1 || last == data[bpp])))
+ {
+ count += length;
+ state = 0;
+
+ if (length >= 128)
+ {
+ rlebuf[len++] = 255 - 127;
+ rlebuf[len++] = (length >> 8);
+ rlebuf[len++] = length & 0x00FF;
+ }
+ else
+ {
+ rlebuf[len++] = 255 - (length - 1);
+ }
+
+ t = data - length * bpp;
+ for (j = 0; j < length; j++)
+ {
+ rlebuf[len++] = *t;
+ t += bpp;
+ }
+
+ size -= length;
+ length = 0;
+ }
+ break;
+ }
+
+ if (size > 0) {
+ length += 1;
+ last = *data;
+ data += bpp;
+ }
+ }
+
+ if (count != (tile_ewidth (tile) * tile_eheight (tile)))
+ g_message ("xcf: uh oh! xcf rle tile saving error: %d", count);
+ }
+ xcf_write_int8_check_error (info, rlebuf, len);
+ tile_release (tile, FALSE);
+
+ return TRUE;
+}
+
+static bool
+xcf_save_parasite (XcfInfo *info,
+ KisAnnotation *parasite,
+ GError **error)
+{
+ if (gimp_parasite_is_persistent (parasite))
+ {
+ GError *tmp_error = NULL;
+
+ xcf_write_string_check_error (info, &parasite->name, 1);
+ xcf_write_int32_check_error (info, &parasite->flags, 1);
+ xcf_write_int32_check_error (info, &parasite->size, 1);
+ xcf_write_int8_check_error (info, parasite->data, parasite->size);
+ }
+
+ return TRUE;
+}
+
+typedef struct
+{
+ XcfInfo *info;
+ GError *error;
+} XcfParasiteData;
+
+static void
+xcf_save_parasite_func (TQCString *key,
+ KisAnnotation *parasite,
+ XcfParasiteData *data)
+{
+ if (! data->error)
+ xcf_save_parasite (data->info, parasite, &data->error);
+}
+
+static bool
+xcf_save_parasite_list (XcfInfo *info,
+ KisAnnotationList *list,
+ GError **error)
+{
+ XcfParasiteData data;
+
+ data.info = info;
+ data.error = NULL;
+
+ gimp_parasite_list_foreach (list, (GHFunc) xcf_save_parasite_func, &data);
+
+ if (data.error)
+ {
+ g_propagate_error (error, data.error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool
+xcf_save_old_paths (XcfInfo *info,
+ KisImage *gimage,
+ GError **error)
+{
+ GimpVectors *active_vectors;
+ TQ_INT32 num_paths;
+ TQ_INT32 active_index = 0;
+ GList *list;
+ GError *tmp_error = NULL;
+
+ /* Write out the following:-
+ *
+ * last_selected_row (TQ_INT32)
+ * number_of_paths (TQ_INT32)
+ *
+ * then each path:-
+ */
+
+ num_paths = gimp_container_num_tqchildren (gimage->vectors);
+
+ active_vectors = gimp_image_get_active_vectors (gimage);
+
+ if (active_vectors)
+ active_index = gimp_container_get_child_index (gimage->vectors,
+ GIMP_OBJECT (active_vectors));
+
+ xcf_write_int32_check_error (info, &active_index, 1);
+ xcf_write_int32_check_error (info, &num_paths, 1);
+
+ for (list = GIMP_LIST (gimage->vectors)->list;
+ list;
+ list = g_list_next (list))
+ {
+ GimpVectors *vectors = list->data;
+ TQCString *name;
+ TQ_INT32 locked;
+ TQ_UINT8 state;
+ TQ_INT32 version;
+ TQ_INT32 pathtype;
+ TQ_INT32 tattoo;
+ GimpVectorsCompatPoint *points;
+ TQ_INT3232 num_points;
+ TQ_INT3232 closed;
+ TQ_INT32 i;
+
+ /*
+ * name (string)
+ * locked (TQ_INT32)
+ * state (TQCString)
+ * closed (TQ_INT32)
+ * number points (TQ_INT32)
+ * version (TQ_INT32)
+ * pathtype (TQ_INT32)
+ * tattoo (TQ_INT32)
+ * then each point.
+ */
+
+ points = gimp_vectors_compat_get_points (vectors, &num_points, &closed);
+
+ /* if no points are generated because of a faulty path we should
+ * skip saving the path - this is unfortunately impossible, because
+ * we already saved the number of paths and I wont start seeking
+ * around to fix that cruft */
+
+ name = (TQCString *) gimp_object_get_name (GIMP_OBJECT (vectors));
+ locked = gimp_item_get_linked (GIMP_ITEM (vectors));
+ state = closed ? 4 : 2; /* EDIT : ADD (editing state, 1.2 compat) */
+ version = 3;
+ pathtype = 1; /* BEZIER (1.2 compat) */
+ tattoo = gimp_item_get_tattoo (GIMP_ITEM (vectors));
+
+ xcf_write_string_check_error (info, &name, 1);
+ xcf_write_int32_check_error (info, &locked, 1);
+ xcf_write_int8_check_error (info, &state, 1);
+ xcf_write_int32_check_error (info, &closed, 1);
+ xcf_write_int32_check_error (info, &num_points, 1);
+ xcf_write_int32_check_error (info, &version, 1);
+ xcf_write_int32_check_error (info, &pathtype, 1);
+ xcf_write_int32_check_error (info, &tattoo, 1);
+
+ for (i = 0; i < num_points; i++)
+ {
+ float x;
+ float y;
+
+ x = points[i].x;
+ y = points[i].y;
+
+ /*
+ * type (TQ_INT32)
+ * x (float)
+ * y (float)
+ */
+
+ xcf_write_int32_check_error (info, &points[i].type, 1);
+ xcf_write_float_check_error (info, &x, 1);
+ xcf_write_float_check_error (info, &y, 1);
+ }
+
+ g_free (points);
+ }
+
+ return TRUE;
+}
+
+static bool
+xcf_save_vectors (XcfInfo *info,
+ KisImage *gimage,
+ GError **error)
+{
+ GimpVectors *active_vectors;
+ TQ_INT32 version = 1;
+ TQ_INT32 active_index = 0;
+ TQ_INT32 num_paths;
+ GList *list;
+ GList *stroke_list;
+ GError *tmp_error = NULL;
+
+ /* Write out the following:-
+ *
+ * version (TQ_INT32)
+ * active_index (TQ_INT32)
+ * num_paths (TQ_INT32)
+ *
+ * then each path:-
+ */
+
+ active_vectors = gimp_image_get_active_vectors (gimage);
+
+ if (active_vectors)
+ active_index = gimp_container_get_child_index (gimage->vectors,
+ GIMP_OBJECT (active_vectors));
+
+ num_paths = gimp_container_num_tqchildren (gimage->vectors);
+
+ xcf_write_int32_check_error (info, &version, 1);
+ xcf_write_int32_check_error (info, &active_index, 1);
+ xcf_write_int32_check_error (info, &num_paths, 1);
+
+ for (list = GIMP_LIST (gimage->vectors)->list;
+ list;
+ list = g_list_next (list))
+ {
+ GimpVectors *vectors = list->data;
+ KisAnnotationList *parasites;
+ TQCString *name;
+ TQ_INT32 tattoo;
+ TQ_INT32 visible;
+ TQ_INT32 linked;
+ TQ_INT32 num_parasites;
+ TQ_INT32 num_strokes;
+
+ /*
+ * name (string)
+ * tattoo (TQ_INT32)
+ * visible (TQ_INT32)
+ * linked (TQ_INT32)
+ * num_parasites (TQ_INT32)
+ * num_strokes (TQ_INT32)
+ *
+ * then each parasite
+ * then each stroke
+ */
+
+ parasites = GIMP_ITEM (vectors)->parasites;
+
+ name = (TQCString *) gimp_object_get_name (GIMP_OBJECT (vectors));
+ visible = gimp_item_get_visible (GIMP_ITEM (vectors));
+ linked = gimp_item_get_linked (GIMP_ITEM (vectors));
+ tattoo = gimp_item_get_tattoo (GIMP_ITEM (vectors));
+ num_parasites = gimp_parasite_list_persistent_length (parasites);
+ num_strokes = g_list_length (vectors->strokes);
+
+ xcf_write_string_check_error (info, &name, 1);
+ xcf_write_int32_check_error (info, &tattoo, 1);
+ xcf_write_int32_check_error (info, &visible, 1);
+ xcf_write_int32_check_error (info, &linked, 1);
+ xcf_write_int32_check_error (info, &num_parasites, 1);
+ xcf_write_int32_check_error (info, &num_strokes, 1);
+
+ xcf_check_error (xcf_save_parasite_list (info, parasites, error));
+
+ for (stroke_list = g_list_first (vectors->strokes);
+ stroke_list;
+ stroke_list = g_list_next (stroke_list))
+ {
+ GimpStroke *stroke;
+ TQ_INT32 stroke_type;
+ TQ_INT32 closed;
+ TQ_INT32 num_axes;
+ GArray *control_points;
+ TQ_INT32 i;
+
+ TQ_INT32 type;
+ float coords[6];
+
+ /*
+ * stroke_type (TQ_INT32)
+ * closed (TQ_INT32)
+ * num_axes (TQ_INT32)
+ * num_control_points (TQ_INT32)
+ *
+ * then each control point.
+ */
+
+ stroke = GIMP_STROKE (stroke_list->data);
+
+ if (GIMP_IS_BEZIER_STROKE (stroke))
+ {
+ stroke_type = XCF_STROKETYPE_BEZIER_STROKE;
+ num_axes = 2; /* hardcoded, might be increased later */
+ }
+ else
+ {
+ g_printerr ("Skipping unknown stroke type!\n");
+ continue;
+ }
+
+ control_points = gimp_stroke_control_points_get (stroke, &closed);
+
+ xcf_write_int32_check_error (info, &stroke_type, 1);
+ xcf_write_int32_check_error (info, &closed, 1);
+ xcf_write_int32_check_error (info, &num_axes, 1);
+ xcf_write_int32_check_error (info, &control_points->len, 1);
+
+ for (i = 0; i < control_points->len; i++)
+ {
+ GimpAnchor *anchor;
+
+ anchor = & (g_array_index (control_points, GimpAnchor, i));
+
+ type = anchor->type;
+ coords[0] = anchor->position.x;
+ coords[1] = anchor->position.y;
+ coords[2] = anchor->position.pressure;
+ coords[3] = anchor->position.xtilt;
+ coords[4] = anchor->position.ytilt;
+ coords[5] = anchor->position.wheel;
+
+ /*
+ * type (TQ_INT32)
+ *
+ * the first num_axis elements of:
+ * [0] x (float)
+ * [1] y (float)
+ * [2] pressure (float)
+ * [3] xtilt (float)
+ * [4] ytilt (float)
+ * [5] wheel (float)
+ */
+
+ xcf_write_int32_check_error (info, &type, 1);
+ xcf_write_float_check_error (info, coords, num_axes);
+ }
+
+ g_array_free (control_points, TRUE);
+ }
+ }
+
+ return TRUE;
+}
diff --git a/filters/chalk/xcf/xcf/xcf-save.h b/filters/chalk/xcf/xcf/xcf-save.h
new file mode 100644
index 00000000..cc49d2d3
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-save.h
@@ -0,0 +1,29 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __XCF_SAVE_H__
+#define __XCF_SAVE_H__
+
+
+void xcf_save_choose_format (XcfInfo *info,
+ KisImage *gimage);
+TQ_INT32 xcf_save_image (XcfInfo *info,
+ KisImage *gimage);
+
+
+#endif /* __XCF_SAVE_H__ */
diff --git a/filters/chalk/xcf/xcf/xcf-seek.cc b/filters/chalk/xcf/xcf/xcf-seek.cc
new file mode 100644
index 00000000..a24271f5
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-seek.cc
@@ -0,0 +1,79 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+#include <glib-object.h>
+
+#include "core/core-types.h"
+
+#include "xcf-private.h"
+#include "xcf-seek.h"
+
+#include "gimp-intl.h"
+
+bool
+xcf_seek_pos (XcfInfo *info,
+ TQ_UINT32 pos,
+ GError **error)
+{
+ if (info->cp != pos)
+ {
+ info->cp = pos;
+ if (fseek (info->fp, info->cp, SEEK_SET) == -1)
+ {
+ g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
+ _("Could not seek in XCF file: %s"),
+ g_strerror (errno));
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+bool
+xcf_seek_end (XcfInfo *info,
+ GError **error)
+{
+ if (fseek (info->fp, 0, SEEK_END) == -1)
+ {
+ g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
+ _("Could not seek in XCF file: %s"),
+ g_strerror (errno));
+
+ return FALSE;
+ }
+
+ info->cp = ftell (info->fp);
+
+ if (fseek (info->fp, 0, SEEK_END) == -1)
+ {
+ g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
+ _("Could not seek in XCF file: %s"),
+ g_strerror (errno));
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/filters/chalk/xcf/xcf/xcf-seek.h b/filters/chalk/xcf/xcf/xcf-seek.h
new file mode 100644
index 00000000..1bb7b7a9
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-seek.h
@@ -0,0 +1,30 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __XCF_SEEK_H__
+#define __XCF_SEEK_H__
+
+
+bool xcf_seek_pos (XcfInfo *info,
+ TQ_UINT32 pos,
+ GError **error);
+bool xcf_seek_end (XcfInfo *info,
+ GError **error);
+
+
+#endif /* __XCF_SEEK_H__ */
diff --git a/filters/chalk/xcf/xcf/xcf-write.cc b/filters/chalk/xcf/xcf/xcf-write.cc
new file mode 100644
index 00000000..4010ab18
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-write.cc
@@ -0,0 +1,104 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h> /* strlen */
+#include <errno.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include <netinet/in.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <cfloat>
+
+#include "xcf-write.h"
+
+TQ_UINT32 xcf_write_int32 (FILE *fp, TQ_INT32 *data, TQ_INT32 count);
+{
+ TQ_INT32 tmp;
+ TQ_INT32 i;
+
+ if (count > 0)
+ {
+ for (i = 0; i < count; i++)
+ {
+ tmp = htonl (data[i]);
+ xcf_write_int8 (fp, (TQ_UINT8*) &tmp, 4);
+
+ if (fp->status() != IO_Ok)
+ {
+ return i * 4;
+ }
+ }
+ }
+
+ return count * 4;
+}
+
+TQ_UINT32 xcf_write_float (FILE *fp, float *data, TQ_INT32 count);
+{
+ return xcf_write_int32 (fp, (TQ_INT32 *)((void *)data), count, error);
+}
+
+TQ_UINT32 xcf_write_int8 (FILE *fp, TQ_UINT8 *data, TQ_INT32 count);
+{
+ TQ_INT32 bytes;
+ bytes = fp->writeBlock( data, count );
+ return bytes;
+}
+
+TQ_UINT32 xcf_write_string (FILE *fp, TQCString *data, TQ_INT32 count);
+{
+ GError *tmp_error = NULL;
+ TQ_INT32 tmp;
+ TQ_UINT32 total;
+ TQ_INT32 i;
+
+ total = 0;
+ for (i = 0; i < count; i++)
+ {
+ if (data[i])
+ tmp = strlen (data[i]) + 1;
+ else
+ tmp = 0;
+
+ xcf_write_int32 (fp, &tmp, 1, &tmp_error);
+ if (tmp_error)
+ {
+ g_propagate_error (error, tmp_error);
+ return total;
+ }
+
+ if (tmp > 0)
+ xcf_write_int8 (fp, (TQ_UINT8*) data[i], tmp, &tmp_error);
+ if (tmp_error)
+ {
+ g_propagate_error (error, tmp_error);
+ return total;
+ }
+
+ total += 4 + tmp;
+ }
+
+ return total;
+}
diff --git a/filters/chalk/xcf/xcf/xcf-write.h b/filters/chalk/xcf/xcf/xcf-write.h
new file mode 100644
index 00000000..8e21a08e
--- /dev/null
+++ b/filters/chalk/xcf/xcf/xcf-write.h
@@ -0,0 +1,39 @@
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __XCF_WRITE_H__
+#define __XCF_WRITE_H__
+
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqfile.h>
+
+// Write count integers to the file
+TQ_UINT32 xcf_write_int32 (TQFile *fp, TQ_INT32 *data, TQ_INT32 count);
+
+// Write count of floats to the file
+TQ_UINT32 xcf_write_float (TQFile *fp, float *data, TQ_INT32 count);
+
+// Write count chars to the file
+TQ_UINT32 xcf_write_int8 (TQFile *fp, TQ_UINT8 *data, TQ_INT32 count);
+
+// Write count zero-terminated strings to the file, each string preceded by its length as an integer
+TQ_UINT32 xcf_write_string (TQFile *fp, TQCString *data, TQ_INT32 count);
+
+
+#endif /* __XCF_WRITE_H__ */
diff --git a/filters/chalk/xcf/xcfexport.cpp b/filters/chalk/xcf/xcfexport.cpp
new file mode 100644
index 00000000..b26fdba8
--- /dev/null
+++ b/filters/chalk/xcf/xcfexport.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <xcfexport.h>
+
+#include <kurl.h>
+#include <kgenericfactory.h>
+
+#include <KoDocument.h>
+#include <KoFilterChain.h>
+
+#include <kis_doc.h>
+#include <kis_image.h>
+#include <kis_annotation.h>
+#include <kis_types.h>
+#include <kis_xcf_converter.h>
+
+typedef KGenericFactory<XCFExport, KoFilter> XCFExportFactory;
+K_EXPORT_COMPONENT_FACTORY(libchalkxcfexport, XCFExportFactory("kofficefilters"))
+
+XCFExport::XCFExport(KoFilter *, const char *, const TQStringList&) : KoFilter()
+{
+}
+
+XCFExport::~XCFExport()
+{
+}
+
+KoFilter::ConversiontqStatus XCFExport::convert(const TQCString& from, const TQCString& to)
+{
+ kdDebug(41008) << "xcf export! From: " << from << ", To: " << to << "\n";
+
+ if (from != "application/x-chalk")
+ return KoFilter::NotImplemented;
+
+ KisDoc *output = dynamic_cast<KisDoc*>(m_chain->inputDocument());
+ TQString filename = m_chain->outputFile();
+
+ if (!output)
+ return KoFilter::CreationError;
+
+
+ if (filename.isEmpty()) return KoFilter::FileNotFound;
+
+ KURL url(filename);
+
+ KisImageSP img = output->currentImage();
+ if (!img) return KoFilter::ParsingError;
+
+ KisXCFConverter ib(output, output->undoAdapter());
+
+ vKisAnnotationSP_it beginIt = img->beginAnnotations();
+ vKisAnnotationSP_it endIt = img->endAnnotations();
+
+ if (ib.buildFile(url, img, beginIt, endIt) == KisImageBuilder_RESULT_OK) {
+ return KoFilter::OK;
+ }
+
+ return KoFilter::InternalError;
+}
+
+#include <xcfexport.moc>
+
diff --git a/filters/chalk/xcf/xcfexport.h b/filters/chalk/xcf/xcfexport.h
new file mode 100644
index 00000000..b6acf737
--- /dev/null
+++ b/filters/chalk/xcf/xcfexport.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef XCFEXPORT_H_
+#define XCFEXPORT_H_
+
+#include <KoFilter.h>
+
+class XCFExport : public KoFilter {
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ XCFExport(KoFilter *tqparent, const char *name, const TQStringList&);
+ virtual ~XCFExport();
+
+public:
+ virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to);
+};
+
+#endif // XCFEXPORT_H_
+
diff --git a/filters/chalk/xcf/xcfimport.cpp b/filters/chalk/xcf/xcfimport.cpp
new file mode 100644
index 00000000..6f07ebcf
--- /dev/null
+++ b/filters/chalk/xcf/xcfimport.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <tqstring.h>
+
+#include <xcfimport.h>
+#include <kgenericfactory.h>
+#include <KoDocument.h>
+#include <KoFilterChain.h>
+
+#include <kis_doc.h>
+#include <kis_view.h>
+#include <kis_xcf_converter.h>
+#include <kis_progress_display_interface.h>
+
+typedef KGenericFactory<XCFImport, KoFilter> XCFImportFactory;
+K_EXPORT_COMPONENT_FACTORY(libchalkxcfimport, XCFImportFactory("kofficefilters"))
+
+XCFImport::XCFImport(KoFilter *, const char *, const TQStringList&) : KoFilter()
+{
+}
+
+XCFImport::~XCFImport()
+{
+}
+
+KoFilter::ConversiontqStatus XCFImport::convert(const TQCString&, const TQCString& to)
+{
+ kdDebug(41008) << "Importing using XCFImport!\n";
+
+ if (to != "application/x-chalk")
+ return KoFilter::BadMimeType;
+
+ KisDoc * doc = dynamic_cast<KisDoc*>(m_chain -> outputDocument());
+ KisView * view = static_cast<KisView*>(doc -> views().getFirst());
+
+ TQString filename = m_chain -> inputFile();
+
+ if (!doc)
+ return KoFilter::CreationError;
+
+ doc -> prepareForImport();
+
+
+ if (!filename.isEmpty()) {
+
+ KURL url(filename);
+
+ if (url.isEmpty())
+ return KoFilter::FileNotFound;
+
+ KisXCFConverter ib(doc, doc -> undoAdapter());
+
+ switch (ib.buildImage(url)) {
+ case KisImageBuilder_RESULT_UNSUPPORTED:
+ return KoFilter::NotImplemented;
+ break;
+ case KisImageBuilder_RESULT_INVALID_ARG:
+ return KoFilter::BadMimeType;
+ break;
+ case KisImageBuilder_RESULT_NO_URI:
+ case KisImageBuilder_RESULT_NOT_LOCAL:
+ return KoFilter::FileNotFound;
+ break;
+ case KisImageBuilder_RESULT_BAD_FETCH:
+ case KisImageBuilder_RESULT_EMPTY:
+ return KoFilter::ParsingError;
+ break;
+ case KisImageBuilder_RESULT_FAILURE:
+ return KoFilter::InternalError;
+ break;
+ case KisImageBuilder_RESULT_OK:
+ doc -> setCurrentImage( ib.image());
+ return KoFilter::OK;
+ default:
+ break;
+ }
+
+ }
+ return KoFilter::StorageCreationError;
+}
+
+#include <xcfimport.moc>
+
diff --git a/filters/chalk/xcf/xcfimport.h b/filters/chalk/xcf/xcfimport.h
new file mode 100644
index 00000000..038e7604
--- /dev/null
+++ b/filters/chalk/xcf/xcfimport.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef XCFIMPORT_H_
+#define XCFIMPORT_H_
+
+#include <KoFilter.h>
+
+class XCFImport : public KoFilter {
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+ XCFImport(KoFilter *tqparent, const char *name, const TQStringList&);
+ virtual ~XCFImport();
+
+public:
+ virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to);
+};
+
+#endif // XCFIMPORT_H_
+
diff --git a/filters/configure.in.mid b/filters/configure.in.mid
index a996cfb7..ba359970 100644
--- a/filters/configure.in.mid
+++ b/filters/configure.in.mid
@@ -21,7 +21,7 @@ for args in $SUBDIRLIST ; do
kpresenter) COMPILE_FILTER_KPRESENTER="$args " ;;
kformula) COMPILE_FILTER_KFORMULA="$args " ;;
kugar) COMPILE_FILTER_KUGAR="$args " ;;
- krita) COMPILE_FILTER_KRITA="$args " ;;
+ chalk) COMPILE_FILTER_KRITA="$args " ;;
kivio) COMPILE_FILTER_KIVIO="$args " ;;
kexi) COMPILE_FILTER_KEXI="$args " ;;
esac
@@ -37,7 +37,7 @@ for args in $DO_NOT_COMPILE ; do
kpresenter) COMPILE_FILTER_KPRESENTER= ;;
kformula) COMPILE_FILTER_KFORMULA= ;;
kugar) COMPILE_FILTER_KUGAR= ;;
- krita) COMPILE_FILTER_KRITA= ;;
+ chalk) COMPILE_FILTER_KRITA= ;;
kivio) COMPILE_FILTER_KIVIO= ;;
kexi) COMPILE_FILTER_KEXI= ;;
esac
diff --git a/filters/filterstatus.xml b/filters/filterstatus.xml
index 6dc47680..6af39854 100644
--- a/filters/filterstatus.xml
+++ b/filters/filterstatus.xml
@@ -347,12 +347,12 @@
</filter>
</application>
- <application id="krita">
- <title xml:lang="en_US">Krita</title> <foreword
- xml:lang="en_US"> Krita can use &lt;a
+ <application id="chalk">
+ <title xml:lang="en_US">Chalk</title> <foreword
+ xml:lang="en_US"> Chalk can use &lt;a
href="http://imagemagick.org/"&gt;ImageMagick&lt;/a&gt;
for importing and exporting images. This means that, in
- addition to the file formats listed below, Krita can work
+ addition to the file formats listed below, Chalk can work
with all images that your installation of ImageMagick
supports. This includes all common image file formats,
including the native formats of Photoshop and the Gimp.
@@ -361,29 +361,29 @@
information on file formats supported by
ImageMagick.&lt;/a&gt;
</foreword>
- <filter id="krita_png">
- <websvn importsuffix="#import" exportsuffix="#export" path="koffice/filters/krita/png"/>
+ <filter id="chalk_png">
+ <websvn importsuffix="#import" exportsuffix="#export" path="koffice/filters/chalk/png"/>
<title xml:lang="en_us">PNG</title>
<note xml:lang="en_us">Portable Network Graphics</note>
<stat import="fourstars" export="fourstars"/>
</filter>
- <filter id="krita_jpeg">
- <websvn importsuffix="#import" exportsuffix="#export" path="koffice/filters/krita/jpeg"/>
+ <filter id="chalk_jpeg">
+ <websvn importsuffix="#import" exportsuffix="#export" path="koffice/filters/chalk/jpeg"/>
<title xml:lang="en_us">JPEG</title>
<stat import="fourstars" export="fourstars"/>
</filter>
- <filter id="krita_tiff">
- <websvn importsuffix="#import" exportsuffix="#export" path="koffice/filters/krita/tiff"/>
+ <filter id="chalk_tiff">
+ <websvn importsuffix="#import" exportsuffix="#export" path="koffice/filters/chalk/tiff"/>
<title xml:lang="en_us">TIFF</title>
<stat import="fivestars" export="fivestarts"/>
</filter>
- <filter id="krita_raw">
- <websvn importsuffix="#import" exportsuffix="#export" path="koffice/filters/krita/raw"/>
+ <filter id="chalk_raw">
+ <websvn importsuffix="#import" exportsuffix="#export" path="koffice/filters/chalk/raw"/>
<title xml:lang="en_us">RAW</title>
<stat import="onestar" export="none"/>
</filter>
- <filter id="krita_openexr">
- <websvn importsuffix="#import" exportsuffix="#export" path="koffice/filters/krita/openexr"/>
+ <filter id="chalk_openexr">
+ <websvn importsuffix="#import" exportsuffix="#export" path="koffice/filters/chalk/openexr"/>
<title xml:lang="en_us">OpenEXR</title>
<note xml:lang="en_us">
&lt;a href="http://www.openexr.com/"&gt;OpenEXR&lt;/a&gt; is a high dynamic-range (HDR) format &lt;br /&gt;
@@ -391,14 +391,14 @@
</note>
<stat import="fourstars" export="fourstars"/>
</filter>
- <filter id="krita_pdf">
- <websvn importsuffix="#import" exportsuffix="#export" path="koffice/filters/krita/pdf"/>
+ <filter id="chalk_pdf">
+ <websvn importsuffix="#import" exportsuffix="#export" path="koffice/filters/chalk/pdf"/>
<title xml:lang="en_us">PDF</title>
<note xml:lang="en_us">Portable Document Format</note>
<stat import="threestars" export="threestars"/>
</filter>
- <filter id="krita_xcf">
- <websvn importsuffix="#import" exportsuffix="#export" path="koffice/filters/krita/xcf"/>
+ <filter id="chalk_xcf">
+ <websvn importsuffix="#import" exportsuffix="#export" path="koffice/filters/chalk/xcf"/>
<title xml:lang="en_us">Gimp (XCF)</title>
<note xml:lang="en_us">Native file format of the
&lt;a href="http://www.gimp.org/"&gt;Gimp&lt;/a&gt;</note>
diff --git a/filters/kspread/gnumeric/gnumericimport.cc b/filters/kspread/gnumeric/gnumericimport.cc
index 4374d14a..ad97a548 100644
--- a/filters/kspread/gnumeric/gnumericimport.cc
+++ b/filters/kspread/gnumeric/gnumericimport.cc
@@ -961,19 +961,19 @@ void GNUMERICFilter::ParseFormat(TQString const & formatString, Cell * kspread_c
kspread_cell->format()->setCurrency( 1, "$" );
lastPos = 1;
}
- else if (formatString[0] == '�')
+ else if ((int)(formatString[0]) == '�')
{
kspread_cell->format()->setFormatType(Money_format);
kspread_cell->format()->setCurrency( 1, "�" );
lastPos = 1;
}
- else if (formatString[0] == '�')
+ else if ((int)(formatString[0]) == '�')
{
kspread_cell->format()->setFormatType(Money_format);
kspread_cell->format()->setCurrency( 1, "�" );
lastPos = 1;
}
- else if (formatString[0] == '�')
+ else if ((int)(formatString[0]) == '�')
{
kspread_cell->format()->setFormatType(Money_format);
kspread_cell->format()->setCurrency( 1, "�" );
diff --git a/filters/tests/global-filter-test.sh b/filters/tests/global-filter-test.sh
index b4885023..ee622bb0 100755
--- a/filters/tests/global-filter-test.sh
+++ b/filters/tests/global-filter-test.sh
@@ -73,8 +73,8 @@ case "$1" in
exit 1;
esac
;;
- krita)
- appname=krita
+ chalk)
+ appname=chalk
oldextension=kra
case "$3" in
magick-png)
@@ -94,7 +94,7 @@ case "$1" in
newmimetype=image/tiff
;;
*)
- printf "Usage: %s {kspread|kword|kpresenter|krita} <file name> {magick-png}\n" "$0"
+ printf "Usage: %s {kspread|kword|kpresenter|chalk} <file name> {magick-png}\n" "$0"
exit1;
esac
;;
@@ -112,7 +112,7 @@ case "$1" in
esac
;;
*)
- printf "Usage: %s {kspread|kword|kpresenter|krita} <file name> <type of filter>\n" "$0"
+ printf "Usage: %s {kspread|kword|kpresenter|chalk} <file name> <type of filter>\n" "$0"
exit 1;
esac